From 9f945b60901a91bf3899175b3948fd1296a36e1b Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Sat, 3 Oct 2026 22:36:42 +0900 Subject: [PATCH 01/73] ci(windows,linux): check published install, Wayland grim and global skills install (#465) - published-install.yml installs the latest release on windows-latest with `irm .../install.ps1 | iex` and compares `unity-cli --version` with the release tag (after Release, weekly, manual, and PRs touching the check) - platform-checks.py checks grim when WAYLAND_DISPLAY is set; the Linux job runs it under sway's headless backend - skills install resolves the home directory from %USERPROFILE% on Windows, like the clients do, so the global install test now runs on Windows too Refs #465 Co-Authored-By: Claude Fable 5.1 --- .github/workflows/README.md | 9 ++++- .github/workflows/published-install.yml | 35 +++++++++++++++++++ .github/workflows/test.yml | 31 ++++++++++++++-- ...32f63d5accca68a326f7320cf23df81bd2ef.jsonl | 1 + ...99da5d81b6374305c665de44bb0ff8d6e9f7.jsonl | 1 + ...8c484a58e8ccab3377ffce522eb5939df416.jsonl | 1 + docs/development.md | 6 ++-- docs/skills.md | 3 +- src/skills/distribution.rs | 4 ++- tests/scripts/install-ps1-published-test.ps1 | 34 ++++++++++++++++++ tests/scripts/platform-checks.py | 12 ++++--- tests/skills_install.rs | 6 ---- 12 files changed, 125 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/published-install.yml create mode 100644 .gwt/work/events/6c/6c33430f6e49c43af88d6fc2513a32f63d5accca68a326f7320cf23df81bd2ef.jsonl create mode 100644 .gwt/work/events/99/99ea4094ca2c7435e791ea7e4c7c99da5d81b6374305c665de44bb0ff8d6e9f7.jsonl create mode 100644 .gwt/work/events/bb/bb6f404b351d7e2650cffbe763118c484a58e8ccab3377ffce522eb5939df416.jsonl create mode 100644 tests/scripts/install-ps1-published-test.ps1 diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 0d1ca35c..0f93b6a3 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -15,7 +15,8 @@ `setup --dry-run`, OS screenshot fallback) and is installed through `scripts/install.ps1` - Linux: the same `platform-checks.py` under Xvfb with the X11 screenshot - tools; none of these checks need a Unity Editor + tools, then its screenshot check again with `grim` under a headless `sway` + (Wayland); none of these checks need a Unity Editor - `dotnet test lsp/Server.Tests.csproj` - `cargo llvm-cov` (Rust coverage gate, line >= 90%) - `dotnet test ... /p:CollectCoverage=true` (LSP coverage gate, line >= 90%) @@ -23,6 +24,12 @@ - runs after `chore(release):` pushes to `main` or manual dispatch - creates the release tag, builds release binaries for Linux/macOS/Windows - publishes GitHub Release assets +- `published-install.yml` + - installs the latest published release on `windows-latest` with + `irm .../main/scripts/install.ps1 | iex` and checks `unity-cli --version` + - runs after the `Release` workflow, weekly, on manual dispatch, and for PRs + that change the check itself (not on every PR: it depends on the network + and on the published release) - `main-pr-policy.yml` - branch policy for PRs into `main` - `auto-merge.yml` diff --git a/.github/workflows/published-install.yml b/.github/workflows/published-install.yml new file mode 100644 index 00000000..51022358 --- /dev/null +++ b/.github/workflows/published-install.yml @@ -0,0 +1,35 @@ +name: Published Install + +# Installs the latest published release on a clean runner (#465). It depends on +# the network and on the state of the published release, so it stays off the +# per-PR path: it runs after a release, weekly, on demand, and for PRs that +# change this check itself. +on: + workflow_run: + workflows: [Release] + types: [completed] + schedule: + - cron: '17 3 * * 1' + workflow_dispatch: + pull_request: + paths: + - .github/workflows/published-install.yml + - tests/scripts/install-ps1-published-test.ps1 + +permissions: + contents: read + +jobs: + windows-published-install: + name: Windows Published Install + runs-on: windows-latest + timeout-minutes: 15 + if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' + steps: + - uses: actions/checkout@v7 + + - name: Install the latest release with install.ps1 and check its version + shell: pwsh + env: + GH_TOKEN: ${{ github.token }} + run: ./tests/scripts/install-ps1-published-test.ps1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5193ebc2..ffc74a69 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -155,10 +155,10 @@ jobs: key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} restore-keys: ${{ runner.os }}-cargo- - - name: Install Xvfb and X11 screenshot tools + - name: Install Xvfb, X11 screenshot tools, sway and grim run: | sudo apt-get update - sudo apt-get install -y xvfb imagemagick scrot maim + sudo apt-get install -y xvfb imagemagick scrot maim sway grim - name: Build unity-cli run: cargo build --bin unity-cli @@ -168,6 +168,33 @@ jobs: xvfb-run -a -s "-screen 0 1280x720x24" python3 tests/scripts/platform-checks.py --unity-cli target/debug/unity-cli + - name: Check the grim OS screenshot fallback under headless sway + # A wlroots compositor on the headless backend with the software + # renderer; WAYLAND_DISPLAY switches the check to grim (#465). + env: + WLR_BACKENDS: headless + WLR_LIBINPUT_NO_DEVICES: '1' + WLR_RENDERER: pixman + run: | + XDG_RUNTIME_DIR="$(mktemp -d)" + export XDG_RUNTIME_DIR + chmod 700 "$XDG_RUNTIME_DIR" + sway -c /dev/null > "$RUNNER_TEMP/sway.log" 2>&1 & + socket="" + for _ in $(seq 1 50); do + socket="$(find "$XDG_RUNTIME_DIR" -maxdepth 1 -type s -name 'wayland-*' | head -n 1)" + [ -n "$socket" ] && break + sleep 0.2 + done + if [ -z "$socket" ]; then + cat "$RUNNER_TEMP/sway.log" + echo "sway did not create a Wayland socket" >&2 + exit 1 + fi + WAYLAND_DISPLAY="$(basename "$socket")" + export WAYLAND_DISPLAY + python3 tests/scripts/platform-checks.py --unity-cli target/debug/unity-cli --checks screenshot + lsp-test: name: LSP Tests (required) runs-on: ubuntu-latest diff --git a/.gwt/work/events/6c/6c33430f6e49c43af88d6fc2513a32f63d5accca68a326f7320cf23df81bd2ef.jsonl b/.gwt/work/events/6c/6c33430f6e49c43af88d6fc2513a32f63d5accca68a326f7320cf23df81bd2ef.jsonl new file mode 100644 index 00000000..da90be1d --- /dev/null +++ b/.gwt/work/events/6c/6c33430f6e49c43af88d6fc2513a32f63d5accca68a326f7320cf23df81bd2ef.jsonl @@ -0,0 +1 @@ +{"id":"0131453b-482f-45f2-bbdf-d9d4d16a9319","work_item_id":"work-work-issue-465-f794e601","kind":"start","title":"ci(windows,linux): 公開版の導入・Wayland スクリーンショット・skills 導入を CI で確認する(#386 から切り出し 第2弾)","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #465","next_action":"Check Board for latest updates","agent_session_id":"1730113d-3d73-4722-b1ca-61b9d6af50c5","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-465","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-465","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T13:29:32.497019Z"} diff --git a/.gwt/work/events/99/99ea4094ca2c7435e791ea7e4c7c99da5d81b6374305c665de44bb0ff8d6e9f7.jsonl b/.gwt/work/events/99/99ea4094ca2c7435e791ea7e4c7c99da5d81b6374305c665de44bb0ff8d6e9f7.jsonl new file mode 100644 index 00000000..f31acc12 --- /dev/null +++ b/.gwt/work/events/99/99ea4094ca2c7435e791ea7e4c7c99da5d81b6374305c665de44bb0ff8d6e9f7.jsonl @@ -0,0 +1 @@ +{"id":"8c0c79a3-56ab-4684-ade8-fc3237db148c","work_item_id":"work-work-issue-465-f794e601","kind":"update","title":"Issue #465 の残り受け入れ基準の実装","intent":"Issue #465 の受け入れ基準を評価中","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #465","next_action":null,"agent_session_id":"1730113d-3d73-4722-b1ca-61b9d6af50c5","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-465","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-465","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T13:29:40.684629Z"} diff --git a/.gwt/work/events/bb/bb6f404b351d7e2650cffbe763118c484a58e8ccab3377ffce522eb5939df416.jsonl b/.gwt/work/events/bb/bb6f404b351d7e2650cffbe763118c484a58e8ccab3377ffce522eb5939df416.jsonl new file mode 100644 index 00000000..5e540752 --- /dev/null +++ b/.gwt/work/events/bb/bb6f404b351d7e2650cffbe763118c484a58e8ccab3377ffce522eb5939df416.jsonl @@ -0,0 +1 @@ +{"id":"0ba0d709-6430-4c49-ac46-9d2293246329","work_item_id":"work-work-issue-465-f794e601","kind":"update","title":"公開版導入・Wayland スクリーンショット・skills 導入の CI 確認 (#465)","intent":"AC-1〜3 の CI テストを実装中","summary":null,"progress_summary":"AC 監査完了: AC-1〜4 すべて未達。sway headless + grim が Ubuntu 24.04 で PNG を生成することを Docker で確認済み。","status_category":null,"owner":"Issue #465","next_action":null,"agent_session_id":"1730113d-3d73-4722-b1ca-61b9d6af50c5","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-465","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-465","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T13:32:04.778621Z"} diff --git a/docs/development.md b/docs/development.md index 91b6c25e..c2301146 100644 --- a/docs/development.md +++ b/docs/development.md @@ -585,7 +585,7 @@ echo "$UNITY_CLI_HOST:$UNITY_CLI_PORT" ## CI Overview -CI is defined in `.github/workflows/lint.yml`, `.github/workflows/test.yml`, and `.github/workflows/skill-routing-eval.yml`. +CI is defined in `.github/workflows/lint.yml`, `.github/workflows/test.yml`, `.github/workflows/published-install.yml`, and `.github/workflows/skill-routing-eval.yml`. | Job | Trigger | Description | | ------------------------------ | ----------------------- | ------------------------------------------------------------------------------------- | @@ -595,6 +595,7 @@ CI is defined in `.github/workflows/lint.yml`, `.github/workflows/test.yml`, and | LSP Performance (required) | push / PR | `scripts/lsp-perf-check.sh` (full cases + history artifact) | | CLI Latency (required) | push / PR | `scripts/bench-cli-latency.py` (p50/p95 budgets + injected-delay evidence) | | Skill Routing Eval | daily schedule / manual | `scripts/skill-eval/llm-routing-eval.sh` (`.github/workflows/skill-routing-eval.yml`) | +| Windows Published Install | release / cron / manual | latest release via `install.ps1` (`.github/workflows/published-install.yml`) | Skill Contract Check, Rust Tests, LSP Tests, LSP Performance, and CLI Latency are required checks for PR merges. @@ -1240,7 +1241,7 @@ echo "$UNITY_CLI_HOST:$UNITY_CLI_PORT" ## CI の概要 -CI は `.github/workflows/lint.yml` / `.github/workflows/test.yml` / `.github/workflows/skill-routing-eval.yml` で定義されています。 +CI は `.github/workflows/lint.yml` / `.github/workflows/test.yml` / `.github/workflows/published-install.yml` / `.github/workflows/skill-routing-eval.yml` で定義されています。 | ジョブ | トリガー | 内容 | | ------------------------------ | ----------------------- | -------------------------------------------------------------------------------------- | @@ -1250,6 +1251,7 @@ CI は `.github/workflows/lint.yml` / `.github/workflows/test.yml` / `.github/wo | LSP Performance (required) | push / PR | `scripts/lsp-perf-check.sh`(全ケース実行 + 履歴artifact) | | CLI Latency (required) | push / PR | `scripts/bench-cli-latency.py`(p50/p95 予算 + 遅延注入の証跡) | | Skill Routing Eval | 毎日スケジュール / 手動 | `scripts/skill-eval/llm-routing-eval.sh`(`.github/workflows/skill-routing-eval.yml`) | +| Windows Published Install | Release 後/週次/手動 | 最新の公開版を `install.ps1` で導入(`.github/workflows/published-install.yml`) | Skill Contract Check / Rust Tests / LSP Tests / LSP Performance / CLI Latency は PR マージの必須チェックです。 diff --git a/docs/skills.md b/docs/skills.md index ee555b91..b5fb2ced 100644 --- a/docs/skills.md +++ b/docs/skills.md @@ -63,7 +63,8 @@ unity-cli skills show unity-scene-create | `vscode` | `.github/skills/` | `~/.copilot/skills/` | These clients read `SKILL.md` directories directly; reference files retain their -relative paths. See the client documentation for +relative paths. The home directory is `$HOME` on Unix and `%USERPROFILE%` on +Windows, the same location the clients read. See the client documentation for [Claude Code](https://code.claude.com/docs/en/skills), [Cursor](https://cursor.com/docs/skills), [Windsurf](https://docs.windsurf.com/windsurf/cascade/skills), and diff --git a/src/skills/distribution.rs b/src/skills/distribution.rs index d89448d4..8965f51e 100644 --- a/src/skills/distribution.rs +++ b/src/skills/distribution.rs @@ -66,7 +66,9 @@ fn scope_root(local: bool) -> Result { let root = if local { std::env::current_dir()? } else { - dirs::home_dir().context("cannot determine the user home directory")? + // Not `dirs::home_dir`: Windows clients resolve their home from + // %USERPROFILE%, which the shell API behind `dirs` ignores. + std::env::home_dir().context("cannot determine the user home directory")? }; ensure!( !fs::symlink_metadata(&root)?.file_type().is_symlink(), diff --git a/tests/scripts/install-ps1-published-test.ps1 b/tests/scripts/install-ps1-published-test.ps1 new file mode 100644 index 00000000..294c9133 --- /dev/null +++ b/tests/scripts/install-ps1-published-test.ps1 @@ -0,0 +1,34 @@ +# Installs the latest published release the way the README tells users to +# (`irm .../main/scripts/install.ps1 | iex`) and checks that the installed +# unity-cli reports that release's version (#465). Needs network access and a +# published release, so it runs from published-install.yml, not on every PR. +$ErrorActionPreference = 'Stop' + +function Assert([bool]$Condition, [string]$Message) { + if (-not $Condition) { throw "FAIL: $Message" } +} + +$repo = 'akiojin/unity-cli' +$installerUrl = "https://raw.githubusercontent.com/$repo/main/scripts/install.ps1" + +$headers = @{ 'User-Agent' = 'unity-cli-published-install-test' } +if ($env:GH_TOKEN) { $headers['Authorization'] = "Bearer $env:GH_TOKEN" } +$tag = (Invoke-RestMethod -Uri "https://api.github.com/repos/$repo/releases/latest" -Headers $headers).tag_name +Assert ($tag -match '^v\d+\.\d+\.\d+$') "unexpected latest release tag: $tag" +$expected = "unity-cli $($tag.TrimStart('v'))" + +# The installer must pick the release and the install location by itself. +foreach ($name in 'UNITY_CLI_VERSION', 'UNITY_CLI_RELEASE_BASE_URL', 'UNITY_CLI_TOOLS_ROOT', 'UNITY_CLI_SKIP_PATH_UPDATE') { + Remove-Item "Env:$name" -ErrorAction SilentlyContinue +} +Invoke-RestMethod -Uri $installerUrl | Invoke-Expression + +$installed = Join-Path $HOME '.unity\tools\unity-cli\win-x64\unity-cli.exe' +Assert (Test-Path $installed) "binary must be installed at $installed" +$resolved = (Get-Command unity-cli -CommandType Application | Select-Object -First 1).Source +Assert ($resolved -eq $installed) "unity-cli must resolve to the installed binary, got: $resolved" +$actual = (unity-cli --version | Out-String).Trim() +Assert ($LASTEXITCODE -eq 0) "unity-cli --version exited with $LASTEXITCODE" +Assert ($actual -eq $expected) "installed binary reported '$actual', expected '$expected' (release $tag)" + +Write-Host "published install test passed ($actual from release $tag)" diff --git a/tests/scripts/platform-checks.py b/tests/scripts/platform-checks.py index 86ce1f49..48ddb214 100644 --- a/tests/scripts/platform-checks.py +++ b/tests/scripts/platform-checks.py @@ -9,7 +9,8 @@ setup `setup --dry-run` prints the Bridge install plan and writes nothing (#363) screenshot a silent fake Editor makes `capture_screenshot` time out and fall - back to an OS screenshot that must be a real PNG (#369) + back to an OS screenshot that must be a real PNG (#369). Linux + checks the X11 tools, or grim when WAYLAND_DISPLAY is set (#465) Unix isolates the home directory through $HOME. Windows resolves the profile through the shell API instead of %USERPROFILE%, so the lockfiles go into the @@ -38,10 +39,11 @@ CHECKS = ("discovery", "setup", "screenshot") IS_WINDOWS = os.name == "nt" PNG_SIGNATURE = b"\x89PNG\r\n\x1a\n" -# X11 tools the CLI tries on Linux, in order (src/tooling/os_capture.rs). -# The Wayland tools (grim, gnome-screenshot, spectacle) need a compositor that -# CI runners do not have, so they stay with the real-machine checks in #386. +# Tools the CLI tries on Linux, in order (src/tooling/os_capture.rs). grim runs +# under a headless wlroots compositor (#465); gnome-screenshot and spectacle +# need a full desktop session, so they stay with the real-machine checks in #386. X11_TOOLS = ("import", "scrot", "maim") +WAYLAND_TOOLS = ("grim",) results: list[tuple[str, bool, str]] = [] @@ -251,7 +253,7 @@ def check_screenshot(runner: Runner) -> None: tools = {"powershell": None} elif sys.platform.startswith("linux"): tools = {} - for tool in X11_TOOLS: + for tool in WAYLAND_TOOLS if os.environ.get("WAYLAND_DISPLAY") else X11_TOOLS: resolved = shutil.which(tool) if resolved is None: check(f"screenshot: {tool} is installed", False, "not on PATH") diff --git a/tests/skills_install.rs b/tests/skills_install.rs index 2cfbcd17..c9a5b231 100644 --- a/tests/skills_install.rs +++ b/tests/skills_install.rs @@ -185,12 +185,6 @@ fn all_clients_install_embedded_references_and_show_works_outside_repository() { .join(local) .join("unity-scene-create/references/runtime-checklist.md") .is_file()); - // Windows resolves the home directory through the shell API, not - // %USERPROFILE%, so a global install cannot be redirected into the - // temp root and would write into the real user profile. - if cfg!(windows) { - continue; - } ok(run(root.path(), &["skills", "install", client])); assert!(root .path() From b0df8c015cefb2d12e3e7ce8cb2c796fde642014 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Sat, 3 Oct 2026 22:41:27 +0900 Subject: [PATCH 02/73] test(windows): run the published installer in a child scope (#465) The installer is dot-evaluated by iex and its $expected (the SHA-256) overwrote the version string the test compares against. Refs #465 Co-Authored-By: Claude Fable 5.1 --- ...2ba4724d2b29edd2ab9b17bdffd5b2d93fa95c29558048b097dc5.jsonl | 1 + ...1548328d1cc9a21c64f1e6994f668eb13febf2fcdf23a7988c680.jsonl | 1 + ...e21655b07f3169ff6850ef750f28999646897424cf16d30382ebd.jsonl | 1 + tests/scripts/install-ps1-published-test.ps1 | 3 ++- 4 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .gwt/work/events/8d/8d6df80bc742ba4724d2b29edd2ab9b17bdffd5b2d93fa95c29558048b097dc5.jsonl create mode 100644 .gwt/work/events/a5/a5365cc444d1548328d1cc9a21c64f1e6994f668eb13febf2fcdf23a7988c680.jsonl create mode 100644 .gwt/work/events/e3/e37e976620ce21655b07f3169ff6850ef750f28999646897424cf16d30382ebd.jsonl diff --git a/.gwt/work/events/8d/8d6df80bc742ba4724d2b29edd2ab9b17bdffd5b2d93fa95c29558048b097dc5.jsonl b/.gwt/work/events/8d/8d6df80bc742ba4724d2b29edd2ab9b17bdffd5b2d93fa95c29558048b097dc5.jsonl new file mode 100644 index 00000000..284a7efa --- /dev/null +++ b/.gwt/work/events/8d/8d6df80bc742ba4724d2b29edd2ab9b17bdffd5b2d93fa95c29558048b097dc5.jsonl @@ -0,0 +1 @@ +{"id":"635a50b1-e5ad-485d-b1b2-6b33cd402bf3","work_item_id":"work-work-issue-465-f794e601","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"active","owner":null,"next_action":null,"agent_session_id":"1730113d-3d73-4722-b1ca-61b9d6af50c5","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-465","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-465","pr_number":466,"pr_url":"https://github.com/akiojin/unity-cli/pull/466","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-03T13:37:19.211991Z"} diff --git a/.gwt/work/events/a5/a5365cc444d1548328d1cc9a21c64f1e6994f668eb13febf2fcdf23a7988c680.jsonl b/.gwt/work/events/a5/a5365cc444d1548328d1cc9a21c64f1e6994f668eb13febf2fcdf23a7988c680.jsonl new file mode 100644 index 00000000..dac66923 --- /dev/null +++ b/.gwt/work/events/a5/a5365cc444d1548328d1cc9a21c64f1e6994f668eb13febf2fcdf23a7988c680.jsonl @@ -0,0 +1 @@ +{"id":"e6ee7dd2-74dc-4789-8eb7-3a18d932e5af","work_item_id":"work-work-issue-465-f794e601","kind":"resume","title":"ci(windows,linux): 公開版の導入・Wayland スクリーンショット・skills 導入を CI で確認する(#386 から切り出し 第2弾)","intent":"Claude Code started work on Issue #465 ci(windows,linux): 公開版の導入・Wayland スクリーンショット・skills 導入を CI で確認する(#386 から切り出し 第2弾) (work/issue-465)","summary":"2 active agents","progress_summary":null,"status_category":"active","owner":"Issue #465","next_action":"Check Board for latest updates","agent_session_id":"fe9e4e72-804e-4519-99c5-032aefc86976","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-465","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-465","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T13:40:02.862336Z"} diff --git a/.gwt/work/events/e3/e37e976620ce21655b07f3169ff6850ef750f28999646897424cf16d30382ebd.jsonl b/.gwt/work/events/e3/e37e976620ce21655b07f3169ff6850ef750f28999646897424cf16d30382ebd.jsonl new file mode 100644 index 00000000..cb7546bc --- /dev/null +++ b/.gwt/work/events/e3/e37e976620ce21655b07f3169ff6850ef750f28999646897424cf16d30382ebd.jsonl @@ -0,0 +1 @@ +{"id":"85520592-bb0f-41a9-8c02-827e03e42fd8","work_item_id":"work-work-issue-465-f794e601","kind":"update","title":null,"intent":"Draft PR #466 の CI(Windows / Wayland ジョブ)を待機中","summary":null,"progress_summary":"AC-1〜3 を実装して push、Draft PR #466 を作成。ローカル品質ゲートと Linux コンテナでの sway+grim / Xvfb チェックは PASS。Windows の 2 項目は CI で確認中。残り: CI 確認、#386 本文更新 (AC-4)、Ready 化。","status_category":null,"owner":"Issue #465","next_action":null,"agent_session_id":"1730113d-3d73-4722-b1ca-61b9d6af50c5","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-465","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-465","pr_number":466,"pr_url":"https://github.com/akiojin/unity-cli/pull/466","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-03T13:37:25.651163Z"} diff --git a/tests/scripts/install-ps1-published-test.ps1 b/tests/scripts/install-ps1-published-test.ps1 index 294c9133..0f049a2f 100644 --- a/tests/scripts/install-ps1-published-test.ps1 +++ b/tests/scripts/install-ps1-published-test.ps1 @@ -21,7 +21,8 @@ $expected = "unity-cli $($tag.TrimStart('v'))" foreach ($name in 'UNITY_CLI_VERSION', 'UNITY_CLI_RELEASE_BASE_URL', 'UNITY_CLI_TOOLS_ROOT', 'UNITY_CLI_SKIP_PATH_UPDATE') { Remove-Item "Env:$name" -ErrorAction SilentlyContinue } -Invoke-RestMethod -Uri $installerUrl | Invoke-Expression +# A child scope keeps the installer's own variables out of this script. +& { Invoke-RestMethod -Uri $installerUrl | Invoke-Expression } $installed = Join-Path $HOME '.unity\tools\unity-cli\win-x64\unity-cli.exe' Assert (Test-Path $installed) "binary must be installed at $installed" From ab6db5d2ad2ca7653b2f8fe20a10b99e62900253 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Sat, 3 Oct 2026 22:52:12 +0900 Subject: [PATCH 03/73] chore(gwt): record work events for #465 Refs #465 Co-Authored-By: Claude Fable 5.1 --- ...72910cc3dffb7ab234a9def2d8f9677ffa53af5bded950f93764212.jsonl | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gwt/work/events/9c/9c58f642272910cc3dffb7ab234a9def2d8f9677ffa53af5bded950f93764212.jsonl diff --git a/.gwt/work/events/9c/9c58f642272910cc3dffb7ab234a9def2d8f9677ffa53af5bded950f93764212.jsonl b/.gwt/work/events/9c/9c58f642272910cc3dffb7ab234a9def2d8f9677ffa53af5bded950f93764212.jsonl new file mode 100644 index 00000000..c2f471c9 --- /dev/null +++ b/.gwt/work/events/9c/9c58f642272910cc3dffb7ab234a9def2d8f9677ffa53af5bded950f93764212.jsonl @@ -0,0 +1 @@ +{"id":"dd2b5d86-e8f2-4ca3-bbbc-a3249c578b3c","work_item_id":"work-work-issue-465-f794e601","kind":"update","title":null,"intent":"PM へ引き継ぎ済み(PR作成可)。PM の pr.ready 待ち","summary":null,"progress_summary":"AC-1〜4 を実装し Draft PR #466 の CI が全ジョブ PASS(head b0df8c0)。#386 本文と #465 のチェックを更新済み。gwtd verify.run は host lease の競合で未実行、PM 裁定により CI を最終確認として引き継いだ。","status_category":null,"owner":"Issue #465","next_action":null,"agent_session_id":"1730113d-3d73-4722-b1ca-61b9d6af50c5","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-465","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-465","pr_number":466,"pr_url":"https://github.com/akiojin/unity-cli/pull/466","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-03T13:51:56.593992Z"} From 0458d7fa83d55a3e77cb833ba74c705b65927a30 Mon Sep 17 00:00:00 2001 From: akiojin Date: Sun, 4 Oct 2026 01:01:19 +0900 Subject: [PATCH 04/73] fix(windows): harden Editor launches and profile isolation --- ...ded79e5b1eb03f253c4312352f1a17399f75.jsonl | 1 + ...20e3abb9181188424a8c3f1d85f60bcaa091.jsonl | 1 + ...48954a2ae0b91d17d07fbcd44c5d16a7d0ea.jsonl | 1 + ...888ac98fe9eaa65c9bc8e4f556a384422c8b.jsonl | 1 + ...ecc84efa3be1775ba65f4cdb890a4613a29d.jsonl | 1 + .../Editor/Handlers/SceneHandler.cs | 4 +- .../Editor/Handlers/SceneHandlerTests.cs | 29 + docs/comparison.md | 13 + docs/verification/issue-386/README.md | 154 + .../issue-386/cargo-all-final.txt | 721 ++++ .../issue-386/cargo-test-inventory.json | 3039 +++++++++++++++++ docs/verification/issue-386/clippy.txt | 2 + .../issue-386/environment-final.json | 19 + docs/verification/issue-386/environment.json | 23 + docs/verification/issue-386/final-checks.json | 58 + .../issue-386/first-operations.json | 140 + docs/verification/issue-386/fmt.txt | 0 .../issue-386/fresh-setup-summary.json | 70 + docs/verification/issue-386/green-results.xml | 13 + .../issue-386/install-release.txt | 9 + .../issue-386/linux-tool-paths.txt | 1 + docs/verification/issue-386/lockfiles.json | 44 + docs/verification/issue-386/mcp-green.txt | 30 + docs/verification/issue-386/mcp-red.txt | 22 + .../modal-fallback-disabled.stdout.json | 16 + .../issue-386/modal-os-fallback.stdout.json | 17 + .../verification/issue-386/modal-summary.json | 49 + docs/verification/issue-386/operations.json | 140 + .../verification/issue-386/profile-audit.json | 19 + docs/verification/issue-386/red-results.xml | 40 + .../issue-386/release-version.json | 10 + docs/verification/issue-386/release.json | 16 + .../issue-386/repository-secret-names.json | 13 + docs/verification/issue-386/setup.stdout.json | 57 + .../issue-386/skills-lint-final.txt | 51 + .../issue-386/staff-final-operations.json | 140 + .../issue-386/staff-final-summary.json | 610 ++++ .../issue-386/staff-play-settings.stdout.json | 25 + .../issue-386/tasklist-14140.json | 14 + .../issue-386/tasklist-44232.json | 14 + .../issue-386/tasklist-52408.json | 14 + docs/verification/issue-386/unity-final.txt | 2 + .../issue-386/verify-run-second.json | 1 + docs/verification/issue-386/verify-run.json | 1 + docs/verification/issue-386/winget.json | 17 + src/app/editor.rs | 47 +- src/app/setup.rs | 5 +- src/app/test_runner.rs | 3 +- src/daemon/unityd.rs | 3 +- src/lsp/client.rs | 11 +- src/lsp/daemon.rs | 5 +- src/mcp/configure.rs | 11 +- src/skills/tests.rs | 4 +- tests/mcp.rs | 14 + tests/setup_dry_run.rs | 85 + 55 files changed, 5832 insertions(+), 18 deletions(-) create mode 100644 .gwt/work/events/37/376d6e3699f9e37edb97bbfa5526ded79e5b1eb03f253c4312352f1a17399f75.jsonl create mode 100644 .gwt/work/events/64/6483d1feaeffee6ef5d6bc013b5c20e3abb9181188424a8c3f1d85f60bcaa091.jsonl create mode 100644 .gwt/work/events/9a/9a605b22f1057785d3f3efb2a49448954a2ae0b91d17d07fbcd44c5d16a7d0ea.jsonl create mode 100644 .gwt/work/events/9c/9c434a5da95639afd344c6072831888ac98fe9eaa65c9bc8e4f556a384422c8b.jsonl create mode 100644 .gwt/work/events/ce/ce5e6b98fd2a773f841a502ee45eecc84efa3be1775ba65f4cdb890a4613a29d.jsonl create mode 100644 docs/verification/issue-386/README.md create mode 100644 docs/verification/issue-386/cargo-all-final.txt create mode 100644 docs/verification/issue-386/cargo-test-inventory.json create mode 100644 docs/verification/issue-386/clippy.txt create mode 100644 docs/verification/issue-386/environment-final.json create mode 100644 docs/verification/issue-386/environment.json create mode 100644 docs/verification/issue-386/final-checks.json create mode 100644 docs/verification/issue-386/first-operations.json create mode 100644 docs/verification/issue-386/fmt.txt create mode 100644 docs/verification/issue-386/fresh-setup-summary.json create mode 100644 docs/verification/issue-386/green-results.xml create mode 100644 docs/verification/issue-386/install-release.txt create mode 100644 docs/verification/issue-386/linux-tool-paths.txt create mode 100644 docs/verification/issue-386/lockfiles.json create mode 100644 docs/verification/issue-386/mcp-green.txt create mode 100644 docs/verification/issue-386/mcp-red.txt create mode 100644 docs/verification/issue-386/modal-fallback-disabled.stdout.json create mode 100644 docs/verification/issue-386/modal-os-fallback.stdout.json create mode 100644 docs/verification/issue-386/modal-summary.json create mode 100644 docs/verification/issue-386/operations.json create mode 100644 docs/verification/issue-386/profile-audit.json create mode 100644 docs/verification/issue-386/red-results.xml create mode 100644 docs/verification/issue-386/release-version.json create mode 100644 docs/verification/issue-386/release.json create mode 100644 docs/verification/issue-386/repository-secret-names.json create mode 100644 docs/verification/issue-386/setup.stdout.json create mode 100644 docs/verification/issue-386/skills-lint-final.txt create mode 100644 docs/verification/issue-386/staff-final-operations.json create mode 100644 docs/verification/issue-386/staff-final-summary.json create mode 100644 docs/verification/issue-386/staff-play-settings.stdout.json create mode 100644 docs/verification/issue-386/tasklist-14140.json create mode 100644 docs/verification/issue-386/tasklist-44232.json create mode 100644 docs/verification/issue-386/tasklist-52408.json create mode 100644 docs/verification/issue-386/unity-final.txt create mode 100644 docs/verification/issue-386/verify-run-second.json create mode 100644 docs/verification/issue-386/verify-run.json create mode 100644 docs/verification/issue-386/winget.json diff --git a/.gwt/work/events/37/376d6e3699f9e37edb97bbfa5526ded79e5b1eb03f253c4312352f1a17399f75.jsonl b/.gwt/work/events/37/376d6e3699f9e37edb97bbfa5526ded79e5b1eb03f253c4312352f1a17399f75.jsonl new file mode 100644 index 00000000..60514f9f --- /dev/null +++ b/.gwt/work/events/37/376d6e3699f9e37edb97bbfa5526ded79e5b1eb03f253c4312352f1a17399f75.jsonl @@ -0,0 +1 @@ +{"id":"c2e0a584-da07-4988-b8cc-b57849f4899a","work_item_id":"work-work-issue-386-8f91ee0d","kind":"resume","title":"test(windows): #362 / #363 / #369 の Windows・Linux 実機検証","intent":"Check Board for latest updates","summary":"Codex is running","progress_summary":null,"status_category":"active","owner":"Issue #386","next_action":"Check Board for latest updates","agent_session_id":"58337a13-2327-417b-b9f2-9b4b847857c4","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-386","worktree_path":"E:/unity-cli/work/issue-386","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T04:08:49.375693400Z"} diff --git a/.gwt/work/events/64/6483d1feaeffee6ef5d6bc013b5c20e3abb9181188424a8c3f1d85f60bcaa091.jsonl b/.gwt/work/events/64/6483d1feaeffee6ef5d6bc013b5c20e3abb9181188424a8c3f1d85f60bcaa091.jsonl new file mode 100644 index 00000000..4872aaec --- /dev/null +++ b/.gwt/work/events/64/6483d1feaeffee6ef5d6bc013b5c20e3abb9181188424a8c3f1d85f60bcaa091.jsonl @@ -0,0 +1 @@ +{"id":"163b0f15-be73-4ad7-b729-cd5770422463","work_item_id":"work-work-issue-386-8f91ee0d","kind":"update","title":"Issue #386 の修正","intent":"Issue と実行状態の確認","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #386","next_action":null,"agent_session_id":"58337a13-2327-417b-b9f2-9b4b847857c4","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-386","worktree_path":"E:/unity-cli/work/issue-386","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T04:26:24.498553Z"} diff --git a/.gwt/work/events/9a/9a605b22f1057785d3f3efb2a49448954a2ae0b91d17d07fbcd44c5d16a7d0ea.jsonl b/.gwt/work/events/9a/9a605b22f1057785d3f3efb2a49448954a2ae0b91d17d07fbcd44c5d16a7d0ea.jsonl new file mode 100644 index 00000000..afe3c77f --- /dev/null +++ b/.gwt/work/events/9a/9a605b22f1057785d3f3efb2a49448954a2ae0b91d17d07fbcd44c5d16a7d0ea.jsonl @@ -0,0 +1 @@ +{"id":"16520be6-a198-41a3-9086-8a82434141cf","work_item_id":"work-work-issue-386-8f91ee0d","kind":"update","title":"Windows・Linux 実機検証 #386","intent":"Windows の Editor 起動ハンドル継承とシーン保存先作成の回帰テスト","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #386","next_action":null,"agent_session_id":"58337a13-2327-417b-b9f2-9b4b847857c4","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-386","worktree_path":"E:/unity-cli/work/issue-386","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T04:39:30.680687400Z"} diff --git a/.gwt/work/events/9c/9c434a5da95639afd344c6072831888ac98fe9eaa65c9bc8e4f556a384422c8b.jsonl b/.gwt/work/events/9c/9c434a5da95639afd344c6072831888ac98fe9eaa65c9bc8e4f556a384422c8b.jsonl new file mode 100644 index 00000000..3ea7ff23 --- /dev/null +++ b/.gwt/work/events/9c/9c434a5da95639afd344c6072831888ac98fe9eaa65c9bc8e4f556a384422c8b.jsonl @@ -0,0 +1 @@ +{"id":"a806a0f9-e9a1-4274-a21d-15d21db5b50d","work_item_id":"work-work-issue-386-8f91ee0d","kind":"blocked","title":"Windows・Linux 実機検証 #386","intent":"Windows 修正・証跡整理済み。skill リンク作成権限、Linux 実 Editor、原資料、winget 公開設定、正式検証枠の不足を解消して再開","summary":"Windows 23操作は比較条件で成功。最終 Cargo は605成功・リンク制約で1失敗、fmt/clippy/Unity11件成功。Issueコメントに証跡記録。PR未作成。","progress_summary":null,"status_category":"blocked","owner":"Issue #386","next_action":"不足する検証環境と配布設定を確認し、正規リンクの checkout で正式 verify.run を再実行する","agent_session_id":"58337a13-2327-417b-b9f2-9b4b847857c4","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-386","worktree_path":"E:/unity-cli/work/issue-386","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T15:57:16.222752200Z"} diff --git a/.gwt/work/events/ce/ce5e6b98fd2a773f841a502ee45eecc84efa3be1775ba65f4cdb890a4613a29d.jsonl b/.gwt/work/events/ce/ce5e6b98fd2a773f841a502ee45eecc84efa3be1775ba65f4cdb890a4613a29d.jsonl new file mode 100644 index 00000000..c0162444 --- /dev/null +++ b/.gwt/work/events/ce/ce5e6b98fd2a773f841a502ee45eecc84efa3be1775ba65f4cdb890a4613a29d.jsonl @@ -0,0 +1 @@ +{"id":"b9d6016e-de5c-46f1-ad45-ab4f27081814","work_item_id":"work-work-issue-386-8f91ee0d","kind":"update","title":"Windows・Linux 実機検証 #386","intent":"Windows 23 操作が比較資料の設定で成功。共通検証枠を待ちながら証跡・未達条件を整理","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #386","next_action":null,"agent_session_id":"58337a13-2327-417b-b9f2-9b4b847857c4","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-386","worktree_path":"E:/unity-cli/work/issue-386","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-03T15:04:19.275941Z"} diff --git a/UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/SceneHandler.cs b/UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/SceneHandler.cs index 4fe30d9f..593b46bd 100644 --- a/UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/SceneHandler.cs +++ b/UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/SceneHandler.cs @@ -62,7 +62,7 @@ public static object CreateScene(JObject parameters) } // Ensure directory exists - var directory = Path.GetDirectoryName(scenePath); + var directory = Path.GetDirectoryName(scenePath).Replace('\\', '/'); if (!AssetDatabase.IsValidFolder(directory)) { // Create directory structure @@ -310,7 +310,7 @@ public static object SaveScene(JObject parameters) } // Ensure directory exists - var directory = Path.GetDirectoryName(savePath); + var directory = Path.GetDirectoryName(savePath).Replace('\\', '/'); if (!AssetDatabase.IsValidFolder(directory)) { // Create directory structure diff --git a/UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/SceneHandlerTests.cs b/UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/SceneHandlerTests.cs index 69f45a3b..731bdb28 100644 --- a/UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/SceneHandlerTests.cs +++ b/UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/SceneHandlerTests.cs @@ -93,6 +93,35 @@ public void CreateScene_ShouldWorkWithCustomPath() Assert.IsTrue(File.Exists(path)); } + [Test] + public void CreateScene_ShouldCreateNestedFolders() + { + var folder = testSceneFolder + "/Nested/Generated"; + var result = ToJObject(SceneHandler.CreateScene(new JObject + { + ["sceneName"] = "TestScene_Nested", + ["path"] = folder, + ["loadScene"] = false + })); + + Assert.IsNull(result.Value("error"), result.ToString()); + Assert.IsTrue(AssetDatabase.IsValidFolder(folder)); + Assert.IsTrue(File.Exists(folder + "/TestScene_Nested.unity")); + } + + [Test] + public void SaveScene_ShouldCreateNestedFolders() + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + var path = testSceneFolder + "/Saved/Generated/TestScene_Saved.unity"; + var result = ToJObject(SceneHandler.SaveScene(new JObject { ["scenePath"] = path })); + + Assert.IsNull(result.Value("error"), result.ToString()); + Assert.IsTrue(AssetDatabase.IsValidFolder(testSceneFolder + "/Saved/Generated")); + Assert.IsTrue(File.Exists(path)); + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + [Test] public void CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse() { diff --git a/docs/comparison.md b/docs/comparison.md index fb0dd64e..d88fa589 100644 --- a/docs/comparison.md +++ b/docs/comparison.md @@ -43,6 +43,13 @@ Each table row links to its evidence: | Editor / project lifecycle | Bridge setup and installed Editor open/close/headless lifecycle; use Unity Hub or the official CLI for Editor installation and licenses. [Setup](../src/app/setup.rs), [lifecycle implementation](../src/app/editor.rs). | Editor/module install, licensing, project creation/opening, builds, tests and version control. [Official skill][official-skill]. | | Agent integration | Claude Code plugin and Codex skills. [Skill contract](skills.md). | Claude Code / Codex plugin, task skills and `unity mcp`. [Official skill][official-skill], [integration guide][official-integration]. | +Windows validation was added separately in [Issue #386 evidence](verification/issue-386/README.md): +CLI / Bridge 0.18.1 with Unity 6000.4.4f1 verified real setup, lockfile discovery, +OS screenshot fallback during an Editor modal, and all 23 listed operations with +DisableDomainReload / PlayUnfocused. The official CLI was not rerun on Windows; +the timings below remain macOS measurements. Normal Domain Reload still produced +connection errors, and Linux, winget and the original staff report remain unverified. + ### Coexistence Both packages were loaded into **one real Unity 6000.3.25f1 Editor project** on @@ -165,6 +172,12 @@ Editor 側の **Pipeline**(`com.unity.pipeline`)を提供しています。 | Editor・プロジェクト管理 | Bridge 導入、導入済み Editor の起動・終了・headless運用。Editor インストールやライセンスは Hub / 公式 CLI を利用。[setup](../src/app/setup.rs)、[ライフサイクル](../src/app/editor.rs)。 | Editor / モジュール導入、ライセンス、プロジェクト作成・起動、ビルド、テスト、VCS。[公式資料][official-skill]。 | | エージェント連携 | Claude Code プラグイン / Codex スキル。[契約](skills.md)。 | Claude Code / Codex プラグイン、タスクスキル、`unity mcp`。[公式スキル][official-skill]、[連携ガイド][official-integration]。 | +Windows の実機確認は [Issue #386 の証跡](verification/issue-386/README.md) を追加しました。 +CLI / Bridge 0.18.1、Unity 6000.4.4f1 で実 setup、lockfile 発見、Editor モーダル中の OS +画面取得、および DisableDomainReload / PlayUnfocused 条件で公開23操作を確認しています。 +公式 CLI の Windows 再測定は行っておらず、下の速度比較は macOS の計測です。 +通常の Domain Reload では接続エラーが出ており、Linux、winget、スタッフ原資料との網羅性確認は未検証です。 + ### 同一プロジェクトでの併用 Apple Silicon macOS の **同じ Unity 6000.3.25f1 プロジェクト**に両パッケージを diff --git a/docs/verification/issue-386/README.md b/docs/verification/issue-386/README.md new file mode 100644 index 00000000..64fb274e --- /dev/null +++ b/docs/verification/issue-386/README.md @@ -0,0 +1,154 @@ +# Issue #386: Windows 実機検証と残る検証条件 + +対象: [Issue #386](https://github.com/akiojin/unity-cli/issues/386)。計測日時は各 JSON の UTC 時刻を参照。 +Windows 11 x64 / Unity 6000.4.4f1 / CLI・Bridge 0.18.1 を使用した。 +CLI は base `338f426119b61123567b74028e7e8fe3bd99caa5` に本変更を加えた開発ビルドで、 +公開 Release 0.18.1 のバイナリも別に導入して接続を確認した。 +[環境・ソースファイル・バイナリの SHA256](environment.json) で区別できる。 +MCP profile 修正後の [最終ソース・バイナリ SHA256](environment-final.json) は別に収録した。 +先に測定した Windows 操作にはその測定時点のバイナリ SHA256 を残している。 + +**Overall: FAIL — Issue 全体は未完了。PR は未作成。** +Windows の成功を Linux、通常の Domain Reload、winget 導入や原資料の全シナリオへ拡張しない。 + +## 受け入れ基準の実測状況 + +| AC | 結果 | 証跡・残る条件 | +| --- | --- | --- | +| 1: Windows lockfile / PID / 自動発見 | PASS | 実 Editor が `%USERPROFILE%\.unity-cli\editors` に発行した [lockfile(認証情報除去)](lockfiles.json)、`tasklist`、[自動発見](fresh-setup-summary.json)。 | +| 2: 実 setup / Bridge 導入・接続 | PASS | 空の隔離プロジェクトで `setup --launch-editor --wait-secs 420` を実行。40.549秒、exit 0、`projectMatches: true`。[結果](setup.stdout.json)、[実行時間と ping](fresh-setup-summary.json)。dry-run ではない。 | +| 3: 証跡の Issue / PR 記録 | PASS | 本資料と [Issue コメント](https://github.com/akiojin/unity-cli/issues/386#issuecomment-5970471700) に成功・失敗・未検証条件を記録。全件ゲート未通過のため PR 未作成。 | +| 4: Windows / Linux OS フォールバック | Windows PASS / Linux 未検証 | 実 Editor の `EditorUtility.DisplayDialog` でメインスレッドを止め、PowerShell + GDI の OS キャプチャが成功。Linux の実 Editor と Wayland/X11 キャプチャツールは本環境で揃わない。 | +| 5: スタッフ原資料の全シナリオ・比較表 | 部分 | 公開済み23操作は既存比較と同じ設定で23/23 PASS。[一覧](staff-final-operations.json)。原資料 `pm-scratch/staff-report.md` は未取得。公式 CLI の Windows 比較・原資料との網羅性確認は未実施。 | +| 6: 公開 install.ps1 / winget / ping | PowerShell PASS / winget 未検証 | 公開 installer で Release 0.18.1 を隔離 tools root へ導入し、実 Editor に ping 成功。winget source に `akiojin.unity-cli` がなく、repository に `WINGET_TOKEN` もない。 | + +## 実機で発見して修正した問題 + +1. Windows では `Command::spawn` が CLI の標準出力ハンドルを Editor に継承させ、 + 呼び出し元の `Command::output` が Editor 終了まで待つ。 + setup、editor open、test の起動を既存 `spawn_detached` に統一した。 + `setup_launch_returns_output_while_editor_is_still_running` は修正前に + `setup output waited for the Editor to exit` で失敗し、修正後に成功した。 + 実 Editor の新規 setup も40.549秒で戻り、Editor は起動したまま接続できた。 +2. Windows の `canonicalize` が返す `\\?\` / `\\?\UNC\` を Unity の起動引数に渡すと、 + この Editor では正しく起動できなかった。Unity に渡す project / log パスを通常形式へ変換した。 + `editor_launch_uses_paths_supported_by_unity` は local / UNC の両方で修正前に失敗し、修正後に成功した。 + CLI の自動 headless 起動による実 Unity テストと GUI 起動の両方でも確認した。 +3. Windows の `Path.GetDirectoryName` は `\` を返す。 + シーンの作成・保存は `/` で分割して AssetDatabase のフォルダを作るため失敗していた。 + AssetDatabase に渡す前に区切り文字を `/` に揃えた。 + 深いフォルダへの作成・保存の回帰テストを追加し、実 Unity で RED → GREEN を確認した。 + +Windows の clippy で検出された既存の Unix 専用テストの未使用 import / helper には +`cfg(unix)` を付けた。LSP の動作変更はない。 + +4. 全件検証で MCP configure の Windows profile 解決も確認した。 + `dirs::home_dir` の Windows shell API はプロセスの `USERPROFILE` 上書きを参照しないため、 + Windsurf の設定テストが実ユーザープロファイルへ書き込んでいた。 + Windows では明示した `USERPROFILE` を優先し、未設定なら従来の解決方法に戻すよう修正した。 + テストは dry-run の出力先と、指定先で更新された `command` を確認するよう強化した。 + `windsurf: preview must target the isolated configuration directory` の RED を確認し、 + 修正後は MCP / auth warning / tool list の11件が成功した。 + 今回生成された実プロファイルの設定ファイルは、内容・SHA256・作成時刻で検証実行の生成物と + 確認して削除した。[削除前のメタデータと削除結果](profile-audit.json)。 + +## Windows OS キャプチャ + +実 Editor PID 44232 に同期 `EditorUtility.DisplayDialog("Issue386FallbackProbe", ...)` を開き、 +その PID 所有のモーダルウィンドウが存在することを確認してから実行した。 + +```text +unity-cli --project-path --timeout-ms 1000 raw capture_screenshot --json '{}' +unity-cli --project-path --timeout-ms 1000 raw capture_screenshot --json '{"osFallback":false}' +``` + +前者は exit 0、`fallback: "os"`、PNG 1512 × 949。 +後者は exit 6、`TIMEOUT`。[実行記録と PNG SHA256](modal-summary.json)、 +[成功レスポンス](modal-os-fallback.stdout.json)、[無効化時のエラー](modal-fallback-disabled.stdout.json)。 +PNG 自体はローカルの隔離プロジェクトに保持し、この証跡には寸法と SHA256 を収録した。 +終了時は対象 PID の検証用ダイアログだけを閉じた。 + +## 公開23操作 + +`scripts/bench-editor-ops.py::operations()` の23操作を使用した。 +シーンとアセットは隔離プロジェクトの `Assets/Scenes/Generated/E2E/Performance` に作成した。 +これは各操作1回の動作確認であり、100サンプルの速度比較や前面・背面のベンチマークではない。 + +最初の試走は Input System の restart ダイアログでアセット3操作が停止した。 +Editor を閉じた状態で setup により `activeInputHandler: 2` に変更し、再試走した。 +初回 setup 用の最小プロジェクトにも、初回 ping 後に同じ Input System の警告が開いた。 +初回接続の成功はその時点の結果であり、設定ファイルのない最小プロジェクトを +継続して無人運用できることまでは主張しない。検証終了時に警告を確認して閉じた。 +その通常 Domain Reload 有効の試走では21/23が成功し、Play 後の状態ポーリングに +`OPERATION_FAILED: early eof`、直後の Stop に `UNAUTHORIZED` が発生した。 +後続の Stop により検証用 Play Mode は終了した。[最初の結果](first-operations.json)、[通常設定の結果](operations.json)。 + +[既存比較資料](../../comparison.md) と同じ `DisableDomainReload` / `PlayUnfocused` にすると、 +23/23が成功した。[設定変更と以前の値](staff-play-settings.stdout.json)、 +[全呼び出しの終了コード・時間](staff-final-summary.json)、[操作別結果](staff-final-operations.json)。 +通常 Domain Reload 中の接続エラーを修正済みとは扱わない。 +ローカル C# 読取は embedded package の `Packages/com.akiojin.unity-cli-bridge/Editor/Core/UnityCliBridgeHost.cs` を使用した。 + +## 配布経路 + +公開スクリプト `https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1` を +Windows PowerShell 5 の `irm ... | iex` で実行した。 +`UNITY_CLI_TOOLS_ROOT` を隔離先に設定し、`UNITY_CLI_SKIP_PATH_UPDATE=1` でユーザーの PATH 更新を省いた。 +Windows PowerShell 5 の module path はプロセス内でその `$PSHOME\Modules` に設定した。 +Release 0.18.1 の Windows バイナリを SHA256SUMS 検証後に導入し、 +[version](release-version.json) と [実 Editor ping](fresh-setup-summary.json) が成功した。 +[公開 Release のアセット](release.json) と [バイナリの SHA256](environment.json) を収録している。 + +[winget show](winget.json) は「入力条件に一致するパッケージが見つかりませんでした」。 +[repository secret の名前一覧](repository-secret-names.json) に `WINGET_TOKEN` はない。 +トークン値は読み取っていない。winget での install / ping、初回公開提出とトークン設定は未実施。 + +## Verification Report + +Mode: full。Launch mode: interactive (`launch_route: manual`)。 +Baseline: `origin/develop` / HEAD `338f426119b61123567b74028e7e8fe3bd99caa5`。 +Changed surfaces: interactive CLI、Editor 外部連携、C# シーン作成・保存、テスト条件、docs。 +Detected runners: Cargo、Unity Test Framework。Playwright と LSP の dotnet test は対象外。 + +直接実行の結果: + +| コマンド | 結果 | +| --- | --- | +| `cargo build --bin unity-cli` | PASS(Windows native) | +| `cargo clippy --all-targets -- -D warnings` | PASS(Windows native、Unix 専用 import の条件修正後) | +| `cargo test --test setup_dry_run -- --test-threads=1` | PASS、2件 | +| `cargo test editor_launch_uses_paths_supported_by_unity -- --test-threads=1` | PASS、1件 | +| `unity-cli test --mode editmode --filter SceneHandlerTests ...` | PASS、11件。[JUnit GREEN](green-results.xml)。修正前は11件中3件失敗。[JUnit RED](red-results.xml)。 | +| `cargo test --all-targets --no-fail-fast -- --test-threads=1` | FAIL。最終修正で **605 PASS / 1 FAIL**。失敗は `json_envelope::skills_show_and_lint_use_envelopes` のみ。[結果](final-checks.json)、[全件ログ](cargo-all-final.txt)。 | +| `unity-cli skills lint --severity error` | FAIL。checkout の skill リンク46件が通常ファイルになっている。 | + +全件ゲートの失敗は `core.symlinks=false` の Windows checkout が Git の symlink を +リンク先文字列の通常ファイルとして展開したことによる R20 / R21 エラー。 +Git blob と内容一致を確認した上で実リンクへの復元を試したが、`WinError 1314`(権限不足)で失敗し、 +リンク変更は行われなかった。lint の抑制や Developer Mode / セキュリティ設定の変更は行っていない。 + +正式な `verify.plan` / `verify.run` には fmt、clippy、全 targets の単一スレッド test +(`--no-fail-fast` で全 suite の結果を収集)、skills lint、実 Unity の SceneHandlerTests を登録した。 +正式 run は [300秒待機](verify-run.json)、[1500秒待機](verify-run-second.json) の両方で +他プロジェクトの host-wide lease により `deferred`。コマンドは正式 run からは未実行で、 +Verification Run Record は未生成。lease 保有者には介入していない。 +上表の最終 Cargo 結果は通常の直接実行で、正式記録と区別する。 + +Test Inventory: [Cargo 全606件のテスト名・suite・結果](cargo-test-inventory.json)。 +Unity の実行テスト名は JUnit に全11件を収録。 +追加 Rust テストは `app::editor::tests::editor_launch_uses_paths_supported_by_unity` と +`setup_launch_returns_output_while_editor_is_still_running`。 +最終バイナリの自動 headless 起動でも SceneHandlerTests 11/11 が成功した。[最終実行ログ](unity-final.txt)。 +`mcp::configure_all_clients_preserves_other_servers_and_dry_run` は出力先と更新内容を確認するテストに強化した。 + +User Verification Result: pending。自動実行の成功をユーザー確認済みとは扱わない。 +自動ゲートが失敗しているため、追加のユーザー確認を Ready 判定に使わない。 +Agent Visual Check: n/a(CLI と Editor 連携を検証。Web/TUI の表示変更なし)。 + +## 再開条件 + +1. Windows checkout の正規 skill リンクを作成できる実行環境で、全件 test / lint を再実行する。 +2. 原資料 `pm-scratch/staff-report.md` の所在を確認し、公開23操作との差分を検証する。 +3. Linux の実 Unity Editor と Wayland / X11 のキャプチャ環境で AC-4 を実行する。 +4. winget 初回公開の担当と `WINGET_TOKEN` の設定を確定し、公開 source から install / ping を検証する。 +5. 共通検証枠を確保し、正式な自動ゲートと必要なユーザー確認が通ってから Ready PR を作成する。 diff --git a/docs/verification/issue-386/cargo-all-final.txt b/docs/verification/issue-386/cargo-all-final.txt new file mode 100644 index 00000000..e37cd86e --- /dev/null +++ b/docs/verification/issue-386/cargo-all-final.txt @@ -0,0 +1,721 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 9.05s + Running unittests src\main.rs (target\debug\deps\unity_cli-66a997df271e997b.exe) + +running 554 tests +test app::editor::tests::editor_launch_uses_paths_supported_by_unity ... ok +test app::runner::tests::ambiguous_editor_fails_before_contacting_any_editor ... ok +test app::runner::tests::animation_curve_edits_accept_operations_and_tangent_modes ... ok +test app::runner::tests::animation_curve_edits_reject_missing_identifiers_and_invalid_nested_fields ... ok +test app::runner::tests::animation_curve_queries_validate_complete_binding_filters ... ok +test app::runner::tests::audio_mixer_arguments_are_action_specific ... ok +test app::runner::tests::augment_command_stats_inserts_cli_snapshot ... ok +test app::runner::tests::baking_invalid_target_missing_scene_and_missing_job_are_rejected ... ok +test app::runner::tests::baking_surface_requires_path_before_contacting_editor ... ok +test app::runner::tests::baking_valid_targets_and_polling_are_accepted ... ok +test app::runner::tests::bridge_commands_resolve_explicit_project_path ... ok +test app::runner::tests::build_reference_call_clean_defaults ... ok +test app::runner::tests::build_reference_call_clean_with_version ... ok +test app::runner::tests::build_reference_call_diff_path_mode_with_limit ... ok +test app::runner::tests::build_reference_call_diff_symbol_mode ... ok +test app::runner::tests::build_reference_call_embed_build_includes_version ... ok +test app::runner::tests::build_reference_call_embed_build_omits_optional_version ... ok +test app::runner::tests::build_reference_call_embed_search_omits_optional_top_k ... ok +test app::runner::tests::build_reference_call_embed_search_with_top_k ... ok +test app::runner::tests::build_reference_call_fetch_carries_all_flags ... ok +test app::runner::tests::build_reference_call_fetch_defaults_without_overrides ... ok +test app::runner::tests::build_reference_call_find_symbol_minimal ... ok +test app::runner::tests::build_reference_call_find_symbol_with_filters ... ok +test app::runner::tests::build_reference_call_grep_defaults_context_to_zero ... ok +test app::runner::tests::build_reference_call_grep_with_file_glob_and_context ... ok +test app::runner::tests::build_reference_call_resolve_symbol_at_minimal ... ok +test app::runner::tests::build_reference_call_resolve_symbol_at_with_version ... ok +test app::runner::tests::build_reference_call_search_minimal_pattern ... ok +test app::runner::tests::build_reference_call_search_with_all_options ... ok +test app::runner::tests::build_reference_call_status_includes_explicit_version ... ok +test app::runner::tests::build_reference_call_status_omits_optional_version ... ok +test app::runner::tests::build_reference_call_view_omits_optional_lines ... ok +test app::runner::tests::build_reference_call_view_with_range ... ok +test app::runner::tests::capture_screenshot_timeout_respects_os_fallback_flag ... ok +test app::runner::tests::env_var_guard_restores_previous_value ... ok +test app::runner::tests::eval_cli_accepts_code_and_rejects_invalid_mode ... ok +test app::runner::tests::eval_dry_run_does_not_execute_arbitrary_code ... ok +test app::runner::tests::eval_schemas_require_code_and_status_id ... ok +test app::runner::tests::eval_transport_error_keeps_generated_request_id ... ok +test app::runner::tests::execute_tool_skips_mutating_tool_in_dry_run_mode ... ok +test app::runner::tests::hot_reload_requires_revision_and_explicit_action ... ok +test app::runner::tests::init_tracing_accepts_verbose_levels ... ok +test app::runner::tests::instances_list_defaults_host_to_ipv4_loopback ... ok +test app::runner::tests::load_params_defaults_to_empty_object ... ok +test app::runner::tests::load_params_reads_inline_json ... ok +test app::runner::tests::load_params_reads_json_from_file ... ok +test app::runner::tests::load_params_rejects_when_json_and_params_file_are_both_set ... ok +test app::runner::tests::parse_external_tool_command_accepts_json_flag ... ok +test app::runner::tests::parse_external_tool_command_rejects_unknown_flag ... ok +test app::runner::tests::parse_external_tool_command_requires_tool_name ... ok +test app::runner::tests::parse_external_tool_command_requires_values_for_flags ... ok +test app::runner::tests::parse_external_tool_command_supports_equals_forms ... ok +test app::runner::tests::parse_json_object_accepts_object ... ok +test app::runner::tests::parse_json_object_rejects_non_object ... ok +test app::runner::tests::parse_ports_deduplicates_values ... ok +test app::runner::tests::parse_ports_rejects_invalid_values ... ok +test app::runner::tests::parse_ports_returns_empty_for_none ... ok +test app::runner::tests::parse_ports_with_diagnostics_reports_duplicate_values ... ok +test app::runner::tests::ping_version_check_reports_mismatch_and_unknown ... ok +test app::runner::tests::prefab_override_validation_requires_explicit_scope_and_apply_target ... ok +test app::runner::tests::print_value_text_handles_string_and_object ... ok +test app::runner::tests::project_path_flag_is_global_and_feeds_runtime_overrides ... ok +test app::runner::tests::run_with_cli_batch_marks_skipped_items_in_dry_run_mode ... ok +test app::runner::tests::run_with_cli_exercises_remote_command_error_paths ... ok +test app::runner::tests::run_with_cli_handles_instances_and_daemon_commands_without_server ... ok +test app::runner::tests::run_with_cli_handles_local_tool_and_batch_paths ... ok +test app::runner::tests::run_with_cli_rejects_unknown_external_tool ... ok +test app::runner::tests::run_with_cli_requires_batch_input_source ... ok +test app::runner::tests::run_with_cli_set_active_text_output_when_reachable ... ok +test app::runner::tests::run_with_cli_supports_tool_schema_command ... ok +test app::runner::tests::runtime_overrides_are_derived_from_cli_at_app_boundary ... ok +test app::runner::tests::setup_and_bridge_cli_arguments_parse ... ok +test app::runner::tests::timeline_manage_is_skipped_in_dry_run ... ok +test app::runner::tests::timeline_validation_requires_target_and_valid_action ... ok +test app::runner::tests::validate_tool_params_accepts_add_component_payload ... ok +test app::runner::tests::validate_tool_params_accepts_addressables_manage_add_entry ... ok +test app::runner::tests::validate_tool_params_accepts_analyze_asset_dependencies_get_dependencies ... ok +test app::runner::tests::validate_tool_params_accepts_build_index_output_path ... ok +test app::runner::tests::validate_tool_params_accepts_create_animation_clip_payload ... ok +test app::runner::tests::validate_tool_params_accepts_create_animator_controller_payload ... ok +test app::runner::tests::validate_tool_params_accepts_create_gameobject_with_vector_fields ... ok +test app::runner::tests::validate_tool_params_accepts_create_sprite_atlas_payload ... ok +test app::runner::tests::validate_tool_params_accepts_delete_gameobject_with_path_and_paths ... ok +test app::runner::tests::validate_tool_params_accepts_execute_menu_item_get_available_menus ... ok +test app::runner::tests::validate_tool_params_accepts_execute_menu_item_without_action ... ok +test app::runner::tests::validate_tool_params_accepts_get_input_actions_state_with_asset_path ... ok +test app::runner::tests::validate_tool_params_accepts_input_keyboard_batch_actions ... ok +test app::runner::tests::validate_tool_params_accepts_load_scene_by_name ... ok +test app::runner::tests::validate_tool_params_accepts_lsp_write_payload_with_path_alias ... ok +test app::runner::tests::validate_tool_params_accepts_manage_layers_get_by_index ... ok +test app::runner::tests::validate_tool_params_accepts_package_manager_list_action ... ok +test app::runner::tests::validate_tool_params_accepts_profiler_start_payload ... ok +test app::runner::tests::validate_tool_params_accepts_valid_payload ... ok +test app::runner::tests::validate_tool_params_accepts_write_csharp_file_payload ... ok +test app::runner::tests::validate_tool_params_rejects_addressables_analyze_dependencies_without_asset_path ... ok +test app::runner::tests::validate_tool_params_rejects_addressables_manage_move_entry_without_target_group ... ok +test app::runner::tests::validate_tool_params_rejects_analyze_asset_dependencies_get_dependencies_without_asset_path ... ok +test app::runner::tests::validate_tool_params_rejects_analyze_asset_dependencies_invalid_action ... ok +test app::runner::tests::validate_tool_params_rejects_analyze_screenshot_without_source ... ok +test app::runner::tests::validate_tool_params_rejects_create_animation_clip_without_sprite_paths ... ok +test app::runner::tests::validate_tool_params_rejects_create_package_setting_without_value ... ok +test app::runner::tests::validate_tool_params_rejects_delete_gameobject_without_target ... ok +test app::runner::tests::validate_tool_params_rejects_execute_menu_item_without_action_or_menu_path ... ok +test app::runner::tests::validate_tool_params_rejects_execute_menu_item_without_menu_path ... ok +test app::runner::tests::validate_tool_params_rejects_invalid_animator_condition_mode ... ok +test app::runner::tests::validate_tool_params_rejects_invalid_sprite_atlas_filter_mode ... ok +test app::runner::tests::validate_tool_params_rejects_load_scene_with_both_identifiers ... ok +test app::runner::tests::validate_tool_params_rejects_manage_asset_database_move_without_to_path ... ok +test app::runner::tests::validate_tool_params_rejects_manage_layers_add_without_layer_name ... ok +test app::runner::tests::validate_tool_params_rejects_manage_layers_invalid_action ... ok +test app::runner::tests::validate_tool_params_rejects_manage_selection_set_without_object_paths ... ok +test app::runner::tests::validate_tool_params_rejects_manage_tools_activate_without_tool_name ... ok +test app::runner::tests::validate_tool_params_rejects_manage_windows_focus_without_window_type ... ok +test app::runner::tests::validate_tool_params_rejects_missing_required_property ... ok +test app::runner::tests::validate_tool_params_rejects_package_manager_search_without_keyword ... ok +test app::runner::tests::validate_tool_params_rejects_registry_config_add_scope_without_scope ... ok +test app::runner::tests::validate_tool_params_rejects_remove_input_binding_without_selector ... ok +test app::runner::tests::validate_tool_params_rejects_set_component_field_missing_required ... ok +test app::runner::tests::validate_tool_params_rejects_unknown_field_for_clear_logs ... ok +test app::runner::tests::validate_tool_params_rejects_unknown_property_when_schema_is_strict ... ok +test app::runner::tests::validate_tool_params_rejects_unknown_run_tests_property ... ok +test app::setup::tests::hub_paths_for_windows_and_linux_do_not_depend_on_test_host ... ok +test app::setup::tests::launch_editor_skips_when_project_is_locked_and_errors_without_editor ... ok +test app::setup::tests::project_unity_version_and_hub_path ... ok +test app::setup::tests::setup_dry_run_leaves_editor_unchecked_and_skips_writes ... ok +test app::setup::tests::setup_flags_editor_serving_another_project ... ok +test app::setup::tests::setup_installs_bridge_and_confirms_matching_editor ... ok +test app::setup::tests::setup_reports_version_mismatch_as_json ... ok +test app::setup::tests::setup_without_dry_run_reports_unreachable_editor ... ok +test app::test_report::tests::github_annotations_extract_unity_location_and_escape_injection ... ok +test app::test_report::tests::junit_preserves_failed_skipped_and_escaped_details ... ok +test app::test_report::tests::junit_time_is_millisecond_precision_for_xunit_schema ... ok +test app::test_report::tests::nunit_nests_test_cases_in_a_suite_and_preserves_details ... ok +test app::test_report::tests::parent_suite_rollups_do_not_duplicate_leaf_failures ... ok +test app::test_report::tests::suite_failure_is_reported_even_without_failed_leaves ... ok +test cli::test_command_tests::test_command_accepts_report_output_without_changing_global_output ... ok +test core::bridge::tests::dry_run_reports_change_without_writing ... ok +test core::bridge::tests::embedded_package_is_reported_and_not_duplicated ... ok +test core::bridge::tests::input_backends_untouched_when_setting_absent_or_already_enabled ... ok +test core::bridge::tests::install_adds_openupm_registry_and_cli_version ... ok +test core::bridge::tests::install_adds_scope_to_existing_openupm_registry ... ok +test core::bridge::tests::install_enables_input_system_backends_while_editor_is_closed ... ok +test core::bridge::tests::install_is_noop_when_already_configured_by_hand ... ok +test core::bridge::tests::install_keeps_other_version_and_upgrade_pins_cli_version ... ok +test core::bridge::tests::install_leaves_input_backends_when_editor_is_open_or_dry_run ... ok +test core::bridge::tests::install_twice_leaves_manifest_byte_identical ... ok +test core::bridge::tests::rejects_malformed_manifest ... ok +test core::bridge::tests::resolve_project_root_walks_up_and_validates_explicit_path ... ok +test core::bridge::tests::status_prefers_lock_resolution_and_reports_missing ... ok +test core::bridge::tests::upgrade_leaves_custom_sources_alone ... ok +test core::bridge::tests::version_check_classifies_versions ... ok +test core::command_stats::tests::snapshot_groups_calls_by_tool_and_route ... ok +test core::config::tests::default_host_returns_ipv4_loopback_without_env ... ok +test core::config::tests::default_port_returns_6400_without_env ... ok +test core::config::tests::default_timeout_returns_30000_without_env ... ok +test core::config::tests::empty_value_is_ignored ... ok +test core::config::tests::execution_context_uses_defaults ... ok +test core::config::tests::fails_when_legacy_alias_is_set ... ok +test core::config::tests::fails_when_removed_unityd_env_is_set ... ok +test core::config::tests::returns_none_when_no_keys_set ... ok +test core::config::tests::u16_env_parses_correctly ... ok +test core::config::tests::u16_env_rejects_zero ... ok +test core::config::tests::u64_env_parses_correctly ... ok +test core::config::tests::u64_env_rejects_zero ... ok +test core::doctor::tests::classification_priority ... ok +test core::doctor::tests::editor_import_workers_are_not_reusable_editors ... ok +test core::doctor::tests::parses_safe_mode_and_latest_compile_errors ... ok +test core::doctor::tests::reads_bridge_version_from_local_file_dependency ... ok +test core::doctor::tests::reads_project_bridge_port ... ok +test core::doctor::tests::recognizes_editor_command_lines_only ... ok +test core::doctor::tests::reports_editor_not_running ... ok +test core::doctor::tests::reports_port_in_use_with_owner_pid ... ok +test core::doctor::tests::safe_mode_exit_clears_flag ... ok +test core::editor_discovery::tests::ambiguous_error_json_lists_candidates ... ok +test core::editor_discovery::tests::dead_pid_marks_lockfile_stale ... ok +test core::editor_discovery::tests::discover_reads_lockfiles_and_skips_garbage ... ok +test core::editor_discovery::tests::expired_heartbeat_marks_lockfile_stale ... ok +test core::editor_discovery::tests::pid_zero_is_never_alive ... ok +test core::editor_discovery::tests::select_for_path_ignores_stale_editors_and_sibling_prefixes ... ok +test core::editor_discovery::tests::select_for_path_prefers_deepest_live_project ... ok +test core::endpoint::tests::active_instance_keeps_priority_over_lockfile_discovery ... ok +test core::endpoint::tests::cli_override_wins_over_active_instance ... ok +test core::endpoint::tests::cwd_inside_project_selects_that_editor ... ok +test core::endpoint::tests::cwd_outside_projects_with_two_editors_is_ambiguous ... ok +test core::endpoint::tests::env_port_wins_when_no_cli_override ... ok +test core::endpoint::tests::explicit_port_wins_over_project_path_and_lockfiles ... ok +test core::endpoint::tests::no_lockfiles_keeps_legacy_default ... ok +test core::endpoint::tests::project_command_targets_its_own_editor_among_several ... ok +test core::endpoint::tests::project_command_without_its_editor_uses_default_endpoint ... ok +test core::endpoint::tests::project_path_selects_matching_editor ... ok +test core::endpoint::tests::project_path_without_running_editor_is_not_found ... ok +test core::endpoint::tests::project_root_env_falls_back_to_default_without_any_lockfile ... ok +test core::endpoint::tests::single_running_editor_is_used_from_anywhere ... ok +test core::endpoint::tests::stale_editors_do_not_cause_ambiguity ... ok +test core::endpoint::tests::unity_project_root_env_acts_as_project_path ... ok +test core::instances::tests::authenticated_health_checks_support_listing_and_selection ... ok +test core::instances::tests::list_instances_adds_default_port_when_no_entries_exist ... ok +test core::instances::tests::list_instances_enumerates_lockfiles_without_ports ... ok +test core::instances::tests::list_instances_keeps_explicit_ports_next_to_lockfiles ... ok +test core::instances::tests::list_instances_reports_down_for_tcp_listener_that_is_not_unity_bridge ... ok +test core::instances::tests::list_instances_reports_up_for_reachable_port ... ok +test core::instances::tests::load_registry_reconstructs_missing_ids ... ok +test core::instances::tests::parse_id_validates_shape ... ok +test core::instances::tests::registry_path_uses_env_and_creates_parent_directory ... ok +test core::instances::tests::registry_round_trip_serialization_shape_is_supported ... ok +test core::instances::tests::set_active_fails_for_unreachable_instance ... ok +test core::instances::tests::set_active_succeeds_for_reachable_instance_and_tracks_previous ... ok +test core::managed_binaries::tests::cache_root_falls_back_to_home_unity_cache ... ok +test core::managed_binaries::tests::cache_root_prefers_unity_cli_cache_root_env ... ok +test core::managed_binaries::tests::detect_rid_returns_known_target_triple ... ok +test core::managed_binaries::tests::download_latest_binary_applies_matching_checksum ... ok +test core::managed_binaries::tests::download_latest_binary_rejects_checksum_mismatch_and_keeps_existing_install ... ok +test core::managed_binaries::tests::ensure_latest_for_can_skip_remote_checks_in_tests ... ok +test core::managed_binaries::tests::ensure_local_uses_existing_binary_without_download ... ok +test core::managed_binaries::tests::get_json_fails_with_status_and_body ... ok +test core::managed_binaries::tests::get_json_parses_http_body ... ok +test core::managed_binaries::tests::get_json_retries_transient_server_error ... ok +test core::managed_binaries::tests::get_optional_text_returns_body_for_success ... ok +test core::managed_binaries::tests::get_optional_text_returns_none_for_not_found ... ok +test core::managed_binaries::tests::get_response_includes_authorization_header ... ok +test core::managed_binaries::tests::get_response_reports_http_status_errors ... ok +test core::managed_binaries::tests::parse_sha256sums_reads_text_and_binary_mode_entries ... ok +test core::managed_binaries::tests::read_local_version_returns_none_for_missing_or_blank_file ... ok +test core::managed_binaries::tests::replace_file_atomic_overwrites_destination ... ok +test core::managed_binaries::tests::sha256_file_matches_known_hash ... ok +test core::managed_binaries::tests::tools_root_falls_back_to_home_unity_tools_when_env_unset ... ok +test core::managed_binaries::tests::tools_root_prefers_unity_cli_tools_root_env ... ok +test core::managed_binaries::tests::unity_cli_status_uses_managed_install_layout ... ok +test core::managed_binaries::tests::verify_manifest_against_checksums_requires_matching_entry ... ok +test core::managed_binaries::tests::write_and_read_local_version_round_trip ... ok +test core::runtime_paths::tests::daemon_dir_is_under_run_root ... ok +test core::self_update::tests::is_recent_returns_false_for_missing_path ... ok +test core::self_update::tests::is_recent_returns_true_for_freshly_touched_file ... ok +test core::self_update::tests::last_check_path_uses_unity_cli_tools_root_env ... ok +test core::self_update::tests::maybe_self_update_skipped_when_opt_out_env_set ... ok +test core::self_update::tests::maybe_self_update_skips_when_recent_check_exists ... ok +test core::self_update::tests::touch_creates_parent_and_writes_marker ... ok +test core::self_update::tests::warn_cargo_conflict_runs_without_panic ... ok +test daemon::runtime::tests::runtime_module_builds_without_warnings_when_unix_code_is_disabled ... ok +test daemon::spawn::tests::spawn_detached_starts_the_command ... ok +test daemon::spawn::tests::spawn_module_builds_for_windows_without_warnings ... ok +test daemon::spawn::tests::spawned_child_does_not_hold_the_callers_stdout_pipe ... ok +test daemon::unityd::tests::daemon_call_error_classification ... ok +test daemon::unityd::tests::daemon_request_batch_round_trip ... ok +test daemon::unityd::tests::daemon_request_ping_round_trip ... ok +test daemon::unityd::tests::daemon_request_status_round_trip ... ok +test daemon::unityd::tests::daemon_request_stop_round_trip ... ok +test daemon::unityd::tests::daemon_request_tool_round_trip ... ok +test daemon::unityd::tests::daemon_response_error_round_trip ... ok +test daemon::unityd::tests::daemon_response_round_trip ... ok +test daemon::unityd::tests::daemon_response_round_trip_preserves_timing ... ok +test daemon::unityd::tests::idle_timeout_default ... ok +test daemon::unityd::tests::pid_file_path_is_under_tools_dir ... ok +test daemon::unityd::tests::pooled_connection_closed_by_editor_restart_is_reconnected_before_sending ... ok +test daemon::unityd::tests::pooled_connection_uses_each_requests_timeout ... ok +test daemon::unityd::tests::request_lost_after_sending_is_reported_and_not_resent ... ok +test daemon::unityd::tests::startup_lock_times_out_and_is_reusable_after_release ... ok +test daemon::unityd::tests::tools_dir_creates_directory ... ok +test lsp::client::tests::collect_document_symbols_flattens_nested_symbols ... ok +test lsp::client::tests::get_apply_defaults_to_false ... ok +test lsp::client::tests::id_matches_accepts_number_and_string_id ... ok +test lsp::client::tests::kind_from_lsp_maps_known_values ... ok +test lsp::client::tests::normalize_lsp_write_result_adds_contract_fields ... ok +test lsp::client::tests::normalize_rel_path_accepts_assets_packages_and_library ... ok +test lsp::client::tests::normalize_rel_path_extracts_supported_prefix_from_absolute_like_input ... ok +test lsp::client::tests::normalize_rel_path_rejects_parent_traversal ... ok +test lsp::client::tests::path_matches_scope_filters_paths ... ok +test lsp::client::tests::remove_symbol_request_includes_fail_on_references_when_set ... ok +test lsp::client::tests::remove_symbol_request_omits_fail_on_references_when_unset ... ok +test lsp::client::tests::require_helpers_validate_expected_fields ... ok +test lsp::client::tests::retryable_session_error_detects_transport_failures ... ok +test lsp::client::tests::retryable_session_error_ignores_argument_errors ... ok +test lsp::client::tests::to_project_relative_or_raw_returns_relative_for_absolute_under_root ... ok +test lsp::client::tests::uri_and_ref_path_helpers_resolve_project_relative_paths ... ok +test lsp::client::tests::uri_to_rel_path_rejects_non_file_uris ... ok +test lsp::daemon::tests::daemon_idle_timeout_uses_env_override ... ok +test lsp::daemon::tests::handle_request_handles_ping_status_and_stop ... ok +test lsp::daemon::tests::is_would_block_checks_error_kind ... ok +test lsp::daemon::tests::write_all_with_retry_handles_would_block_and_partial_writes ... ok +test lsp::daemon::tests::write_all_with_retry_rejects_zero_byte_progress ... ok +test lsp::daemon::tests::write_pid_file_and_cleanup_manage_files_under_tools_root ... ok +test mcp::configure::tests::custom_root_may_have_missing_ancestors_without_creating_them ... ok +test mcp::configure::tests::invalid_config_is_never_overwritten_and_preview_creates_nothing ... ok +test mcp::configure::tests::malformed_shapes_and_http_name_collisions_are_rejected ... ok +test mcp::configure::tests::merges_inline_toml_without_losing_other_servers_or_options ... ok +test mcp::configure::tests::windows_and_local_paths ... ok +test mcp::tests::projects_owned_custom_descriptor_without_an_mcp_specific_schema ... ok +test reference::cache::tests::gc_empty_root_returns_empty ... ok +test reference::cache::tests::gc_keep_zero_removes_all_versions ... ok +test reference::cache::tests::gc_keeps_n_newest_and_returns_removed ... ok +test reference::cache::tests::gc_skips_non_directory_entries ... ok +test reference::cache::tests::list_versions_empty_when_root_missing ... ok +test reference::cache::tests::list_versions_returns_existing_dirs ... ok +test reference::cache::tests::list_versions_skips_files_in_root ... ok +test reference::cache::tests::meta_roundtrip ... ok +test reference::cache::tests::read_meta_returns_error_for_invalid_json ... ok +test reference::cache::tests::read_meta_returns_error_when_missing ... ok +test reference::cache::tests::version_dir_rejects_empty ... ok +test reference::cache::tests::version_dir_rejects_paths_outside_single_cache_entry ... ok +test reference::cache::tests::version_dir_under_cache_root ... ok +test reference::diff::tests::compute_line_diff_empty_for_identical_lines ... ok +test reference::diff::tests::compute_line_diff_for_deletes_only_returns_removal_hunk ... ok +test reference::diff::tests::compute_line_diff_for_inserts_only_returns_addition_hunk ... ok +test reference::diff::tests::compute_line_diff_for_separate_changes_produces_multiple_hunks ... ok +test reference::diff::tests::compute_line_diff_replacement_isolates_changed_lines ... ok +test reference::diff::tests::compute_path_diff_can_be_truncated ... ok +test reference::diff::tests::compute_path_diff_categorises_runtime_export ... ok +test reference::diff::tests::compute_symbol_diff_detects_changed_animator ... ok +test reference::diff::tests::compute_symbol_diff_returns_diff_when_only_one_side_has_symbol ... ok +test reference::diff::tests::compute_symbol_diff_returns_none_for_missing_in_both ... ok +test reference::diff::tests::ensure_cache_dir_errors_on_missing ... ok +test reference::diff::tests::split_fqn_separates_namespace_and_name ... ok +test reference::embed::tests::build_embedding_index_handles_empty_symbol_index ... ok +test reference::embed::tests::build_embedding_index_with_mock_embedder ... ok +test reference::embed::tests::cosine_similarity_handles_zero_vectors ... ok +test reference::embed::tests::embedding_roundtrip_via_bincode ... ok +test reference::embed::tests::resolve_onnxruntime_dylib_explains_how_to_install_when_missing ... ok +test reference::embed::tests::resolve_onnxruntime_dylib_falls_back_to_first_existing_candidate ... ok +test reference::embed::tests::resolve_onnxruntime_dylib_prefers_existing_env_path ... ok +test reference::embed::tests::resolve_onnxruntime_dylib_rejects_missing_env_path ... ok +test reference::embed::tests::search_ranks_by_cosine_similarity ... ok +test reference::embed::tests::search_returns_empty_for_empty_index ... ok +test reference::embed::tests::search_returns_empty_for_empty_query ... ok +test reference::embed::tests::symbol_to_text_includes_namespace_and_kind ... ok +test reference::embed::tests::symbol_to_text_without_namespace_omits_dot ... ok +test reference::fetcher::tests::api_discovery_paginates_branches_and_includes_tags ... ok +test reference::fetcher::tests::api_discovery_surfaces_http_errors ... ok +test reference::fetcher::tests::archive_url_uses_unity_cs_reference_org ... ok +test reference::fetcher::tests::build_clone_args_emits_shallow_single_branch ... ok +test reference::fetcher::tests::ensure_git_available_succeeds_in_test_env ... ok +test reference::fetcher::tests::extract_zip_to_rejects_entries_with_parent_segments ... ok +test reference::fetcher::tests::extract_zip_to_strips_top_level_prefix_and_writes_files ... ok +test reference::fetcher::tests::fetch_selected_pins_commit_after_branch_advances ... ok +test reference::fetcher::tests::fetch_selected_rejects_invalid_commit_before_creating_destination ... ok +test reference::fetcher::tests::github_token_returns_none_when_env_unset ... ok +test reference::fetcher::tests::github_token_skips_empty_and_picks_first_non_empty ... ok +test reference::fetcher::tests::license_ok_when_env_set ... ok +test reference::fetcher::tests::license_ok_when_flag_true ... ok +test reference::fetcher::tests::license_rejects_zero_value ... ok +test reference::fetcher::tests::license_required_when_flag_false_and_env_unset ... ok +test reference::fetcher::tests::list_public_refs_discovers_branches_and_tags ... ok +test reference::fetcher::tests::list_public_refs_preserves_transport_error ... ok +test reference::fetcher::tests::run_clone_rejects_when_license_not_accepted ... ok +test reference::index::tests::build_or_update_index_handles_existing_fixture ... ok +test reference::index::tests::build_or_update_index_persists_signature ... ok +test reference::index::tests::build_or_update_index_skips_already_indexed_files_until_change ... ok +test reference::index::tests::extract_symbols_from_text_captures_namespace ... ok +test reference::index::tests::extract_symbols_from_text_does_not_double_capture_class_name ... ok +test reference::index::tests::extract_symbols_from_text_finds_class ... ok +test reference::index::tests::extract_symbols_from_text_finds_methods ... ok +test reference::index::tests::extract_symbols_from_text_finds_property ... ok +test reference::index::tests::extract_symbols_from_text_finds_struct_and_interface ... ok +test reference::index::tests::file_signature_changes_when_content_changes ... ok +test reference::index::tests::find_symbol_filters_by_kind_and_namespace ... ok +test reference::index::tests::validate_kind_accepts_known_and_rejects_unknown ... ok +test reference::search::tests::grep_filters_by_filename_glob ... ok +test reference::search::tests::grep_finds_class_animator_with_line_numbers ... ok +test reference::search::tests::grep_returns_context_lines ... ok +test reference::search::tests::view_rejects_parent_traversal ... ok +test reference::search::tests::view_returns_requested_line_range ... ok +test reference::tests::cached_fetch_and_status_report_stored_provenance ... ok +test reference::tests::cached_unknown_version_can_be_used_without_branch_resolution ... ok +test reference::tests::dir_size_empty_returns_zero ... ok +test reference::tests::dir_size_sums_file_lengths ... ok +test reference::tests::execute_clean_dry_run_false_actually_removes ... ok +test reference::tests::execute_clean_dry_run_on_empty_cache_returns_empty_removed ... ok +test reference::tests::execute_diff_errors_when_cache_missing ... ok +test reference::tests::execute_diff_path_mode_returns_added_removed_changed ... ok +test reference::tests::execute_diff_requires_from_and_to ... ok +test reference::tests::execute_diff_requires_symbol_or_path ... ok +test reference::tests::execute_diff_symbol_mode_returns_diffs ... ok +test reference::tests::execute_embed_build_errors_when_cache_missing ... ok +test reference::tests::execute_embed_search_errors_when_index_missing ... ok +test reference::tests::execute_embed_search_requires_query ... ok +test reference::tests::execute_fetch_force_preserves_existing_on_transport_failure ... ok +test reference::tests::execute_fetch_skips_when_destination_exists_without_force ... ok +test reference::tests::execute_find_symbol_empty_hits_for_unknown_name ... ok +test reference::tests::execute_find_symbol_filters_namespace ... ok +test reference::tests::execute_find_symbol_rejects_unknown_kind ... ok +test reference::tests::execute_find_symbol_requires_name ... ok +test reference::tests::execute_find_symbol_returns_error_when_cache_missing ... ok +test reference::tests::execute_find_symbol_returns_hits_from_fixture ... ok +test reference::tests::execute_grep_invalid_regex_returns_error ... ok +test reference::tests::execute_grep_requires_pattern ... ok +test reference::tests::execute_grep_supports_file_glob_filter ... ok +test reference::tests::execute_grep_via_dispatcher_returns_hits ... ok +test reference::tests::execute_resolve_symbol_at_empty_token_for_blank_position ... ok +test reference::tests::execute_resolve_symbol_at_finds_token_via_fixture ... ok +test reference::tests::execute_resolve_symbol_at_requires_path_line_column ... ok +test reference::tests::execute_resolve_symbol_at_requires_project_prefix ... ok +test reference::tests::execute_search_requires_pattern ... ok +test reference::tests::execute_search_via_dispatcher_truncates_max_results ... ok +test reference::tests::execute_search_without_max_results_returns_all_hits ... ok +test reference::tests::execute_status_includes_size_bytes ... ok +test reference::tests::execute_status_returns_versions_list ... ok +test reference::tests::execute_view_rejects_parent_traversal_via_dispatcher ... ok +test reference::tests::execute_view_requires_path_param ... ok +test reference::tests::execute_view_via_dispatcher_returns_lines ... ok +test reference::tests::extract_token_at_cursor_handles_edge_cases ... ok +test reference::tests::extract_token_at_cursor_handles_escaped_quote_in_string ... ok +test reference::tests::extract_token_at_cursor_returns_ident_after_closed_string ... ok +test reference::tests::extract_token_at_cursor_skips_line_comment ... ok +test reference::tests::extract_token_at_cursor_skips_string_literal ... ok +test reference::tests::fetch_resolves_project_and_explicit_refs_and_records_actual_commit ... ok +test reference::tests::legacy_metadata_keeps_unknown_match_instead_of_claiming_exact ... ok +test reference::tests::maybe_execute_returns_none_for_unknown_tool ... ok +test reference::tests::now_unix_seconds_string_is_decimal ... ok +test reference::tests::resolve_version_falls_back_to_project_detection ... ok +test reference::tests::resolve_version_uses_explicit_param ... ok +test reference::version::tests::ambiguous_auto_candidates_and_unknown_versions_return_candidates ... ok +test reference::version::tests::detect_returns_error_when_editor_version_line_absent ... ok +test reference::version::tests::detect_returns_error_when_editor_version_value_empty ... ok +test reference::version::tests::detect_returns_error_when_project_version_missing ... ok +test reference::version::tests::exact_tag_precedes_minor_but_version_named_head_is_not_exact ... ok +test reference::version::tests::explicit_ref_has_priority_and_ambiguous_short_names_require_full_ref ... ok +test reference::version::tests::minor_version_key_rejects_invalid_inputs ... ok +test reference::version::tests::parse_editor_version_returns_value_directly ... ok +test reference::version::tests::parses_remote_refs_with_peeled_tag_commits_in_any_order ... ok +test reference::version::tests::public_resolver_handles_previously_supported_minors ... ok +test reference::version::tests::reads_known_project_version ... ok +test reference::version::tests::reads_unknown_minor_without_static_mapping ... ok +test reference::version::tests::selects_new_and_existing_minor_branches_without_claiming_exact_match ... ok +test skills::loader::tests::load_skills_handles_missing_root_and_skips_non_skill_entries ... ok +test skills::loader::tests::load_skills_supports_single_skill_root_and_dir_name_fallback ... ok +test skills::loader::tests::parse_frontmatter_and_collect_references_cover_optional_branches ... ok +test skills::loader::tests::parse_frontmatter_extracts_metadata ... ok +test skills::loader::tests::split_frontmatter_and_parse_frontmatter_cover_edge_cases ... ok +test skills::loader::tests::split_frontmatter_handles_basic_skill ... ok +test skills::tests::good_skill_passes_all_rules ... ok +test skills::tests::model_helpers_cover_skill_accessors_and_tool_sets ... ok +test skills::tests::r01_missing_description_fires ... ok +test skills::tests::r01_missing_multiple_required_fields_fire ... ok +test skills::tests::r02_name_mismatch_fires ... ok +test skills::tests::r03_disallowed_tool_fires ... ok +test skills::tests::r03_legacy_bare_bash_fires ... ok +test skills::tests::r04_unknown_category_fires ... ok +test skills::tests::r05_empty_and_duplicate_triggers_fire ... ok +test skills::tests::r05_uppercase_trigger_fires ... ok +test skills::tests::r06_unknown_sibling_fires ... ok +test skills::tests::r07_too_long_description_fires ... ok +test skills::tests::r08_missing_front_trigger_fires ... ok +test skills::tests::r09_first_person_fires ... ok +test skills::tests::r10_missing_use_when_fires ... ok +test skills::tests::r11_missing_sibling_mention_fires ... ok +test skills::tests::r12_unidirectional_sibling_fires ... ok +test skills::tests::r13_too_long_body_fires ... ok +test skills::tests::r14_missing_heading_fires ... ok +test skills::tests::r15_references_without_link_fires ... ok +test skills::tests::r16_time_sensitive_phrase_fires ... ok +test skills::tests::r17_missing_runtime_checklist_fires ... ok +test skills::tests::r18_long_reference_without_toc_fires ... ok +test skills::tests::r19_reference_link_to_reference_fires ... ok +test skills::tests::r22_collision_without_cross_listing_fires ... ok +test skills::tests::report_and_runner_cover_text_json_discovery_and_error_paths ... ok +test test_env::isolated_runtime_restores_inherited_environment_after_unwind ... ok +test tooling::discovery::tests::bridge_reserved_names_match_the_cli_catalog_including_local_tools ... ok +test tooling::discovery::tests::builtin_descriptors_keep_schemas_and_mark_their_source ... ok +test tooling::discovery::tests::custom_descriptor_roundtrips_owned_names_and_schema ... ok +test tooling::discovery::tests::list_tools_is_a_read_only_remote_builtin ... ok +test tooling::local_tools::tests::build_index_and_find_symbol_roundtrip ... ok +test tooling::local_tools::tests::collect_cs_files_and_index_helpers_cover_readiness_branches ... ok +test tooling::local_tools::tests::create_class_generates_simple_class ... ok +test tooling::local_tools::tests::create_class_rejects_existing_file ... ok +test tooling::local_tools::tests::create_class_rejects_invalid_name ... ok +test tooling::local_tools::tests::create_class_with_namespace_and_inherits ... ok +test tooling::local_tools::tests::default_runtime_config_falls_back_to_ipv4_loopback ... ok +test tooling::local_tools::tests::extract_symbols_from_text_covers_major_symbol_kinds ... ok +test tooling::local_tools::tests::find_refs_supports_cursor_paging ... ok +test tooling::local_tools::tests::find_symbol_returns_index_not_ready_before_build ... ok +test tooling::local_tools::tests::get_symbols_extracts_class_and_method ... ok +test tooling::local_tools::tests::helper_comment_and_snippet_processing_works ... ok +test tooling::local_tools::tests::helper_path_normalization_and_resolution_cover_edge_cases ... ok +test tooling::local_tools::tests::helper_symbol_and_scope_predicates_work ... ok +test tooling::local_tools::tests::list_packages_lists_package_dirs ... ok +test tooling::local_tools::tests::lsp_write_tools_require_lsp_mode ... ok +test tooling::local_tools::tests::post_write_refresh_failure_preserves_applied_files_without_runtime_panic ... ok +test tooling::local_tools::tests::read_returns_file_slice ... ok +test tooling::local_tools::tests::requires_unityengine_using_only_for_monobehaviour ... ok +test tooling::local_tools::tests::search_finds_matching_lines ... ok +test tooling::local_tools::tests::update_index_refreshes_symbol_names ... ok +test tooling::os_capture::tests::capture_fails_when_no_candidate_exists ... ok +test tooling::os_capture::tests::detects_daemon_stringified_timeouts ... ok +test tooling::os_capture::tests::disabled_fallback_returns_the_timeout_error ... ok +test tooling::os_capture::tests::failed_os_capture_keeps_both_errors ... ok +test tooling::os_capture::tests::fallback_flag_defaults_on_and_is_stripped ... ok +test tooling::os_capture::tests::non_timeout_errors_are_not_recovered ... ok +test tooling::os_capture::tests::output_path_follows_bridge_capture_directory ... ok +test tooling::os_capture::tests::timeout_is_recovered_with_os_fallback_marker ... ok +test tooling::os_capture::tests::verbatim_prefix_is_dropped_before_the_path_reaches_os_tools ... ok +test tooling::tool_catalog::tests::action_enum_schemas_use_composite_variants ... ok +test tooling::tool_catalog::tests::addressables_analyze_schema_uses_action_specific_variants ... ok +test tooling::tool_catalog::tests::addressables_manage_schema_has_manage_actions ... ok +test tooling::tool_catalog::tests::all_tools_e2e_covers_catalog_or_documents_exclusion ... ok +test tooling::tool_catalog::tests::analyze_asset_dependencies_schema_has_expected_actions ... ok +test tooling::tool_catalog::tests::animation_curve_tools_advertise_strict_unity_contracts ... ok +test tooling::tool_catalog::tests::baking_tools_have_explicit_target_and_polling_contracts ... ok +test tooling::tool_catalog::tests::build_index_schema_allows_output_path ... ok +test tooling::tool_catalog::tests::build_player_schema_requires_explicit_safe_build_inputs ... ok +test tooling::tool_catalog::tests::capture_video_start_schema_restricts_mode_and_format ... ok +test tooling::tool_catalog::tests::clear_logs_schema_is_strict_empty_object ... ok +test tooling::tool_catalog::tests::create_animation_clip_schema_requires_clip_and_sprite_paths ... ok +test tooling::tool_catalog::tests::create_animator_controller_schema_is_strict_and_nested ... ok +test tooling::tool_catalog::tests::create_prefab_schema_allows_template_mode_without_source_object ... ok +test tooling::tool_catalog::tests::create_sprite_atlas_schema_is_strict_and_nested ... ok +test tooling::tool_catalog::tests::csharp_file_write_schemas_are_local_and_strict ... ok +test tooling::tool_catalog::tests::delete_gameobject_schema_uses_any_of_targets ... ok +test tooling::tool_catalog::tests::execute_menu_item_schema_supports_default_and_action_variants ... ok +test tooling::tool_catalog::tests::get_build_status_is_read_only_and_requires_build_id ... ok +test tooling::tool_catalog::tests::get_gameobject_details_schema_uses_any_of_identifiers ... ok +test tooling::tool_catalog::tests::get_index_status_schema_is_strict_empty_object ... ok +test tooling::tool_catalog::tests::hot_reload_tools_expose_explicit_preview_and_recovery_contract ... ok +test tooling::tool_catalog::tests::input_keyboard_schema_uses_any_of_for_action_or_actions ... ok +test tooling::tool_catalog::tests::known_tool_lookup_works ... ok +test tooling::tool_catalog::tests::load_scene_schema_uses_one_of_identifier_variants ... ok +test tooling::tool_catalog::tests::local_executor_tools_are_marked ... ok +test tooling::tool_catalog::tests::manage_asset_database_schema_uses_action_specific_variants ... ok +test tooling::tool_catalog::tests::manage_layers_schema_requires_action_enum ... ok +test tooling::tool_catalog::tests::modify_gameobject_schema_requires_path ... ok +test tooling::tool_catalog::tests::package_manager_schema_has_required_action ... ok +test tooling::tool_catalog::tests::ping_schema_is_strict_object ... ok +test tooling::tool_catalog::tests::prefab_override_tools_have_strict_discoverable_schemas ... ok +test tooling::tool_catalog::tests::quit_editor_exposes_optional_scene_protection_parameter ... ok +test tooling::tool_catalog::tests::remote_tools_have_unity_bridge_dispatch_cases ... ok +test tooling::tool_catalog::tests::rename_symbol_schema_is_strict_and_requires_name_path ... ok +test tooling::tool_catalog::tests::run_tests_schema_allows_test_mode_enum ... ok +test tooling::tool_catalog::tests::set_component_field_schema_requires_component_and_field ... ok +test tooling::tool_catalog::tests::timeline_schema_exposes_actions_and_stale_clip_guard ... ok +test tooling::tool_catalog::tests::timeline_tools_are_discoverable_with_correct_mutation_flags ... ok +test tooling::tool_catalog::tests::tool_catalog_avoids_default_params_schema_for_known_tools ... ok +test tooling::tool_catalog::tests::tool_catalog_keeps_manifest_parity_count ... ok +test tooling::tool_catalog::tests::tool_specs_cover_catalog ... ok +test tooling::tool_catalog::tests::tools_doc_matches_registered_catalog ... ok +test tooling::tool_catalog::tests::vfx_apply_is_mutating_and_requires_op ... ok +test tooling::tool_catalog::tests::vfx_describe_graph_is_read_only_and_requires_asset_path ... ok +test tooling::tool_catalog::tests::vfx_runtime_is_mutating_and_requires_op_and_game_object ... ok +test tooling::tool_catalog::tests::vfx_settings_is_mutating_and_requires_op ... ok +test tooling::tool_index::tests::category_accepts_heading_or_slug ... ok +test tooling::tool_index::tests::every_tool_has_exactly_one_index_entry_with_a_short_summary ... ok +test tooling::tool_index::tests::query_matches_name_or_summary_case_insensitively ... ok +test tooling::tool_index::tests::tool_index_matches_docs_headings ... ok +test tooling::tool_index::tests::unknown_category_lists_valid_slugs ... ok +test unity::auth::tests::credentials_are_endpoint_scoped_and_absent_from_discovery_output ... ok +test unity::auth::tests::explicit_mounted_lockfile_and_invalid_file_errors_do_not_expose_token ... ok +test unity::auth::tests::only_exact_one_enables_legacy_opt_out ... ok +test unity::transport::tests::call_tool_returns_error_on_failure_response ... ok +test unity::transport::tests::call_tool_returns_result_on_success ... ok +test unity::transport::tests::call_tool_with_timing_reports_non_negative_durations ... ok +test unity::transport::tests::every_request_carries_token_from_private_lockfile ... ok +test unity::transport::tests::normalize_failure_preserves_complete_error_envelope ... ok +test unity::transport::tests::normalize_response_handles_success_and_error_shapes ... ok +test unity::transport::tests::parse_embedded_json_keeps_plain_strings ... ok +test unity::transport::tests::parse_json_accepts_trimmed_json ... ok +test unity::transport::tests::parse_json_rejects_empty_and_non_utf8_payload ... ok +test unity::transport::tests::ping_backfills_bridge_version_from_editor_state_envelope ... ok + +test result: ok. 554 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 41.15s + + Running tests\auth_warning.rs (target\debug\deps\auth_warning-fcf05279c683382e.exe) + +running 1 test +test legacy_opt_out_warns_on_stderr_only_for_exact_one ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.82s + + Running tests\bridge_package_dependencies.rs (target\debug\deps\bridge_package_dependencies-ca7aa8976d9aff95.exe) + +running 1 test +test bridge_declares_ugui_when_sources_use_it ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s + + Running tests\build_failure_output.rs (target\debug\deps\build_failure_output-072d26c38af5069a.exe) + +running 1 test +test failed_build_status_keeps_json_report_and_nonzero_exit ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.42s + + Running tests\ci_tests.rs (target\debug\deps\ci_tests-3334446bbab2c8fb.exe) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests\csharp_post_write.rs (target\debug\deps\csharp_post_write-0cbd1abd0894dff0.exe) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests\custom_tools.rs (target\debug\deps\custom_tools-5d4f508f07ac9ebf.exe) + +running 10 tests +test batch_validates_all_custom_arguments_before_any_side_effect ... ok +test custom_method_is_not_retried_after_lost_response ... ok +test custom_numeric_ranges_and_nullable_defaults_are_validated_before_execution ... ok +test discovery_merges_schemas_and_sources_and_filters_custom_tools ... ok +test discovery_rejects_conflicting_or_malformed_editor_catalogs ... ok +test dry_run_and_unknown_tools_never_invoke_a_custom_method ... ok +test invalid_custom_arguments_never_reach_the_method ... ok +test names_only_and_compact_preserve_small_list_shapes ... ok +test old_bridges_keep_the_builtin_catalog_but_auth_errors_are_visible ... ok +test schema_and_all_call_spellings_support_custom_names ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.16s + + Running tests\editor_lifecycle.rs (target\debug\deps\editor_lifecycle-aeb0970475380a52.exe) + +running 4 tests +test close_requires_bridge_scene_protection_before_sending_quit ... ok +test editor_lifecycle_commands_are_available ... ok +test missing_editor_explains_official_install_and_returns_precondition ... ok +test status_reports_compilation_from_the_selected_project ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.11s + + Running tests\install_script.rs (target\debug\deps\install_script-b6d8d13afae90fa0.exe) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests\json_envelope.rs (target\debug\deps\json_envelope-12e7edbd882a2b08.exe) + +running 15 tests +test batch_with_failed_operation_does_not_exit_zero ... ok +test bridge_errors_preserve_codes_and_authentication_exit ... ok +test bridge_warnings_reach_the_public_envelope ... ok +test clap_usage_error_has_json_envelope ... ok +test direct_authentication_and_bridge_failures_match_daemon ... ok +test invalid_batch_is_usage_error ... ok +test invalid_json_is_usage_error ... ok +test invalid_port_list_is_usage_error ... ok +test invalid_tool_routes_are_usage_errors ... ok +test local_success_uses_single_envelope ... ok +test nested_bridge_failure_is_not_reported_as_success ... ok +test response_timeout_is_retryable_operation_failure ... ok +test skills_show_and_lint_use_envelopes ... FAILED +test test_completion_distinguishes_failed_and_passed ... ok +test unreachable_editor_is_exit_seven ... ok + +failures: + +---- skills_show_and_lint_use_envelopes stdout ---- + +thread 'skills_show_and_lint_use_envelopes' (50576) panicked at tests\json_envelope.rs:37:5: +assertion `left == right` failed: stderr= + left: Some(1) + right: Some(0) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + +failures: + skills_show_and_lint_use_envelopes + +test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.87s + +error: test failed, to rerun pass `--test json_envelope` + Running tests\mcp.rs (target\debug\deps\mcp-86a7609ca7ad34e1.exe) + +running 3 tests +test configure_all_clients_preserves_other_servers_and_dry_run ... ok +test malformed_requests_do_not_end_session_or_execute_tools_before_initialization ... ok +test stdio_catalog_and_failure_contract_without_editor ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.51s + + Running tests\mcp_dynamic.rs (target\debug\deps\mcp_dynamic-499b85548652bf36.exe) + +running 1 test +test custom_catalog_calls_and_live_removal_share_cli_discovery_and_validation ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.11s + + Running tests\setup_dry_run.rs (target\debug\deps\setup_dry_run-e3a3263aee254c2d.exe) + +running 2 tests +test setup_dry_run_prints_plan_without_connections_writes_or_launches ... ok +test setup_launch_returns_output_while_editor_is_still_running ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.86s + + Running tests\skills_install.rs (target\debug\deps\skills_install-e3670c19589ccb8a.exe) + +running 7 tests +test all_clients_install_embedded_references_and_show_works_outside_repository ... ok +test dry_run_prints_only_paths_without_creating_files ... ok +test global_dry_run_flag_also_prevents_installation ... ok +test install_protects_unowned_directory_and_force_keeps_unrelated_files ... ok +test invalid_ledger_paths_are_rejected_even_with_force ... ok +test refresh_does_not_install_clients_without_a_ledger ... ok +test refresh_syncs_an_older_owned_version_and_protects_local_edits ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.89s + + Running tests\tool_list_filters.rs (target\debug\deps\tool_list_filters-71cf420645a1f348.exe) + +running 7 tests +test category_returns_only_that_docs_section ... ok +test compact_is_name_and_description_only_and_at_most_half_of_full_catalog ... ok +test limit_and_offset_page_the_filtered_list ... ok +test offline_default_list_has_schemas_and_names_only_is_compatible ... ok +test query_returns_only_matching_tools ... ok +test unknown_category_is_rejected ... ok +test unopened_project_still_exposes_the_offline_builtin_catalog ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.35s + + Running tests\unityd_autostart.rs (target\debug\deps\unityd_autostart-c58b98ce6bcf74d1.exe) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +error: 1 target failed: + `--test json_envelope` diff --git a/docs/verification/issue-386/cargo-test-inventory.json b/docs/verification/issue-386/cargo-test-inventory.json new file mode 100644 index 00000000..4b65d119 --- /dev/null +++ b/docs/verification/issue-386/cargo-test-inventory.json @@ -0,0 +1,3039 @@ +{ + "counts": { + "PASS": 605, + "FAIL": 1, + "SKIP": 0 + }, + "tests": [ + { + "suite": "unittests", + "name": "app::editor::tests::editor_launch_uses_paths_supported_by_unity", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::ambiguous_editor_fails_before_contacting_any_editor", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::animation_curve_edits_accept_operations_and_tangent_modes", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::animation_curve_edits_reject_missing_identifiers_and_invalid_nested_fields", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::animation_curve_queries_validate_complete_binding_filters", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::audio_mixer_arguments_are_action_specific", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::augment_command_stats_inserts_cli_snapshot", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::baking_invalid_target_missing_scene_and_missing_job_are_rejected", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::baking_surface_requires_path_before_contacting_editor", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::baking_valid_targets_and_polling_are_accepted", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::bridge_commands_resolve_explicit_project_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_clean_defaults", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_clean_with_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_diff_path_mode_with_limit", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_diff_symbol_mode", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_embed_build_includes_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_embed_build_omits_optional_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_embed_search_omits_optional_top_k", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_embed_search_with_top_k", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_fetch_carries_all_flags", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_fetch_defaults_without_overrides", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_find_symbol_minimal", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_find_symbol_with_filters", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_grep_defaults_context_to_zero", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_grep_with_file_glob_and_context", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_resolve_symbol_at_minimal", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_resolve_symbol_at_with_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_search_minimal_pattern", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_search_with_all_options", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_status_includes_explicit_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_status_omits_optional_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_view_omits_optional_lines", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::build_reference_call_view_with_range", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::capture_screenshot_timeout_respects_os_fallback_flag", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::env_var_guard_restores_previous_value", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::eval_cli_accepts_code_and_rejects_invalid_mode", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::eval_dry_run_does_not_execute_arbitrary_code", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::eval_schemas_require_code_and_status_id", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::eval_transport_error_keeps_generated_request_id", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::execute_tool_skips_mutating_tool_in_dry_run_mode", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::hot_reload_requires_revision_and_explicit_action", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::init_tracing_accepts_verbose_levels", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::instances_list_defaults_host_to_ipv4_loopback", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::load_params_defaults_to_empty_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::load_params_reads_inline_json", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::load_params_reads_json_from_file", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::load_params_rejects_when_json_and_params_file_are_both_set", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_external_tool_command_accepts_json_flag", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_external_tool_command_rejects_unknown_flag", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_external_tool_command_requires_tool_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_external_tool_command_requires_values_for_flags", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_external_tool_command_supports_equals_forms", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_json_object_accepts_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_json_object_rejects_non_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_ports_deduplicates_values", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_ports_rejects_invalid_values", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_ports_returns_empty_for_none", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::parse_ports_with_diagnostics_reports_duplicate_values", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::ping_version_check_reports_mismatch_and_unknown", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::prefab_override_validation_requires_explicit_scope_and_apply_target", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::print_value_text_handles_string_and_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::project_path_flag_is_global_and_feeds_runtime_overrides", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::run_with_cli_batch_marks_skipped_items_in_dry_run_mode", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::run_with_cli_exercises_remote_command_error_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::run_with_cli_handles_instances_and_daemon_commands_without_server", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::run_with_cli_handles_local_tool_and_batch_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::run_with_cli_rejects_unknown_external_tool", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::run_with_cli_requires_batch_input_source", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::run_with_cli_set_active_text_output_when_reachable", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::run_with_cli_supports_tool_schema_command", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::runtime_overrides_are_derived_from_cli_at_app_boundary", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::setup_and_bridge_cli_arguments_parse", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::timeline_manage_is_skipped_in_dry_run", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::timeline_validation_requires_target_and_valid_action", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_add_component_payload", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_addressables_manage_add_entry", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_analyze_asset_dependencies_get_dependencies", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_build_index_output_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_create_animation_clip_payload", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_create_animator_controller_payload", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_create_gameobject_with_vector_fields", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_create_sprite_atlas_payload", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_delete_gameobject_with_path_and_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_execute_menu_item_get_available_menus", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_execute_menu_item_without_action", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_get_input_actions_state_with_asset_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_input_keyboard_batch_actions", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_load_scene_by_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_lsp_write_payload_with_path_alias", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_manage_layers_get_by_index", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_package_manager_list_action", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_profiler_start_payload", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_valid_payload", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_accepts_write_csharp_file_payload", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_addressables_analyze_dependencies_without_asset_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_addressables_manage_move_entry_without_target_group", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_analyze_asset_dependencies_get_dependencies_without_asset_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_analyze_asset_dependencies_invalid_action", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_analyze_screenshot_without_source", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_create_animation_clip_without_sprite_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_create_package_setting_without_value", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_delete_gameobject_without_target", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_execute_menu_item_without_action_or_menu_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_execute_menu_item_without_menu_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_invalid_animator_condition_mode", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_invalid_sprite_atlas_filter_mode", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_load_scene_with_both_identifiers", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_manage_asset_database_move_without_to_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_manage_layers_add_without_layer_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_manage_layers_invalid_action", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_manage_selection_set_without_object_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_manage_tools_activate_without_tool_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_manage_windows_focus_without_window_type", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_missing_required_property", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_package_manager_search_without_keyword", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_registry_config_add_scope_without_scope", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_remove_input_binding_without_selector", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_set_component_field_missing_required", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_unknown_field_for_clear_logs", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_unknown_property_when_schema_is_strict", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::runner::tests::validate_tool_params_rejects_unknown_run_tests_property", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::setup::tests::hub_paths_for_windows_and_linux_do_not_depend_on_test_host", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::setup::tests::launch_editor_skips_when_project_is_locked_and_errors_without_editor", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::setup::tests::project_unity_version_and_hub_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::setup::tests::setup_dry_run_leaves_editor_unchecked_and_skips_writes", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::setup::tests::setup_flags_editor_serving_another_project", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::setup::tests::setup_installs_bridge_and_confirms_matching_editor", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::setup::tests::setup_reports_version_mismatch_as_json", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::setup::tests::setup_without_dry_run_reports_unreachable_editor", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::test_report::tests::github_annotations_extract_unity_location_and_escape_injection", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::test_report::tests::junit_preserves_failed_skipped_and_escaped_details", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::test_report::tests::junit_time_is_millisecond_precision_for_xunit_schema", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::test_report::tests::nunit_nests_test_cases_in_a_suite_and_preserves_details", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::test_report::tests::parent_suite_rollups_do_not_duplicate_leaf_failures", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "app::test_report::tests::suite_failure_is_reported_even_without_failed_leaves", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "cli::test_command_tests::test_command_accepts_report_output_without_changing_global_output", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::dry_run_reports_change_without_writing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::embedded_package_is_reported_and_not_duplicated", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::input_backends_untouched_when_setting_absent_or_already_enabled", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::install_adds_openupm_registry_and_cli_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::install_adds_scope_to_existing_openupm_registry", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::install_enables_input_system_backends_while_editor_is_closed", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::install_is_noop_when_already_configured_by_hand", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::install_keeps_other_version_and_upgrade_pins_cli_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::install_leaves_input_backends_when_editor_is_open_or_dry_run", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::install_twice_leaves_manifest_byte_identical", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::rejects_malformed_manifest", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::resolve_project_root_walks_up_and_validates_explicit_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::status_prefers_lock_resolution_and_reports_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::upgrade_leaves_custom_sources_alone", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::bridge::tests::version_check_classifies_versions", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::command_stats::tests::snapshot_groups_calls_by_tool_and_route", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::default_host_returns_ipv4_loopback_without_env", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::default_port_returns_6400_without_env", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::default_timeout_returns_30000_without_env", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::empty_value_is_ignored", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::execution_context_uses_defaults", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::fails_when_legacy_alias_is_set", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::fails_when_removed_unityd_env_is_set", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::returns_none_when_no_keys_set", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::u16_env_parses_correctly", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::u16_env_rejects_zero", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::u64_env_parses_correctly", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::config::tests::u64_env_rejects_zero", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::classification_priority", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::editor_import_workers_are_not_reusable_editors", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::parses_safe_mode_and_latest_compile_errors", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::reads_bridge_version_from_local_file_dependency", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::reads_project_bridge_port", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::recognizes_editor_command_lines_only", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::reports_editor_not_running", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::reports_port_in_use_with_owner_pid", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::doctor::tests::safe_mode_exit_clears_flag", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::editor_discovery::tests::ambiguous_error_json_lists_candidates", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::editor_discovery::tests::dead_pid_marks_lockfile_stale", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::editor_discovery::tests::discover_reads_lockfiles_and_skips_garbage", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::editor_discovery::tests::expired_heartbeat_marks_lockfile_stale", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::editor_discovery::tests::pid_zero_is_never_alive", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::editor_discovery::tests::select_for_path_ignores_stale_editors_and_sibling_prefixes", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::editor_discovery::tests::select_for_path_prefers_deepest_live_project", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::active_instance_keeps_priority_over_lockfile_discovery", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::cli_override_wins_over_active_instance", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::cwd_inside_project_selects_that_editor", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::cwd_outside_projects_with_two_editors_is_ambiguous", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::env_port_wins_when_no_cli_override", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::explicit_port_wins_over_project_path_and_lockfiles", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::no_lockfiles_keeps_legacy_default", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::project_command_targets_its_own_editor_among_several", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::project_command_without_its_editor_uses_default_endpoint", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::project_path_selects_matching_editor", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::project_path_without_running_editor_is_not_found", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::project_root_env_falls_back_to_default_without_any_lockfile", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::single_running_editor_is_used_from_anywhere", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::stale_editors_do_not_cause_ambiguity", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::endpoint::tests::unity_project_root_env_acts_as_project_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::authenticated_health_checks_support_listing_and_selection", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::list_instances_adds_default_port_when_no_entries_exist", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::list_instances_enumerates_lockfiles_without_ports", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::list_instances_keeps_explicit_ports_next_to_lockfiles", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::list_instances_reports_down_for_tcp_listener_that_is_not_unity_bridge", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::list_instances_reports_up_for_reachable_port", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::load_registry_reconstructs_missing_ids", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::parse_id_validates_shape", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::registry_path_uses_env_and_creates_parent_directory", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::registry_round_trip_serialization_shape_is_supported", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::set_active_fails_for_unreachable_instance", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::instances::tests::set_active_succeeds_for_reachable_instance_and_tracks_previous", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::cache_root_falls_back_to_home_unity_cache", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::cache_root_prefers_unity_cli_cache_root_env", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::detect_rid_returns_known_target_triple", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::download_latest_binary_applies_matching_checksum", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::download_latest_binary_rejects_checksum_mismatch_and_keeps_existing_install", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::ensure_latest_for_can_skip_remote_checks_in_tests", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::ensure_local_uses_existing_binary_without_download", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::get_json_fails_with_status_and_body", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::get_json_parses_http_body", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::get_json_retries_transient_server_error", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::get_optional_text_returns_body_for_success", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::get_optional_text_returns_none_for_not_found", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::get_response_includes_authorization_header", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::get_response_reports_http_status_errors", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::parse_sha256sums_reads_text_and_binary_mode_entries", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::read_local_version_returns_none_for_missing_or_blank_file", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::replace_file_atomic_overwrites_destination", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::sha256_file_matches_known_hash", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::tools_root_falls_back_to_home_unity_tools_when_env_unset", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::tools_root_prefers_unity_cli_tools_root_env", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::unity_cli_status_uses_managed_install_layout", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::verify_manifest_against_checksums_requires_matching_entry", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::managed_binaries::tests::write_and_read_local_version_round_trip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::runtime_paths::tests::daemon_dir_is_under_run_root", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::self_update::tests::is_recent_returns_false_for_missing_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::self_update::tests::is_recent_returns_true_for_freshly_touched_file", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::self_update::tests::last_check_path_uses_unity_cli_tools_root_env", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::self_update::tests::maybe_self_update_skipped_when_opt_out_env_set", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::self_update::tests::maybe_self_update_skips_when_recent_check_exists", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::self_update::tests::touch_creates_parent_and_writes_marker", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "core::self_update::tests::warn_cargo_conflict_runs_without_panic", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::runtime::tests::runtime_module_builds_without_warnings_when_unix_code_is_disabled", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::spawn::tests::spawn_detached_starts_the_command", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::spawn::tests::spawn_module_builds_for_windows_without_warnings", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::spawn::tests::spawned_child_does_not_hold_the_callers_stdout_pipe", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_call_error_classification", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_request_batch_round_trip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_request_ping_round_trip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_request_status_round_trip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_request_stop_round_trip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_request_tool_round_trip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_response_error_round_trip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_response_round_trip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::daemon_response_round_trip_preserves_timing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::idle_timeout_default", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::pid_file_path_is_under_tools_dir", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::pooled_connection_closed_by_editor_restart_is_reconnected_before_sending", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::pooled_connection_uses_each_requests_timeout", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::request_lost_after_sending_is_reported_and_not_resent", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::startup_lock_times_out_and_is_reusable_after_release", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "daemon::unityd::tests::tools_dir_creates_directory", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::collect_document_symbols_flattens_nested_symbols", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::get_apply_defaults_to_false", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::id_matches_accepts_number_and_string_id", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::kind_from_lsp_maps_known_values", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::normalize_lsp_write_result_adds_contract_fields", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::normalize_rel_path_accepts_assets_packages_and_library", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::normalize_rel_path_extracts_supported_prefix_from_absolute_like_input", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::normalize_rel_path_rejects_parent_traversal", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::path_matches_scope_filters_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::remove_symbol_request_includes_fail_on_references_when_set", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::remove_symbol_request_omits_fail_on_references_when_unset", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::require_helpers_validate_expected_fields", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::retryable_session_error_detects_transport_failures", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::retryable_session_error_ignores_argument_errors", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::to_project_relative_or_raw_returns_relative_for_absolute_under_root", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::uri_and_ref_path_helpers_resolve_project_relative_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::client::tests::uri_to_rel_path_rejects_non_file_uris", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::daemon::tests::daemon_idle_timeout_uses_env_override", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::daemon::tests::handle_request_handles_ping_status_and_stop", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::daemon::tests::is_would_block_checks_error_kind", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::daemon::tests::write_all_with_retry_handles_would_block_and_partial_writes", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::daemon::tests::write_all_with_retry_rejects_zero_byte_progress", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "lsp::daemon::tests::write_pid_file_and_cleanup_manage_files_under_tools_root", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "mcp::configure::tests::custom_root_may_have_missing_ancestors_without_creating_them", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "mcp::configure::tests::invalid_config_is_never_overwritten_and_preview_creates_nothing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "mcp::configure::tests::malformed_shapes_and_http_name_collisions_are_rejected", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "mcp::configure::tests::merges_inline_toml_without_losing_other_servers_or_options", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "mcp::configure::tests::windows_and_local_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "mcp::tests::projects_owned_custom_descriptor_without_an_mcp_specific_schema", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::gc_empty_root_returns_empty", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::gc_keep_zero_removes_all_versions", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::gc_keeps_n_newest_and_returns_removed", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::gc_skips_non_directory_entries", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::list_versions_empty_when_root_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::list_versions_returns_existing_dirs", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::list_versions_skips_files_in_root", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::meta_roundtrip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::read_meta_returns_error_for_invalid_json", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::read_meta_returns_error_when_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::version_dir_rejects_empty", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::version_dir_rejects_paths_outside_single_cache_entry", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::cache::tests::version_dir_under_cache_root", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_line_diff_empty_for_identical_lines", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_line_diff_for_deletes_only_returns_removal_hunk", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_line_diff_for_inserts_only_returns_addition_hunk", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_line_diff_for_separate_changes_produces_multiple_hunks", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_line_diff_replacement_isolates_changed_lines", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_path_diff_can_be_truncated", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_path_diff_categorises_runtime_export", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_symbol_diff_detects_changed_animator", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_symbol_diff_returns_diff_when_only_one_side_has_symbol", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::compute_symbol_diff_returns_none_for_missing_in_both", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::ensure_cache_dir_errors_on_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::diff::tests::split_fqn_separates_namespace_and_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::build_embedding_index_handles_empty_symbol_index", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::build_embedding_index_with_mock_embedder", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::cosine_similarity_handles_zero_vectors", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::embedding_roundtrip_via_bincode", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::resolve_onnxruntime_dylib_explains_how_to_install_when_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::resolve_onnxruntime_dylib_falls_back_to_first_existing_candidate", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::resolve_onnxruntime_dylib_prefers_existing_env_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::resolve_onnxruntime_dylib_rejects_missing_env_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::search_ranks_by_cosine_similarity", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::search_returns_empty_for_empty_index", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::search_returns_empty_for_empty_query", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::symbol_to_text_includes_namespace_and_kind", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::embed::tests::symbol_to_text_without_namespace_omits_dot", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::api_discovery_paginates_branches_and_includes_tags", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::api_discovery_surfaces_http_errors", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::archive_url_uses_unity_cs_reference_org", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::build_clone_args_emits_shallow_single_branch", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::ensure_git_available_succeeds_in_test_env", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::extract_zip_to_rejects_entries_with_parent_segments", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::extract_zip_to_strips_top_level_prefix_and_writes_files", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::fetch_selected_pins_commit_after_branch_advances", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::fetch_selected_rejects_invalid_commit_before_creating_destination", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::github_token_returns_none_when_env_unset", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::github_token_skips_empty_and_picks_first_non_empty", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::license_ok_when_env_set", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::license_ok_when_flag_true", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::license_rejects_zero_value", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::license_required_when_flag_false_and_env_unset", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::list_public_refs_discovers_branches_and_tags", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::list_public_refs_preserves_transport_error", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::fetcher::tests::run_clone_rejects_when_license_not_accepted", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::build_or_update_index_handles_existing_fixture", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::build_or_update_index_persists_signature", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::build_or_update_index_skips_already_indexed_files_until_change", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::extract_symbols_from_text_captures_namespace", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::extract_symbols_from_text_does_not_double_capture_class_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::extract_symbols_from_text_finds_class", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::extract_symbols_from_text_finds_methods", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::extract_symbols_from_text_finds_property", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::extract_symbols_from_text_finds_struct_and_interface", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::file_signature_changes_when_content_changes", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::find_symbol_filters_by_kind_and_namespace", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::index::tests::validate_kind_accepts_known_and_rejects_unknown", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::search::tests::grep_filters_by_filename_glob", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::search::tests::grep_finds_class_animator_with_line_numbers", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::search::tests::grep_returns_context_lines", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::search::tests::view_rejects_parent_traversal", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::search::tests::view_returns_requested_line_range", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::cached_fetch_and_status_report_stored_provenance", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::cached_unknown_version_can_be_used_without_branch_resolution", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::dir_size_empty_returns_zero", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::dir_size_sums_file_lengths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_clean_dry_run_false_actually_removes", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_clean_dry_run_on_empty_cache_returns_empty_removed", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_diff_errors_when_cache_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_diff_path_mode_returns_added_removed_changed", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_diff_requires_from_and_to", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_diff_requires_symbol_or_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_diff_symbol_mode_returns_diffs", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_embed_build_errors_when_cache_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_embed_search_errors_when_index_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_embed_search_requires_query", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_fetch_force_preserves_existing_on_transport_failure", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_fetch_skips_when_destination_exists_without_force", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_find_symbol_empty_hits_for_unknown_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_find_symbol_filters_namespace", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_find_symbol_rejects_unknown_kind", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_find_symbol_requires_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_find_symbol_returns_error_when_cache_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_find_symbol_returns_hits_from_fixture", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_grep_invalid_regex_returns_error", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_grep_requires_pattern", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_grep_supports_file_glob_filter", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_grep_via_dispatcher_returns_hits", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_resolve_symbol_at_empty_token_for_blank_position", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_resolve_symbol_at_finds_token_via_fixture", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_resolve_symbol_at_requires_path_line_column", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_resolve_symbol_at_requires_project_prefix", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_search_requires_pattern", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_search_via_dispatcher_truncates_max_results", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_search_without_max_results_returns_all_hits", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_status_includes_size_bytes", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_status_returns_versions_list", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_view_rejects_parent_traversal_via_dispatcher", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_view_requires_path_param", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::execute_view_via_dispatcher_returns_lines", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::extract_token_at_cursor_handles_edge_cases", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::extract_token_at_cursor_handles_escaped_quote_in_string", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::extract_token_at_cursor_returns_ident_after_closed_string", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::extract_token_at_cursor_skips_line_comment", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::extract_token_at_cursor_skips_string_literal", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::fetch_resolves_project_and_explicit_refs_and_records_actual_commit", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::legacy_metadata_keeps_unknown_match_instead_of_claiming_exact", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::maybe_execute_returns_none_for_unknown_tool", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::now_unix_seconds_string_is_decimal", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::resolve_version_falls_back_to_project_detection", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::tests::resolve_version_uses_explicit_param", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::ambiguous_auto_candidates_and_unknown_versions_return_candidates", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::detect_returns_error_when_editor_version_line_absent", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::detect_returns_error_when_editor_version_value_empty", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::detect_returns_error_when_project_version_missing", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::exact_tag_precedes_minor_but_version_named_head_is_not_exact", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::explicit_ref_has_priority_and_ambiguous_short_names_require_full_ref", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::minor_version_key_rejects_invalid_inputs", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::parse_editor_version_returns_value_directly", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::parses_remote_refs_with_peeled_tag_commits_in_any_order", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::public_resolver_handles_previously_supported_minors", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::reads_known_project_version", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::reads_unknown_minor_without_static_mapping", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "reference::version::tests::selects_new_and_existing_minor_branches_without_claiming_exact_match", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::loader::tests::load_skills_handles_missing_root_and_skips_non_skill_entries", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::loader::tests::load_skills_supports_single_skill_root_and_dir_name_fallback", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::loader::tests::parse_frontmatter_and_collect_references_cover_optional_branches", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::loader::tests::parse_frontmatter_extracts_metadata", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::loader::tests::split_frontmatter_and_parse_frontmatter_cover_edge_cases", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::loader::tests::split_frontmatter_handles_basic_skill", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::good_skill_passes_all_rules", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::model_helpers_cover_skill_accessors_and_tool_sets", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r01_missing_description_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r01_missing_multiple_required_fields_fire", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r02_name_mismatch_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r03_disallowed_tool_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r03_legacy_bare_bash_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r04_unknown_category_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r05_empty_and_duplicate_triggers_fire", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r05_uppercase_trigger_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r06_unknown_sibling_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r07_too_long_description_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r08_missing_front_trigger_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r09_first_person_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r10_missing_use_when_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r11_missing_sibling_mention_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r12_unidirectional_sibling_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r13_too_long_body_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r14_missing_heading_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r15_references_without_link_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r16_time_sensitive_phrase_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r17_missing_runtime_checklist_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r18_long_reference_without_toc_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r19_reference_link_to_reference_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::r22_collision_without_cross_listing_fires", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "skills::tests::report_and_runner_cover_text_json_discovery_and_error_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "test_env::isolated_runtime_restores_inherited_environment_after_unwind", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::discovery::tests::bridge_reserved_names_match_the_cli_catalog_including_local_tools", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::discovery::tests::builtin_descriptors_keep_schemas_and_mark_their_source", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::discovery::tests::custom_descriptor_roundtrips_owned_names_and_schema", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::discovery::tests::list_tools_is_a_read_only_remote_builtin", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::build_index_and_find_symbol_roundtrip", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::collect_cs_files_and_index_helpers_cover_readiness_branches", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::create_class_generates_simple_class", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::create_class_rejects_existing_file", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::create_class_rejects_invalid_name", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::create_class_with_namespace_and_inherits", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::default_runtime_config_falls_back_to_ipv4_loopback", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::extract_symbols_from_text_covers_major_symbol_kinds", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::find_refs_supports_cursor_paging", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::find_symbol_returns_index_not_ready_before_build", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::get_symbols_extracts_class_and_method", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::helper_comment_and_snippet_processing_works", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::helper_path_normalization_and_resolution_cover_edge_cases", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::helper_symbol_and_scope_predicates_work", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::list_packages_lists_package_dirs", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::lsp_write_tools_require_lsp_mode", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::post_write_refresh_failure_preserves_applied_files_without_runtime_panic", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::read_returns_file_slice", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::requires_unityengine_using_only_for_monobehaviour", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::search_finds_matching_lines", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::local_tools::tests::update_index_refreshes_symbol_names", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::capture_fails_when_no_candidate_exists", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::detects_daemon_stringified_timeouts", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::disabled_fallback_returns_the_timeout_error", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::failed_os_capture_keeps_both_errors", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::fallback_flag_defaults_on_and_is_stripped", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::non_timeout_errors_are_not_recovered", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::output_path_follows_bridge_capture_directory", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::timeout_is_recovered_with_os_fallback_marker", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::os_capture::tests::verbatim_prefix_is_dropped_before_the_path_reaches_os_tools", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::action_enum_schemas_use_composite_variants", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::addressables_analyze_schema_uses_action_specific_variants", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::addressables_manage_schema_has_manage_actions", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::all_tools_e2e_covers_catalog_or_documents_exclusion", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::analyze_asset_dependencies_schema_has_expected_actions", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::animation_curve_tools_advertise_strict_unity_contracts", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::baking_tools_have_explicit_target_and_polling_contracts", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::build_index_schema_allows_output_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::build_player_schema_requires_explicit_safe_build_inputs", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::capture_video_start_schema_restricts_mode_and_format", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::clear_logs_schema_is_strict_empty_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::create_animation_clip_schema_requires_clip_and_sprite_paths", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::create_animator_controller_schema_is_strict_and_nested", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::create_prefab_schema_allows_template_mode_without_source_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::create_sprite_atlas_schema_is_strict_and_nested", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::csharp_file_write_schemas_are_local_and_strict", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::delete_gameobject_schema_uses_any_of_targets", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::execute_menu_item_schema_supports_default_and_action_variants", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::get_build_status_is_read_only_and_requires_build_id", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::get_gameobject_details_schema_uses_any_of_identifiers", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::get_index_status_schema_is_strict_empty_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::hot_reload_tools_expose_explicit_preview_and_recovery_contract", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::input_keyboard_schema_uses_any_of_for_action_or_actions", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::known_tool_lookup_works", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::load_scene_schema_uses_one_of_identifier_variants", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::local_executor_tools_are_marked", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::manage_asset_database_schema_uses_action_specific_variants", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::manage_layers_schema_requires_action_enum", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::modify_gameobject_schema_requires_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::package_manager_schema_has_required_action", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::ping_schema_is_strict_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::prefab_override_tools_have_strict_discoverable_schemas", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::quit_editor_exposes_optional_scene_protection_parameter", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::remote_tools_have_unity_bridge_dispatch_cases", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::rename_symbol_schema_is_strict_and_requires_name_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::run_tests_schema_allows_test_mode_enum", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::set_component_field_schema_requires_component_and_field", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::timeline_schema_exposes_actions_and_stale_clip_guard", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::timeline_tools_are_discoverable_with_correct_mutation_flags", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::tool_catalog_avoids_default_params_schema_for_known_tools", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::tool_catalog_keeps_manifest_parity_count", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::tool_specs_cover_catalog", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::tools_doc_matches_registered_catalog", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::vfx_apply_is_mutating_and_requires_op", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::vfx_describe_graph_is_read_only_and_requires_asset_path", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::vfx_runtime_is_mutating_and_requires_op_and_game_object", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_catalog::tests::vfx_settings_is_mutating_and_requires_op", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_index::tests::category_accepts_heading_or_slug", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_index::tests::every_tool_has_exactly_one_index_entry_with_a_short_summary", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_index::tests::query_matches_name_or_summary_case_insensitively", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_index::tests::tool_index_matches_docs_headings", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "tooling::tool_index::tests::unknown_category_lists_valid_slugs", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::auth::tests::credentials_are_endpoint_scoped_and_absent_from_discovery_output", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::auth::tests::explicit_mounted_lockfile_and_invalid_file_errors_do_not_expose_token", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::auth::tests::only_exact_one_enables_legacy_opt_out", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::call_tool_returns_error_on_failure_response", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::call_tool_returns_result_on_success", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::call_tool_with_timing_reports_non_negative_durations", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::every_request_carries_token_from_private_lockfile", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::normalize_failure_preserves_complete_error_envelope", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::normalize_response_handles_success_and_error_shapes", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::parse_embedded_json_keeps_plain_strings", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::parse_json_accepts_trimmed_json", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::parse_json_rejects_empty_and_non_utf8_payload", + "status": "PASS" + }, + { + "suite": "unittests", + "name": "unity::transport::tests::ping_backfills_bridge_version_from_editor_state_envelope", + "status": "PASS" + }, + { + "suite": "auth_warning.rs", + "name": "legacy_opt_out_warns_on_stderr_only_for_exact_one", + "status": "PASS" + }, + { + "suite": "bridge_package_dependencies.rs", + "name": "bridge_declares_ugui_when_sources_use_it", + "status": "PASS" + }, + { + "suite": "build_failure_output.rs", + "name": "failed_build_status_keeps_json_report_and_nonzero_exit", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "batch_validates_all_custom_arguments_before_any_side_effect", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "custom_method_is_not_retried_after_lost_response", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "custom_numeric_ranges_and_nullable_defaults_are_validated_before_execution", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "discovery_merges_schemas_and_sources_and_filters_custom_tools", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "discovery_rejects_conflicting_or_malformed_editor_catalogs", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "dry_run_and_unknown_tools_never_invoke_a_custom_method", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "invalid_custom_arguments_never_reach_the_method", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "names_only_and_compact_preserve_small_list_shapes", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "old_bridges_keep_the_builtin_catalog_but_auth_errors_are_visible", + "status": "PASS" + }, + { + "suite": "custom_tools.rs", + "name": "schema_and_all_call_spellings_support_custom_names", + "status": "PASS" + }, + { + "suite": "editor_lifecycle.rs", + "name": "close_requires_bridge_scene_protection_before_sending_quit", + "status": "PASS" + }, + { + "suite": "editor_lifecycle.rs", + "name": "editor_lifecycle_commands_are_available", + "status": "PASS" + }, + { + "suite": "editor_lifecycle.rs", + "name": "missing_editor_explains_official_install_and_returns_precondition", + "status": "PASS" + }, + { + "suite": "editor_lifecycle.rs", + "name": "status_reports_compilation_from_the_selected_project", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "batch_with_failed_operation_does_not_exit_zero", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "bridge_errors_preserve_codes_and_authentication_exit", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "bridge_warnings_reach_the_public_envelope", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "clap_usage_error_has_json_envelope", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "direct_authentication_and_bridge_failures_match_daemon", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "invalid_batch_is_usage_error", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "invalid_json_is_usage_error", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "invalid_port_list_is_usage_error", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "invalid_tool_routes_are_usage_errors", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "local_success_uses_single_envelope", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "nested_bridge_failure_is_not_reported_as_success", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "response_timeout_is_retryable_operation_failure", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "skills_show_and_lint_use_envelopes", + "status": "FAIL" + }, + { + "suite": "json_envelope.rs", + "name": "test_completion_distinguishes_failed_and_passed", + "status": "PASS" + }, + { + "suite": "json_envelope.rs", + "name": "unreachable_editor_is_exit_seven", + "status": "PASS" + }, + { + "suite": "mcp.rs", + "name": "configure_all_clients_preserves_other_servers_and_dry_run", + "status": "PASS" + }, + { + "suite": "mcp.rs", + "name": "malformed_requests_do_not_end_session_or_execute_tools_before_initialization", + "status": "PASS" + }, + { + "suite": "mcp.rs", + "name": "stdio_catalog_and_failure_contract_without_editor", + "status": "PASS" + }, + { + "suite": "mcp_dynamic.rs", + "name": "custom_catalog_calls_and_live_removal_share_cli_discovery_and_validation", + "status": "PASS" + }, + { + "suite": "setup_dry_run.rs", + "name": "setup_dry_run_prints_plan_without_connections_writes_or_launches", + "status": "PASS" + }, + { + "suite": "setup_dry_run.rs", + "name": "setup_launch_returns_output_while_editor_is_still_running", + "status": "PASS" + }, + { + "suite": "skills_install.rs", + "name": "all_clients_install_embedded_references_and_show_works_outside_repository", + "status": "PASS" + }, + { + "suite": "skills_install.rs", + "name": "dry_run_prints_only_paths_without_creating_files", + "status": "PASS" + }, + { + "suite": "skills_install.rs", + "name": "global_dry_run_flag_also_prevents_installation", + "status": "PASS" + }, + { + "suite": "skills_install.rs", + "name": "install_protects_unowned_directory_and_force_keeps_unrelated_files", + "status": "PASS" + }, + { + "suite": "skills_install.rs", + "name": "invalid_ledger_paths_are_rejected_even_with_force", + "status": "PASS" + }, + { + "suite": "skills_install.rs", + "name": "refresh_does_not_install_clients_without_a_ledger", + "status": "PASS" + }, + { + "suite": "skills_install.rs", + "name": "refresh_syncs_an_older_owned_version_and_protects_local_edits", + "status": "PASS" + }, + { + "suite": "tool_list_filters.rs", + "name": "category_returns_only_that_docs_section", + "status": "PASS" + }, + { + "suite": "tool_list_filters.rs", + "name": "compact_is_name_and_description_only_and_at_most_half_of_full_catalog", + "status": "PASS" + }, + { + "suite": "tool_list_filters.rs", + "name": "limit_and_offset_page_the_filtered_list", + "status": "PASS" + }, + { + "suite": "tool_list_filters.rs", + "name": "offline_default_list_has_schemas_and_names_only_is_compatible", + "status": "PASS" + }, + { + "suite": "tool_list_filters.rs", + "name": "query_returns_only_matching_tools", + "status": "PASS" + }, + { + "suite": "tool_list_filters.rs", + "name": "unknown_category_is_rejected", + "status": "PASS" + }, + { + "suite": "tool_list_filters.rs", + "name": "unopened_project_still_exposes_the_offline_builtin_catalog", + "status": "PASS" + } + ] +} diff --git a/docs/verification/issue-386/clippy.txt b/docs/verification/issue-386/clippy.txt new file mode 100644 index 00000000..52b4ece6 --- /dev/null +++ b/docs/verification/issue-386/clippy.txt @@ -0,0 +1,2 @@ + Checking unity-cli v0.18.1 () + Finished `dev` profile [unoptimized + debuginfo] target(s) in 7.97s diff --git a/docs/verification/issue-386/environment-final.json b/docs/verification/issue-386/environment-final.json new file mode 100644 index 00000000..1c1979b5 --- /dev/null +++ b/docs/verification/issue-386/environment-final.json @@ -0,0 +1,19 @@ +{ + "observed_at": "2026-10-03T15:48:32.464333+00:00", + "source_file_sha256": { + "UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/SceneHandler.cs": "3d44351bdbeda87ffb1a432f3ac013e6c86f2709935bbc7462e01e057a3cc2f9", + "UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/SceneHandlerTests.cs": "381ffee4c4341d6ab7442523ff4e4cec82ae3d9fe8d8239de1edfbbb7bda4717", + "src/app/editor.rs": "12ea2e975445003f9f47e5a8b9e62bbf9c5c7be5ca5e1393ef6bfab022c67199", + "src/app/setup.rs": "eab8bdf7cd59500812ac40c9acc104cf5a6c2c35140733e23571583a0829aa1f", + "src/app/test_runner.rs": "f8023e20459795926704614160cbb05b782f1fdc8b32e6c196d7695b38ae5691", + "src/daemon/unityd.rs": "3cbc5499fc3edb1b8ad3422a864e2e64c94a8f2be4f73f98513a4e5df55d629d", + "src/lsp/client.rs": "7c676ee0a967f79f6914140c1e147d29b58100ac5ec4fa41829b32563bbfd838", + "src/lsp/daemon.rs": "581ac8fd1f9df763069df66c0ed17d6507919ee63c52afff9741aa452f49fc7b", + "src/skills/tests.rs": "77bdd7487e0abc90357bf64d9f3ebc84d6e0f3fba42963a97b368381c15b0fa5", + "tests/setup_dry_run.rs": "b833e5151da71df57eba9770fa88d446a6142c605c5c56a94ae76f0e64344ea8", + "src/mcp/configure.rs": "eced95030b0b011ae2a661b4b8cec1420549064c4945aa74242cc6e38523be64", + "tests/mcp.rs": "bcecb2c5333ddff5d980c9d8f62bfcd6a0e802bda8b8e18b04e213ad7c73a9c8" + }, + "binary_sha256": "9204ab2ad1edaa4b511e559401a04a84b628153c74b08e240d54c4720369eb59", + "note": "Latest native Cargo checks include the MCP profile fix; earlier Windows functional measurements retain their own binary hash." +} diff --git a/docs/verification/issue-386/environment.json b/docs/verification/issue-386/environment.json new file mode 100644 index 00000000..28462eb2 --- /dev/null +++ b/docs/verification/issue-386/environment.json @@ -0,0 +1,23 @@ +{ + "observed_at": "2026-10-03T15:01:21.948334+00:00", + "os": "Windows-11-10.0.26300-SP0", + "machine": "AMD64", + "source_commit": "338f426119b61123567b74028e7e8fe3bd99caa5", + "source_file_sha256": { + "UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/SceneHandler.cs": "3d44351bdbeda87ffb1a432f3ac013e6c86f2709935bbc7462e01e057a3cc2f9", + "UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/SceneHandlerTests.cs": "381ffee4c4341d6ab7442523ff4e4cec82ae3d9fe8d8239de1edfbbb7bda4717", + "src/app/editor.rs": "12ea2e975445003f9f47e5a8b9e62bbf9c5c7be5ca5e1393ef6bfab022c67199", + "src/app/setup.rs": "eab8bdf7cd59500812ac40c9acc104cf5a6c2c35140733e23571583a0829aa1f", + "src/app/test_runner.rs": "f8023e20459795926704614160cbb05b782f1fdc8b32e6c196d7695b38ae5691", + "src/daemon/unityd.rs": "3cbc5499fc3edb1b8ad3422a864e2e64c94a8f2be4f73f98513a4e5df55d629d", + "src/lsp/client.rs": "7c676ee0a967f79f6914140c1e147d29b58100ac5ec4fa41829b32563bbfd838", + "src/lsp/daemon.rs": "581ac8fd1f9df763069df66c0ed17d6507919ee63c52afff9741aa452f49fc7b", + "src/skills/tests.rs": "77bdd7487e0abc90357bf64d9f3ebc84d6e0f3fba42963a97b368381c15b0fa5", + "tests/setup_dry_run.rs": "b833e5151da71df57eba9770fa88d446a6142c605c5c56a94ae76f0e64344ea8" + }, + "binary_sha256": "abb04eca3cee68b3260c4701f6a10b2b053c87c1eaef95423117143cf4288eeb", + "release_binary_sha256": "efcd697b940f78b6457829453888d9c608f19d2fcd331d0005b1ff47a7839357", + "unity_version": "6000.4.4f1", + "cli_version": "0.18.1", + "bridge_version": "0.18.1" +} diff --git a/docs/verification/issue-386/final-checks.json b/docs/verification/issue-386/final-checks.json new file mode 100644 index 00000000..84320ce5 --- /dev/null +++ b/docs/verification/issue-386/final-checks.json @@ -0,0 +1,58 @@ +[ + { + "argv": [ + "cargo", + "fmt", + "--all", + "--", + "--check" + ], + "started_at": "2026-10-03T15:40:57.221387+00:00", + "finished_at": "2026-10-03T15:40:58.257958+00:00", + "exit_code": 0, + "log": "fmt.txt" + }, + { + "argv": [ + "cargo", + "clippy", + "--all-targets", + "--", + "-D", + "warnings" + ], + "started_at": "2026-10-03T15:40:58.258389+00:00", + "finished_at": "2026-10-03T15:41:08.285820+00:00", + "exit_code": 0, + "log": "clippy.txt" + }, + { + "argv": [ + "cargo", + "test", + "--all-targets", + "--no-fail-fast", + "--", + "--test-threads=1" + ], + "started_at": "2026-10-03T15:41:08.286169+00:00", + "finished_at": "2026-10-03T15:42:46.665584+00:00", + "exit_code": 101, + "log": "cargo-all-final.txt" + }, + { + "argv": [ + "cargo", + "run", + "--", + "skills", + "lint", + "--severity", + "error" + ], + "started_at": "2026-10-03T15:42:46.666218+00:00", + "finished_at": "2026-10-03T15:42:48.136472+00:00", + "exit_code": 1, + "log": "skills-lint-final.txt" + } +] diff --git a/docs/verification/issue-386/first-operations.json b/docs/verification/issue-386/first-operations.json new file mode 100644 index 00000000..6711d46f --- /dev/null +++ b/docs/verification/issue-386/first-operations.json @@ -0,0 +1,140 @@ +[ + { + "name": "editor_state", + "tool": "get_editor_state", + "status": "PASS", + "elapsed_seconds": 0.159 + }, + { + "name": "hierarchy", + "tool": "get_hierarchy", + "status": "PASS", + "elapsed_seconds": 0.072 + }, + { + "name": "find_gameobject", + "tool": "find_gameobject", + "status": "PASS", + "elapsed_seconds": 0.217 + }, + { + "name": "transform", + "tool": "get_component_values", + "status": "PASS", + "elapsed_seconds": 0.117 + }, + { + "name": "position", + "tool": "modify_gameobject", + "status": "PASS", + "elapsed_seconds": 0.08 + }, + { + "name": "create_cube", + "tool": "create_gameobject", + "status": "PASS", + "elapsed_seconds": 0.292 + }, + { + "name": "add_component", + "tool": "add_component", + "status": "PASS", + "elapsed_seconds": 0.108 + }, + { + "name": "remove_component", + "tool": "remove_component", + "status": "PASS", + "elapsed_seconds": 0.194 + }, + { + "name": "delete_gameobject", + "tool": "delete_gameobject", + "status": "PASS", + "elapsed_seconds": 0.302 + }, + { + "name": "scene_info", + "tool": "get_scene_info", + "status": "PASS", + "elapsed_seconds": 0.393 + }, + { + "name": "scene_save", + "tool": "save_scene", + "status": "PASS", + "elapsed_seconds": 0.431 + }, + { + "name": "console", + "tool": "read_console", + "status": "PASS", + "elapsed_seconds": 0.626 + }, + { + "name": "screenshot", + "tool": "capture_screenshot", + "status": "PASS", + "elapsed_seconds": 0.459 + }, + { + "name": "material_search", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.092 + }, + { + "name": "asset_copy", + "tool": "manage_asset_database", + "status": "FAIL", + "error": "Command '['E:\\\\unity-cli\\\\work\\\\issue-386\\\\target\\\\debug\\\\unity-cli.exe', '--output', 'json', '--project-path', 'E:\\\\unity-cli\\\\work\\\\issue-386\\\\.cache\\\\issue-386\\\\red-project', '--timeout-ms', '60000', 'raw', 'manage_asset_database', '--json', '{\"action\": \"copy_asset\", \"fromPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\", \"toPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat\"}']' timed out after 120 seconds" + }, + { + "name": "asset_move", + "tool": "manage_asset_database", + "status": "FAIL", + "error": "Command '['E:\\\\unity-cli\\\\work\\\\issue-386\\\\target\\\\debug\\\\unity-cli.exe', '--output', 'json', '--project-path', 'E:\\\\unity-cli\\\\work\\\\issue-386\\\\.cache\\\\issue-386\\\\red-project', '--timeout-ms', '60000', 'raw', 'manage_asset_database', '--json', '{\"action\": \"move_asset\", \"fromPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat\", \"toPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat\"}']' timed out after 120 seconds" + }, + { + "name": "asset_delete", + "tool": "manage_asset_database", + "status": "FAIL", + "error": "Command '['E:\\\\unity-cli\\\\work\\\\issue-386\\\\target\\\\debug\\\\unity-cli.exe', '--output', 'json', '--project-path', 'E:\\\\unity-cli\\\\work\\\\issue-386\\\\.cache\\\\issue-386\\\\red-project', '--timeout-ms', '60000', 'raw', 'manage_asset_database', '--json', '{\"action\": \"delete_asset\", \"assetPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat\"}']' timed out after 120 seconds" + }, + { + "name": "import_settings", + "tool": "manage_asset_import_settings", + "status": "PASS", + "elapsed_seconds": 8.369 + }, + { + "name": "material_modify", + "tool": "modify_material", + "status": "PASS", + "elapsed_seconds": 0.072 + }, + { + "name": "time_settings", + "tool": "get_project_settings", + "status": "PASS", + "elapsed_seconds": 0.041 + }, + { + "name": "read_csharp", + "tool": "read", + "status": "PASS", + "elapsed_seconds": 0.039 + }, + { + "name": "play_until_ready", + "tool": "play_game", + "status": "FAIL", + "error": "{'code': 'OPERATION_FAILED', 'error': 'OPERATION_FAILED: early eof', 'status': 'error'}" + }, + { + "name": "stop_until_ready", + "tool": "stop_game", + "status": "FAIL", + "error": "{'code': 'UNAUTHORIZED', 'error': 'Missing or invalid authentication token', 'id': '1', 'status': 'error'}" + } +] diff --git a/docs/verification/issue-386/fmt.txt b/docs/verification/issue-386/fmt.txt new file mode 100644 index 00000000..e69de29b diff --git a/docs/verification/issue-386/fresh-setup-summary.json b/docs/verification/issue-386/fresh-setup-summary.json new file mode 100644 index 00000000..e7cc2496 --- /dev/null +++ b/docs/verification/issue-386/fresh-setup-summary.json @@ -0,0 +1,70 @@ +{ + "started_at": "2026-10-03T14:30:44.503670+00:00", + "source_commit": "338f426119b61123567b74028e7e8fe3bd99caa5", + "binary_sha256": "abb04eca3cee68b3260c4701f6a10b2b053c87c1eaef95423117143cf4288eeb", + "cases": { + "setup": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\fresh-setup-project", + "--port", + "6488", + "setup", + "--launch-editor", + "--wait-secs", + "420" + ], + "exit_code": 0, + "elapsed_seconds": 40.549, + "success": true + }, + "ping": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\fresh-setup-project", + "system", + "ping" + ], + "exit_code": 0, + "elapsed_seconds": 1.212, + "success": true + }, + "auto-discovery": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\fresh-setup-project", + "instances", + "list" + ], + "exit_code": 0, + "elapsed_seconds": 3.259, + "success": true + }, + "release-ping": { + "argv": [ + "\\.cache\\issue-386\\installed-tools\\unity-cli\\win-x64\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\fresh-setup-project", + "system", + "ping" + ], + "exit_code": 0, + "elapsed_seconds": 0.552, + "success": true + } + }, + "editor_pid": 14140, + "unity_version": "6000.4.4f1", + "finished_at": "2026-10-03T14:31:30.524967+00:00" +} diff --git a/docs/verification/issue-386/green-results.xml b/docs/verification/issue-386/green-results.xml new file mode 100644 index 00000000..a7b758d4 --- /dev/null +++ b/docs/verification/issue-386/green-results.xml @@ -0,0 +1,13 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders + diff --git a/docs/verification/issue-386/install-release.txt b/docs/verification/issue-386/install-release.txt new file mode 100644 index 00000000..b335606d --- /dev/null +++ b/docs/verification/issue-386/install-release.txt @@ -0,0 +1,9 @@ +Detected platform: win-x64 +Fetching latest release... +Release: v0.18.1 +Downloading unity-cli-win-x64... +Checksum verified. +Installed unity-cli 0.18.1 -> E:\unity-cli\work\issue-386\.cache\issue-386\installed-tools\unity-cli\win-x64\unity-cli.exe + +Done. Run 'unity-cli --version' to verify. +unity-cli 0.18.1 diff --git a/docs/verification/issue-386/linux-tool-paths.txt b/docs/verification/issue-386/linux-tool-paths.txt new file mode 100644 index 00000000..c9c846db --- /dev/null +++ b/docs/verification/issue-386/linux-tool-paths.txt @@ -0,0 +1 @@ +/usr/bin/Xvfb diff --git a/docs/verification/issue-386/lockfiles.json b/docs/verification/issue-386/lockfiles.json new file mode 100644 index 00000000..71925144 --- /dev/null +++ b/docs/verification/issue-386/lockfiles.json @@ -0,0 +1,44 @@ +{ + "directory": "%USERPROFILE%\\.unity-cli\\editors", + "locks": [ + { + "schemaVersion": 1, + "pid": 14140, + "projectPath": "\\.cache\\issue-386\\fresh-setup-project", + "host": "127.0.0.1", + "port": 6488, + "configuredPort": 6488, + "unityVersion": "6000.4.4f1", + "bridgeVersion": "0.18.1", + "state": "ready", + "startedAt": 1791037874.9763892, + "heartbeatAt": 1791039672.4251444 + }, + { + "schemaVersion": 1, + "pid": 44232, + "projectPath": "\\.cache\\issue-386\\setup-project", + "host": "127.0.0.1", + "port": 6486, + "configuredPort": 6486, + "unityVersion": "6000.4.4f1", + "bridgeVersion": "0.18.1", + "state": "ready", + "startedAt": 1791001895.7939308, + "heartbeatAt": 1791039677.1909142 + }, + { + "schemaVersion": 1, + "pid": 52408, + "projectPath": "\\.cache\\issue-386\\red-project", + "host": "127.0.0.1", + "port": 6487, + "configuredPort": 6487, + "unityVersion": "6000.4.4f1", + "bridgeVersion": "0.18.1", + "state": "ready", + "startedAt": 1791039377.3480923, + "heartbeatAt": 1791039672.755435 + } + ] +} diff --git a/docs/verification/issue-386/mcp-green.txt b/docs/verification/issue-386/mcp-green.txt new file mode 100644 index 00000000..fb601fa5 --- /dev/null +++ b/docs/verification/issue-386/mcp-green.txt @@ -0,0 +1,30 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 6.27s + Running tests\auth_warning.rs (target\debug\deps\auth_warning-fcf05279c683382e.exe) + +running 1 test +test legacy_opt_out_warns_on_stderr_only_for_exact_one ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.70s + + Running tests\mcp.rs (target\debug\deps\mcp-86a7609ca7ad34e1.exe) + +running 3 tests +test configure_all_clients_preserves_other_servers_and_dry_run ... ok +test malformed_requests_do_not_end_session_or_execute_tools_before_initialization ... ok +test stdio_catalog_and_failure_contract_without_editor ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.24s + + Running tests\tool_list_filters.rs (target\debug\deps\tool_list_filters-71cf420645a1f348.exe) + +running 7 tests +test category_returns_only_that_docs_section ... ok +test compact_is_name_and_description_only_and_at_most_half_of_full_catalog ... ok +test limit_and_offset_page_the_filtered_list ... ok +test offline_default_list_has_schemas_and_names_only_is_compatible ... ok +test query_returns_only_matching_tools ... ok +test unknown_category_is_rejected ... ok +test unopened_project_still_exposes_the_offline_builtin_catalog ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.53s diff --git a/docs/verification/issue-386/mcp-red.txt b/docs/verification/issue-386/mcp-red.txt new file mode 100644 index 00000000..dd750f76 --- /dev/null +++ b/docs/verification/issue-386/mcp-red.txt @@ -0,0 +1,22 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 1.06s + Running tests\mcp.rs (target\debug\deps\mcp-86a7609ca7ad34e1.exe) + +running 1 test +test configure_all_clients_preserves_other_servers_and_dry_run ... FAILED + +failures: + +---- configure_all_clients_preserves_other_servers_and_dry_run stdout ---- + +thread 'configure_all_clients_preserves_other_servers_and_dry_run' (49484) panicked at tests\mcp.rs:189:9: +windsurf: preview must target the isolated configuration directory +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + +failures: + configure_all_clients_preserves_other_servers_and_dry_run + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.77s + +error: test failed, to rerun pass `--test mcp` diff --git a/docs/verification/issue-386/modal-fallback-disabled.stdout.json b/docs/verification/issue-386/modal-fallback-disabled.stdout.json new file mode 100644 index 00000000..471c67da --- /dev/null +++ b/docs/verification/issue-386/modal-fallback-disabled.stdout.json @@ -0,0 +1,16 @@ +{ + "command": "raw capture_screenshot", + "data": { + "code": "TIMEOUT", + "error": "OPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed", + "status": "error" + }, + "errors": [ + { + "code": "TIMEOUT", + "message": "OPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)" + } + ], + "success": false, + "warnings": [] +} diff --git a/docs/verification/issue-386/modal-os-fallback.stdout.json b/docs/verification/issue-386/modal-os-fallback.stdout.json new file mode 100644 index 00000000..ae1a2740 --- /dev/null +++ b/docs/verification/issue-386/modal-os-fallback.stdout.json @@ -0,0 +1,17 @@ +{ + "command": "raw capture_screenshot", + "data": { + "captureMode": "game", + "fallback": "os", + "fallbackTool": "powershell", + "fileSize": 637755, + "height": 949, + "message": "Desktop screenshot captured by the OS (Unity Editor did not respond)", + "note": "Unity Editor did not respond (OPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)); captured the whole desktop with an OS screenshot instead. The Editor main thread may be blocked by a modal dialog. Pass \"osFallback\": false to get the timeout error instead.", + "path": "\\.cache\\issue-386\\setup-project\\.unity\\capture\\image_os_1791037847148.png", + "width": 1512 + }, + "errors": [], + "success": true, + "warnings": [] +} diff --git a/docs/verification/issue-386/modal-summary.json b/docs/verification/issue-386/modal-summary.json new file mode 100644 index 00000000..adcf338c --- /dev/null +++ b/docs/verification/issue-386/modal-summary.json @@ -0,0 +1,49 @@ +{ + "started_at": "2026-10-03T14:30:44.505484+00:00", + "source_commit": "338f426119b61123567b74028e7e8fe3bd99caa5", + "binary_sha256": "abb04eca3cee68b3260c4701f6a10b2b053c87c1eaef95423117143cf4288eeb", + "cases": { + "modal-os-fallback": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\setup-project", + "--timeout-ms", + "1000", + "raw", + "capture_screenshot", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 2.917, + "success": true + }, + "modal-fallback-disabled": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\setup-project", + "--timeout-ms", + "1000", + "raw", + "capture_screenshot", + "--json", + "{\"osFallback\":false}" + ], + "exit_code": 6, + "elapsed_seconds": 3.212, + "success": false + } + }, + "png": { + "width": 1512, + "height": 949, + "sha256": "08a9cea00d74d0d463b6d345a3755a96066b9ef6bee6857d563e1e91b12cab41" + }, + "finished_at": "2026-10-03T14:30:51.515950+00:00" +} diff --git a/docs/verification/issue-386/operations.json b/docs/verification/issue-386/operations.json new file mode 100644 index 00000000..03d41ef7 --- /dev/null +++ b/docs/verification/issue-386/operations.json @@ -0,0 +1,140 @@ +[ + { + "name": "editor_state", + "tool": "get_editor_state", + "status": "PASS", + "elapsed_seconds": 0.157 + }, + { + "name": "hierarchy", + "tool": "get_hierarchy", + "status": "PASS", + "elapsed_seconds": 0.172 + }, + { + "name": "find_gameobject", + "tool": "find_gameobject", + "status": "PASS", + "elapsed_seconds": 0.345 + }, + { + "name": "transform", + "tool": "get_component_values", + "status": "PASS", + "elapsed_seconds": 0.412 + }, + { + "name": "position", + "tool": "modify_gameobject", + "status": "PASS", + "elapsed_seconds": 0.51 + }, + { + "name": "create_cube", + "tool": "create_gameobject", + "status": "PASS", + "elapsed_seconds": 0.589 + }, + { + "name": "add_component", + "tool": "add_component", + "status": "PASS", + "elapsed_seconds": 0.105 + }, + { + "name": "remove_component", + "tool": "remove_component", + "status": "PASS", + "elapsed_seconds": 0.1 + }, + { + "name": "delete_gameobject", + "tool": "delete_gameobject", + "status": "PASS", + "elapsed_seconds": 0.102 + }, + { + "name": "scene_info", + "tool": "get_scene_info", + "status": "PASS", + "elapsed_seconds": 0.094 + }, + { + "name": "scene_save", + "tool": "save_scene", + "status": "PASS", + "elapsed_seconds": 0.342 + }, + { + "name": "console", + "tool": "read_console", + "status": "PASS", + "elapsed_seconds": 0.126 + }, + { + "name": "screenshot", + "tool": "capture_screenshot", + "status": "PASS", + "elapsed_seconds": 0.32 + }, + { + "name": "material_search", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.563 + }, + { + "name": "asset_copy", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.119 + }, + { + "name": "asset_move", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 1.08 + }, + { + "name": "asset_delete", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.069 + }, + { + "name": "import_settings", + "tool": "manage_asset_import_settings", + "status": "PASS", + "elapsed_seconds": 0.045 + }, + { + "name": "material_modify", + "tool": "modify_material", + "status": "PASS", + "elapsed_seconds": 0.074 + }, + { + "name": "time_settings", + "tool": "get_project_settings", + "status": "PASS", + "elapsed_seconds": 0.042 + }, + { + "name": "read_csharp", + "tool": "read", + "status": "PASS", + "elapsed_seconds": 0.035 + }, + { + "name": "play_until_ready", + "tool": "play_game", + "status": "FAIL", + "error": "{'code': 'OPERATION_FAILED', 'error': 'OPERATION_FAILED: early eof', 'status': 'error'}" + }, + { + "name": "stop_until_ready", + "tool": "stop_game", + "status": "FAIL", + "error": "{'code': 'UNAUTHORIZED', 'error': 'Missing or invalid authentication token', 'id': '1', 'status': 'error'}" + } +] diff --git a/docs/verification/issue-386/profile-audit.json b/docs/verification/issue-386/profile-audit.json new file mode 100644 index 00000000..d2ab8fda --- /dev/null +++ b/docs/verification/issue-386/profile-audit.json @@ -0,0 +1,19 @@ +{ + "path": "%USERPROFILE%/.codeium/windsurf/mcp_config.json", + "created_at": "2026-10-03T15:14:29.659230+00:00", + "modified_at": "2026-10-03T15:14:29.660750+00:00", + "sha256": "29153948358c2c3e6db04ed03afe13bbe1f3eb6b738d8b6dc2bc8978761b4d10", + "top_level_keys": [ + "mcpServers" + ], + "server_names": [ + "unity-cli" + ], + "only_generated_entry": true, + "generated_file_removed": true, + "generated_file_still_absent_after_green": true, + "removed_empty_directories_created_by_test": [ + ".codeium/windsurf", + ".codeium" + ] +} diff --git a/docs/verification/issue-386/red-results.xml b/docs/verification/issue-386/red-results.xml new file mode 100644 index 00000000..a444a614 --- /dev/null +++ b/docs/verification/issue-386/red-results.xml @@ -0,0 +1,40 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested + { + "error": "Failed to save scene" +} + Expected: null + But was: "Failed to save scene" +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +Parent directory must exist before creating asset at: Assets/TestScenes/Nested/Generated/TestScene_Nested.unity +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath + Expected: null + But was: "Failed to save scene" +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +Parent directory must exist before creating asset at: Assets/Scenes/TestScene_Auto.unity + { + "error": "Failed to save scene" +} + Expected: null + But was: "Failed to save scene" +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +Parent directory must exist before creating asset at: Assets/TestScenes/Saved/Generated/TestScene_Saved.unity + diff --git a/docs/verification/issue-386/release-version.json b/docs/verification/issue-386/release-version.json new file mode 100644 index 00000000..5321e864 --- /dev/null +++ b/docs/verification/issue-386/release-version.json @@ -0,0 +1,10 @@ +{ + "argv": [ + "\\.cache\\issue-386\\installed-tools\\unity-cli\\win-x64\\unity-cli.exe", + "--version" + ], + "exit_code": 0, + "stdout": "unity-cli 0.18.1\n", + "stderr": "", + "observed_at": "2026-10-03T15:01:21.887453+00:00" +} diff --git a/docs/verification/issue-386/release.json b/docs/verification/issue-386/release.json new file mode 100644 index 00000000..7c897865 --- /dev/null +++ b/docs/verification/issue-386/release.json @@ -0,0 +1,16 @@ +{ + "argv": [ + "gh", + "release", + "view", + "v0.18.1", + "--repo", + "akiojin/unity-cli", + "--json", + "tagName,url,assets" + ], + "exit_code": 0, + "stdout": "{\"assets\":[{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103537\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:88d78c90a4f1530c1d1fab96d04f4d18ecb4f150ace344ce2ad9218408450c9d\",\"downloadCount\":0,\"id\":\"RA_kwDORR8NH84kIGfx\",\"label\":\"\",\"name\":\"csharp-lsp-linux-arm64\",\"size\":97260271,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:24Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/csharp-lsp-linux-arm64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103535\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:80503f54c025c5f602ba321a2c169f0f85cd8feb9f012324e48d375c269c8ed4\",\"downloadCount\":4,\"id\":\"RA_kwDORR8NH84kIGfv\",\"label\":\"\",\"name\":\"csharp-lsp-linux-x64\",\"size\":89837645,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:24Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/csharp-lsp-linux-x64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103528\",\"contentType\":\"application/json\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:2c91efd0efa8af84b7036d6be385c37cbc8269d79e177f036916f44bd31602ef\",\"downloadCount\":4,\"id\":\"RA_kwDORR8NH84kIGfo\",\"label\":\"\",\"name\":\"csharp-lsp-manifest.json\",\"size\":1191,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:19Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/csharp-lsp-manifest.json\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103539\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:c7427a1845e0bc3d96667a63a27331e10bd346067333e58ef94fcaca3053d64b\",\"downloadCount\":0,\"id\":\"RA_kwDORR8NH84kIGfz\",\"label\":\"\",\"name\":\"csharp-lsp-osx-arm64\",\"size\":96438839,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:24Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/csharp-lsp-osx-arm64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103540\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:3a915a97a00560a634bcb4e37ab12fe3df15702fe6b4adc73da56671df8a178b\",\"downloadCount\":0,\"id\":\"RA_kwDORR8NH84kIGf0\",\"label\":\"\",\"name\":\"csharp-lsp-osx-x64\",\"size\":89173351,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:24Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/csharp-lsp-osx-x64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103542\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927\",\"downloadCount\":0,\"id\":\"RA_kwDORR8NH84kIGf2\",\"label\":\"\",\"name\":\"csharp-lsp-win-x64\",\"size\":89822243,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:24Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/csharp-lsp-win-x64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103536\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:486597bce974b41bb47c20de96ea87929cb66874ac80a97688fb6647129765a1\",\"downloadCount\":276,\"id\":\"RA_kwDORR8NH84kIGfw\",\"label\":\"\",\"name\":\"SHA256SUMS\",\"size\":1130,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:19Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/SHA256SUMS\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103544\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:adcf93e3e75fdb29a7262c84d0a3b91a83d7aeee93bf26b4e0c220a366b22f22\",\"downloadCount\":0,\"id\":\"RA_kwDORR8NH84kIGf4\",\"label\":\"\",\"name\":\"unity-cli-linux-arm64\",\"size\":32675272,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:22Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/unity-cli-linux-arm64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103531\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:f0b12f5e4815e77a7c71098903ff9e1dd86ca350dd59e06f50fa27fd256b0a8e\",\"downloadCount\":19,\"id\":\"RA_kwDORR8NH84kIGfr\",\"label\":\"\",\"name\":\"unity-cli-linux-x64\",\"size\":33825448,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:22Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/unity-cli-linux-x64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103541\",\"contentType\":\"application/json\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:a9a8c7539a2cf3718d778e073dd103e610dcf63e9ab87692fbe851ef1936677b\",\"downloadCount\":449,\"id\":\"RA_kwDORR8NH84kIGf1\",\"label\":\"\",\"name\":\"unity-cli-manifest.json\",\"size\":1186,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:19Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/unity-cli-manifest.json\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103543\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:73283bfff946a4363affc6093fabaf5aaaf878075e3147ee26a445d30888ba5e\",\"downloadCount\":10,\"id\":\"RA_kwDORR8NH84kIGf3\",\"label\":\"\",\"name\":\"unity-cli-osx-arm64\",\"size\":27006240,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:21Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/unity-cli-osx-arm64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103530\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:bbd4884cb0e7de60241a6c38255486e86e506221586aec6a8412187426f74500\",\"downloadCount\":0,\"id\":\"RA_kwDORR8NH84kIGfq\",\"label\":\"\",\"name\":\"unity-cli-osx-x64\",\"size\":10443032,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:20Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/unity-cli-osx-x64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103533\",\"contentType\":\"application/octet-stream\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:efcd697b940f78b6457829453888d9c608f19d2fcd331d0005b1ff47a7839357\",\"downloadCount\":142,\"id\":\"RA_kwDORR8NH84kIGft\",\"label\":\"\",\"name\":\"unity-cli-win-x64\",\"size\":33678336,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:22Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/unity-cli-win-x64\"},{\"apiUrl\":\"https://api.github.com/repos/akiojin/unity-cli/releases/assets/606103534\",\"contentType\":\"application/x-msdos-program\",\"createdAt\":\"2026-10-02T17:18:19Z\",\"digest\":\"sha256:efcd697b940f78b6457829453888d9c608f19d2fcd331d0005b1ff47a7839357\",\"downloadCount\":5,\"id\":\"RA_kwDORR8NH84kIGfu\",\"label\":\"\",\"name\":\"unity-cli-win-x64.exe\",\"size\":33678336,\"state\":\"uploaded\",\"updatedAt\":\"2026-10-02T17:18:22Z\",\"url\":\"https://github.com/akiojin/unity-cli/releases/download/v0.18.1/unity-cli-win-x64.exe\"}],\"tagName\":\"v0.18.1\",\"url\":\"https://github.com/akiojin/unity-cli/releases/tag/v0.18.1\"}\n", + "stderr": "", + "observed_at": "2026-10-03T15:01:21.710037+00:00" +} diff --git a/docs/verification/issue-386/repository-secret-names.json b/docs/verification/issue-386/repository-secret-names.json new file mode 100644 index 00000000..95166442 --- /dev/null +++ b/docs/verification/issue-386/repository-secret-names.json @@ -0,0 +1,13 @@ +{ + "argv": [ + "gh", + "secret", + "list", + "--repo", + "akiojin/unity-cli" + ], + "exit_code": 0, + "stdout": "CARGO_REGISTRY_TOKEN\t2026-03-06T02:37:14Z\nCODECOV_TOKEN\t2026-03-11T02:17:20Z\nHOMEBREW_TAP_TOKEN\t2026-10-02T03:29:54Z\nPERSONAL_ACCESS_TOKEN\t2026-03-03T08:17:23Z\n", + "stderr": "", + "observed_at": "2026-10-03T15:01:21.069791+00:00" +} diff --git a/docs/verification/issue-386/setup.stdout.json b/docs/verification/issue-386/setup.stdout.json new file mode 100644 index 00000000..fae3bc2c --- /dev/null +++ b/docs/verification/issue-386/setup.stdout.json @@ -0,0 +1,57 @@ +{ + "command": "setup", + "data": { + "binary": { + "ok": true, + "onPath": null, + "path": "\\target\\debug\\unity-cli.exe", + "version": "0.18.1" + }, + "bridge": { + "action": "install", + "declared": "0.18.1", + "dryRun": false, + "inputBackends": null, + "installed": true, + "manifestChanged": true, + "manifestPath": "\\.cache\\issue-386\\fresh-setup-project\\Packages\\manifest.json", + "notes": [], + "package": "com.akiojin.unity-cli-bridge", + "projectPath": "\\.cache\\issue-386\\fresh-setup-project", + "registry": true, + "resolvedVersion": null, + "source": "registry", + "versionCheck": { + "bridgeVersion": "0.18.1", + "cliVersion": "0.18.1", + "message": "CLI and bridge are both 0.18.1", + "status": "match" + } + }, + "editor": { + "bridgeVersion": "0.18.1", + "endpoint": "127.0.0.1:6488", + "projectMatches": true, + "projectPath": "\\.cache\\issue-386\\fresh-setup-project", + "reachable": true, + "versionCheck": { + "bridgeVersion": "0.18.1", + "cliVersion": "0.18.1", + "message": "CLI and bridge are both 0.18.1", + "status": "match" + } + }, + "launch": { + "editorPath": "C:\\Program Files\\Unity\\Hub\\Editor\\6000.4.4f1\\Editor\\Unity.exe", + "launched": true, + "pid": 14140, + "port": 6488, + "unityVersion": "6000.4.4f1" + }, + "ok": true, + "warnings": [] + }, + "errors": [], + "success": true, + "warnings": [] +} diff --git a/docs/verification/issue-386/skills-lint-final.txt b/docs/verification/issue-386/skills-lint-final.txt new file mode 100644 index 00000000..a635c6bd --- /dev/null +++ b/docs/verification/issue-386/skills-lint-final.txt @@ -0,0 +1,51 @@ + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s + Running `target\debug\unity-cli.exe skills lint --severity error` +\.claude/skills\unity-2d-sprite-tilemap: error [R20] symlink `\.claude/skills\unity-2d-sprite-tilemap` points to `\\?\\.claude\skills\unity-2d-sprite-tilemap` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-2d-sprite-tilemap` +\.agents/skills\unity-2d-sprite-tilemap: error [R21] symlink `\.agents/skills\unity-2d-sprite-tilemap` points to `\\?\\.agents\skills\unity-2d-sprite-tilemap` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-2d-sprite-tilemap` +\.claude/skills\unity-addressables: error [R20] symlink `\.claude/skills\unity-addressables` points to `\\?\\.claude\skills\unity-addressables` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-addressables` +\.agents/skills\unity-addressables: error [R21] symlink `\.agents/skills\unity-addressables` points to `\\?\\.agents\skills\unity-addressables` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-addressables` +\.claude/skills\unity-asset-management: error [R20] symlink `\.claude/skills\unity-asset-management` points to `\\?\\.claude\skills\unity-asset-management` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-asset-management` +\.agents/skills\unity-asset-management: error [R21] symlink `\.agents/skills\unity-asset-management` points to `\\?\\.agents\skills\unity-asset-management` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-asset-management` +\.claude/skills\unity-audio-setup: error [R20] symlink `\.claude/skills\unity-audio-setup` points to `\\?\\.claude\skills\unity-audio-setup` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-audio-setup` +\.agents/skills\unity-audio-setup: error [R21] symlink `\.agents/skills\unity-audio-setup` points to `\\?\\.agents\skills\unity-audio-setup` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-audio-setup` +\.claude/skills\unity-cli-usage: error [R20] symlink `\.claude/skills\unity-cli-usage` points to `\\?\\.claude\skills\unity-cli-usage` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-cli-usage` +\.agents/skills\unity-cli-usage: error [R21] symlink `\.agents/skills\unity-cli-usage` points to `\\?\\.agents\skills\unity-cli-usage` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-cli-usage` +\.claude/skills\unity-csharp-edit: error [R20] symlink `\.claude/skills\unity-csharp-edit` points to `\\?\\.claude\skills\unity-csharp-edit` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-csharp-edit` +\.agents/skills\unity-csharp-edit: error [R21] symlink `\.agents/skills\unity-csharp-edit` points to `\\?\\.agents\skills\unity-csharp-edit` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-csharp-edit` +\.claude/skills\unity-csharp-navigate: error [R20] symlink `\.claude/skills\unity-csharp-navigate` points to `\\?\\.claude\skills\unity-csharp-navigate` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-csharp-navigate` +\.agents/skills\unity-csharp-navigate: error [R21] symlink `\.agents/skills\unity-csharp-navigate` points to `\\?\\.agents\skills\unity-csharp-navigate` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-csharp-navigate` +\.claude/skills\unity-csharp-reference: error [R20] symlink `\.claude/skills\unity-csharp-reference` points to `\\?\\.claude\skills\unity-csharp-reference` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-csharp-reference` +\.agents/skills\unity-csharp-reference: error [R21] symlink `\.agents/skills\unity-csharp-reference` points to `\\?\\.agents\skills\unity-csharp-reference` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-csharp-reference` +\.claude/skills\unity-development-loop: error [R20] symlink `\.claude/skills\unity-development-loop` points to `\\?\\.claude\skills\unity-development-loop` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-development-loop` +\.agents/skills\unity-development-loop: error [R21] symlink `\.agents/skills\unity-development-loop` points to `\\?\\.agents\skills\unity-development-loop` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-development-loop` +\.claude/skills\unity-editor-tools: error [R20] symlink `\.claude/skills\unity-editor-tools` points to `\\?\\.claude\skills\unity-editor-tools` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-editor-tools` +\.agents/skills\unity-editor-tools: error [R21] symlink `\.agents/skills\unity-editor-tools` points to `\\?\\.agents\skills\unity-editor-tools` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-editor-tools` +\.claude/skills\unity-gameobject-edit: error [R20] symlink `\.claude/skills\unity-gameobject-edit` points to `\\?\\.claude\skills\unity-gameobject-edit` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-gameobject-edit` +\.agents/skills\unity-gameobject-edit: error [R21] symlink `\.agents/skills\unity-gameobject-edit` points to `\\?\\.agents\skills\unity-gameobject-edit` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-gameobject-edit` +\.claude/skills\unity-input-system: error [R20] symlink `\.claude/skills\unity-input-system` points to `\\?\\.claude\skills\unity-input-system` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-input-system` +\.agents/skills\unity-input-system: error [R21] symlink `\.agents/skills\unity-input-system` points to `\\?\\.agents\skills\unity-input-system` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-input-system` +\.claude/skills\unity-localization: error [R20] symlink `\.claude/skills\unity-localization` points to `\\?\\.claude\skills\unity-localization` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-localization` +\.agents/skills\unity-localization: error [R21] symlink `\.agents/skills\unity-localization` points to `\\?\\.agents\skills\unity-localization` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-localization` +\.claude/skills\unity-package-management: error [R20] symlink `\.claude/skills\unity-package-management` points to `\\?\\.claude\skills\unity-package-management` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-package-management` +\.agents/skills\unity-package-management: error [R21] symlink `\.agents/skills\unity-package-management` points to `\\?\\.agents\skills\unity-package-management` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-package-management` +\.claude/skills\unity-playmode-testing: error [R20] symlink `\.claude/skills\unity-playmode-testing` points to `\\?\\.claude\skills\unity-playmode-testing` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-playmode-testing` +\.agents/skills\unity-playmode-testing: error [R21] symlink `\.agents/skills\unity-playmode-testing` points to `\\?\\.agents\skills\unity-playmode-testing` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-playmode-testing` +\.claude/skills\unity-prefab-workflow: error [R20] symlink `\.claude/skills\unity-prefab-workflow` points to `\\?\\.claude\skills\unity-prefab-workflow` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-prefab-workflow` +\.agents/skills\unity-prefab-workflow: error [R21] symlink `\.agents/skills\unity-prefab-workflow` points to `\\?\\.agents\skills\unity-prefab-workflow` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-prefab-workflow` +\.claude/skills\unity-project-bootstrap: error [R20] symlink `\.claude/skills\unity-project-bootstrap` points to `\\?\\.claude\skills\unity-project-bootstrap` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-project-bootstrap` +\.agents/skills\unity-project-bootstrap: error [R21] symlink `\.agents/skills\unity-project-bootstrap` points to `\\?\\.agents\skills\unity-project-bootstrap` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-project-bootstrap` +\.claude/skills\unity-scene-create: error [R20] symlink `\.claude/skills\unity-scene-create` points to `\\?\\.claude\skills\unity-scene-create` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-scene-create` +\.agents/skills\unity-scene-create: error [R21] symlink `\.agents/skills\unity-scene-create` points to `\\?\\.agents\skills\unity-scene-create` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-scene-create` +\.claude/skills\unity-scene-inspect: error [R20] symlink `\.claude/skills\unity-scene-inspect` points to `\\?\\.claude\skills\unity-scene-inspect` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-scene-inspect` +\.agents/skills\unity-scene-inspect: error [R21] symlink `\.agents/skills\unity-scene-inspect` points to `\\?\\.agents\skills\unity-scene-inspect` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-scene-inspect` +\.claude/skills\unity-ui-automation: error [R20] symlink `\.claude/skills\unity-ui-automation` points to `\\?\\.claude\skills\unity-ui-automation` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-ui-automation` +\.agents/skills\unity-ui-automation: error [R21] symlink `\.agents/skills\unity-ui-automation` points to `\\?\\.agents\skills\unity-ui-automation` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-ui-automation` +\.claude/skills\unity-ui-toolkit-build: error [R20] symlink `\.claude/skills\unity-ui-toolkit-build` points to `\\?\\.claude\skills\unity-ui-toolkit-build` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-ui-toolkit-build` +\.agents/skills\unity-ui-toolkit-build: error [R21] symlink `\.agents/skills\unity-ui-toolkit-build` points to `\\?\\.agents\skills\unity-ui-toolkit-build` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-ui-toolkit-build` +\.claude/skills\unity-urp-setup: error [R20] symlink `\.claude/skills\unity-urp-setup` points to `\\?\\.claude\skills\unity-urp-setup` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-urp-setup` +\.agents/skills\unity-urp-setup: error [R21] symlink `\.agents/skills\unity-urp-setup` points to `\\?\\.agents\skills\unity-urp-setup` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-urp-setup` +\.claude/skills\unity-vfx-graph: error [R20] symlink `\.claude/skills\unity-vfx-graph` points to `\\?\\.claude\skills\unity-vfx-graph` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-vfx-graph` +\.agents/skills\unity-vfx-graph: error [R21] symlink `\.agents/skills\unity-vfx-graph` points to `\\?\\.agents\skills\unity-vfx-graph` but expected `\\?\\.claude-plugin\plugins\unity-cli\skills\unity-vfx-graph` + +23 skills checked, 46 violations +error: process didn't exit successfully: `target\debug\unity-cli.exe skills lint --severity error` (exit code: 1) diff --git a/docs/verification/issue-386/staff-final-operations.json b/docs/verification/issue-386/staff-final-operations.json new file mode 100644 index 00000000..962ee9f0 --- /dev/null +++ b/docs/verification/issue-386/staff-final-operations.json @@ -0,0 +1,140 @@ +[ + { + "name": "editor_state", + "tool": "get_editor_state", + "status": "PASS", + "elapsed_seconds": 0.809 + }, + { + "name": "hierarchy", + "tool": "get_hierarchy", + "status": "PASS", + "elapsed_seconds": 0.428 + }, + { + "name": "find_gameobject", + "tool": "find_gameobject", + "status": "PASS", + "elapsed_seconds": 0.056 + }, + { + "name": "transform", + "tool": "get_component_values", + "status": "PASS", + "elapsed_seconds": 0.064 + }, + { + "name": "position", + "tool": "modify_gameobject", + "status": "PASS", + "elapsed_seconds": 0.049 + }, + { + "name": "create_cube", + "tool": "create_gameobject", + "status": "PASS", + "elapsed_seconds": 0.04 + }, + { + "name": "add_component", + "tool": "add_component", + "status": "PASS", + "elapsed_seconds": 0.055 + }, + { + "name": "remove_component", + "tool": "remove_component", + "status": "PASS", + "elapsed_seconds": 0.049 + }, + { + "name": "delete_gameobject", + "tool": "delete_gameobject", + "status": "PASS", + "elapsed_seconds": 0.054 + }, + { + "name": "scene_info", + "tool": "get_scene_info", + "status": "PASS", + "elapsed_seconds": 0.042 + }, + { + "name": "scene_save", + "tool": "save_scene", + "status": "PASS", + "elapsed_seconds": 0.059 + }, + { + "name": "console", + "tool": "read_console", + "status": "PASS", + "elapsed_seconds": 0.047 + }, + { + "name": "screenshot", + "tool": "capture_screenshot", + "status": "PASS", + "elapsed_seconds": 0.113 + }, + { + "name": "material_search", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.223 + }, + { + "name": "asset_copy", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.07 + }, + { + "name": "asset_move", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.089 + }, + { + "name": "asset_delete", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.271 + }, + { + "name": "import_settings", + "tool": "manage_asset_import_settings", + "status": "PASS", + "elapsed_seconds": 0.047 + }, + { + "name": "material_modify", + "tool": "modify_material", + "status": "PASS", + "elapsed_seconds": 0.084 + }, + { + "name": "time_settings", + "tool": "get_project_settings", + "status": "PASS", + "elapsed_seconds": 0.247 + }, + { + "name": "read_csharp", + "tool": "read", + "status": "PASS", + "elapsed_seconds": 0.036 + }, + { + "name": "play_until_ready", + "tool": "play_game", + "status": "PASS", + "elapsed_seconds": 0.979 + }, + { + "name": "stop_until_ready", + "tool": "stop_game", + "status": "PASS", + "elapsed_seconds": 0.893 + } +] diff --git a/docs/verification/issue-386/staff-final-summary.json b/docs/verification/issue-386/staff-final-summary.json new file mode 100644 index 00000000..50dba718 --- /dev/null +++ b/docs/verification/issue-386/staff-final-summary.json @@ -0,0 +1,610 @@ +{ + "started_at": "2026-10-03T14:58:11.479989+00:00", + "source_commit": "338f426119b61123567b74028e7e8fe3bd99caa5", + "binary_sha256": "abb04eca3cee68b3260c4701f6a10b2b053c87c1eaef95423117143cf4288eeb", + "cases": { + "staff-play-settings": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "editor", + "eval", + "\nvar before = new { enabled = UnityEditor.EditorSettings.enterPlayModeOptionsEnabled,\n options = UnityEditor.EditorSettings.enterPlayModeOptions.ToString() };\nUnityEditor.EditorSettings.enterPlayModeOptionsEnabled = true;\nUnityEditor.EditorSettings.enterPlayModeOptions = UnityEditor.EnterPlayModeOptions.DisableDomainReload;\nvar assembly = typeof(UnityEditor.EditorWindow).Assembly;\nvar game = assembly.GetType(\"UnityEditor.GameView\", true);\nUnityEditor.EditorWindow.GetWindow(game, false, \"Game\", false);\nvar type = assembly.GetType(\"UnityEditor.PlayModeView\", true);\nvar property = type.GetProperty(\"enterPlayModeBehavior\");\nforeach (var view in UnityEngine.Resources.FindObjectsOfTypeAll(type))\n property.SetValue(view, System.Enum.Parse(property.PropertyType, \"PlayUnfocused\"));\nreturn before;\n", + "--mode", + "statements" + ], + "exit_code": 0, + "elapsed_seconds": 1.635, + "success": true + }, + "staff-get_editor_state-1": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.046, + "success": true + }, + "staff-create_scene-2": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "create_scene", + "--json", + "{\"sceneName\": \"Issue386_Staff_1791039493306097700\", \"path\": \"Assets/Scenes/Generated/E2E/Performance\", \"loadScene\": true}" + ], + "exit_code": 0, + "elapsed_seconds": 0.44, + "success": true + }, + "staff-create_gameobject-3": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "create_gameobject", + "--json", + "{\"name\": \"Perf394Target\", \"primitiveType\": \"cube\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.114, + "success": true + }, + "staff-create_material-4": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "create_material", + "--json", + "{\"materialPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\", \"shader\": \"Unlit/Color\", \"overwrite\": true}" + ], + "exit_code": 0, + "elapsed_seconds": 0.392, + "success": true + }, + "staff-save_scene-5": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "save_scene", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.314, + "success": true + }, + "staff-get_editor_state-6": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.808, + "success": true + }, + "staff-get_hierarchy-7": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_hierarchy", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.427, + "success": true + }, + "staff-find_gameobject-8": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "find_gameobject", + "--json", + "{\"name\": \"Perf394Target\", \"exactMatch\": true}" + ], + "exit_code": 0, + "elapsed_seconds": 0.056, + "success": true + }, + "staff-get_component_values-9": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_component_values", + "--json", + "{\"gameObjectName\": \"Perf394Target\", \"componentType\": \"Transform\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.064, + "success": true + }, + "staff-modify_gameobject-10": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "modify_gameobject", + "--json", + "{\"path\": \"/Perf394Target\", \"position\": {\"x\": 1, \"y\": 2, \"z\": 3}}" + ], + "exit_code": 0, + "elapsed_seconds": 0.048, + "success": true + }, + "staff-create_gameobject-11": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "create_gameobject", + "--json", + "{\"name\": \"Perf394Cube\", \"primitiveType\": \"cube\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.039, + "success": true + }, + "staff-add_component-12": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "add_component", + "--json", + "{\"gameObjectPath\": \"/Perf394Cube\", \"componentType\": \"Rigidbody\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.055, + "success": true + }, + "staff-remove_component-13": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "remove_component", + "--json", + "{\"gameObjectPath\": \"/Perf394Cube\", \"componentType\": \"Rigidbody\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.048, + "success": true + }, + "staff-delete_gameobject-14": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "delete_gameobject", + "--json", + "{\"path\": \"/Perf394Cube\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.053, + "success": true + }, + "staff-get_scene_info-15": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_scene_info", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.042, + "success": true + }, + "staff-save_scene-16": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "save_scene", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.059, + "success": true + }, + "staff-read_console-17": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "read_console", + "--json", + "{\"count\": 20}" + ], + "exit_code": 0, + "elapsed_seconds": 0.046, + "success": true + }, + "staff-capture_screenshot-18": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "capture_screenshot", + "--json", + "{\"captureMode\": \"game\", \"width\": 1280, \"height\": 720, \"includeUI\": false, \"encodeAsBase64\": false, \"osFallback\": false}" + ], + "exit_code": 0, + "elapsed_seconds": 0.113, + "success": true + }, + "staff-manage_asset_database-19": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_database", + "--json", + "{\"action\": \"find_assets\", \"filter\": \"t:Material\", \"searchInFolders\": [\"Assets/Scenes/Generated/E2E/Performance\"]}" + ], + "exit_code": 0, + "elapsed_seconds": 0.223, + "success": true + }, + "staff-manage_asset_database-20": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_database", + "--json", + "{\"action\": \"copy_asset\", \"fromPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\", \"toPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.07, + "success": true + }, + "staff-manage_asset_database-21": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_database", + "--json", + "{\"action\": \"move_asset\", \"fromPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat\", \"toPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.088, + "success": true + }, + "staff-manage_asset_database-22": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_database", + "--json", + "{\"action\": \"delete_asset\", \"assetPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.271, + "success": true + }, + "staff-manage_asset_import_settings-23": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_import_settings", + "--json", + "{\"action\": \"get\", \"assetPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.047, + "success": true + }, + "staff-modify_material-24": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "modify_material", + "--json", + "{\"materialPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\", \"properties\": {\"_Color\": [0.2, 0.4, 0.8, 1]}}" + ], + "exit_code": 0, + "elapsed_seconds": 0.083, + "success": true + }, + "staff-get_project_settings-25": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_project_settings", + "--json", + "{\"includeTime\": true, \"includePlayer\": false}" + ], + "exit_code": 0, + "elapsed_seconds": 0.246, + "success": true + }, + "staff-read-26": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "read", + "--json", + "{\"path\": \"Packages/com.akiojin.unity-cli-bridge/Editor/Core/UnityCliBridgeHost.cs\", \"maxLines\": 50}" + ], + "exit_code": 0, + "elapsed_seconds": 0.036, + "success": true + }, + "staff-play_game-27": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "play_game", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.05, + "success": true + }, + "staff-get_editor_state-28": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.219, + "success": true + }, + "staff-get_editor_state-29": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.224, + "success": true + }, + "staff-get_editor_state-30": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.463, + "success": true + }, + "staff-stop_game-31": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "stop_game", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.463, + "success": true + }, + "staff-get_editor_state-32": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.429, + "success": true + } + }, + "play_settings": { + "enterPlayModeOptionsEnabled": true, + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeBehavior": "PlayUnfocused", + "previous": { + "enabled": false, + "options": "None" + } + }, + "finished_at": "2026-10-03T14:58:19.377632+00:00" +} diff --git a/docs/verification/issue-386/staff-play-settings.stdout.json b/docs/verification/issue-386/staff-play-settings.stdout.json new file mode 100644 index 00000000..de04d7f7 --- /dev/null +++ b/docs/verification/issue-386/staff-play-settings.stdout.json @@ -0,0 +1,25 @@ +{ + "command": "editor eval", + "data": { + "diagnostics": [ + { + "column": 1, + "id": "CS0162", + "line": 19, + "message": "Unreachable code detected", + "severity": "warning" + } + ], + "exception": null, + "logs": [], + "requestId": "cli-23136-18db0ceda6f62ce8-0", + "state": "completed", + "value": { + "enabled": false, + "options": "None" + } + }, + "errors": [], + "success": true, + "warnings": [] +} diff --git a/docs/verification/issue-386/tasklist-14140.json b/docs/verification/issue-386/tasklist-14140.json new file mode 100644 index 00000000..4fa1eaa1 --- /dev/null +++ b/docs/verification/issue-386/tasklist-14140.json @@ -0,0 +1,14 @@ +{ + "argv": [ + "tasklist", + "/FI", + "PID eq 14140", + "/FO", + "CSV", + "/NH" + ], + "exit_code": 0, + "stdout": "\"Unity.exe\",\"14140\",\"RDP-Tcp#0\",\"2\",\"1,638,552 K\"\n", + "stderr": "", + "observed_at": "2026-10-03T15:01:17.338442+00:00" +} diff --git a/docs/verification/issue-386/tasklist-44232.json b/docs/verification/issue-386/tasklist-44232.json new file mode 100644 index 00000000..26a04578 --- /dev/null +++ b/docs/verification/issue-386/tasklist-44232.json @@ -0,0 +1,14 @@ +{ + "argv": [ + "tasklist", + "/FI", + "PID eq 44232", + "/FO", + "CSV", + "/NH" + ], + "exit_code": 0, + "stdout": "\"Unity.exe\",\"44232\",\"RDP-Tcp#0\",\"2\",\"1,648,308 K\"\n", + "stderr": "", + "observed_at": "2026-10-03T15:01:17.661572+00:00" +} diff --git a/docs/verification/issue-386/tasklist-52408.json b/docs/verification/issue-386/tasklist-52408.json new file mode 100644 index 00000000..7f00a5c6 --- /dev/null +++ b/docs/verification/issue-386/tasklist-52408.json @@ -0,0 +1,14 @@ +{ + "argv": [ + "tasklist", + "/FI", + "PID eq 52408", + "/FO", + "CSV", + "/NH" + ], + "exit_code": 0, + "stdout": "\"Unity.exe\",\"52408\",\"RDP-Tcp#0\",\"2\",\"2,026,148 K\"\n", + "stderr": "", + "observed_at": "2026-10-03T15:01:18.042840+00:00" +} diff --git a/docs/verification/issue-386/unity-final.txt b/docs/verification/issue-386/unity-final.txt new file mode 100644 index 00000000..5956fa55 --- /dev/null +++ b/docs/verification/issue-386/unity-final.txt @@ -0,0 +1,2 @@ +Started headless Editor (pid 44188) +11 tests, 0 failed; report: \.cache\issue-386\green-results.xml diff --git a/docs/verification/issue-386/verify-run-second.json b/docs/verification/issue-386/verify-run-second.json new file mode 100644 index 00000000..48622d60 --- /dev/null +++ b/docs/verification/issue-386/verify-run-second.json @@ -0,0 +1 @@ +{"error":"unexpected server response: verify: deferred — host busy for 1500s (budget 1500s): verification lease held by verification 99a8660247f5bc49--verification--8955c99b1a861e67 (pid 49800 alive, job running, nice unknown, spawn-host inherit, 2338s left, 6 batches ≈ 5389s); holder stalled: held 66m13s, its 3 processes gained no CPU time beyond scheduler noise (< 0.5% of one core) over the last 2.7s and none started or exited — it is blocked waiting (I/O, a lock or a prompt) and may be hung; next_turn_reserved: yes; queue_position: 2; rerun `verify.run` in about 5389s (timing hint only; a progressing holder renews its TTL) — a deferral is not a failure and there is no attempt cap: your turn stays reserved, so keep rerunning `verify.run` while the holder makes progress","exit_code":1,"ok":false,"operation":"verify.run"} diff --git a/docs/verification/issue-386/verify-run.json b/docs/verification/issue-386/verify-run.json new file mode 100644 index 00000000..9e397532 --- /dev/null +++ b/docs/verification/issue-386/verify-run.json @@ -0,0 +1 @@ +{"error":"unexpected server response: verify: deferred — host busy for 300s (budget 300s): verification lease held by verification 99a8660247f5bc49--verification--8955c99b1a861e67 (pid 49800 alive, job running, nice unknown, spawn-host inherit, 2694s left, 7 batches ≈ 43s); holder progressing: held 37m01s, its 3 working processes gained 516ms of CPU over the last 1.8s (29.3% of one core); next_turn_reserved: yes; queue_position: 2; rerun `verify.run` in about 43s (timing hint only; a progressing holder renews its TTL) — a deferral is not a failure and there is no attempt cap: your turn stays reserved, so keep rerunning `verify.run` while the holder makes progress","exit_code":1,"ok":false,"operation":"verify.run"} diff --git a/docs/verification/issue-386/winget.json b/docs/verification/issue-386/winget.json new file mode 100644 index 00000000..b59f4a40 --- /dev/null +++ b/docs/verification/issue-386/winget.json @@ -0,0 +1,17 @@ +{ + "argv": [ + "winget", + "show", + "--id", + "akiojin.unity-cli", + "--exact", + "--source", + "winget", + "--accept-source-agreements", + "--disable-interactivity" + ], + "exit_code": 2316632084, + "stdout": "入力条件に一致するパッケージが見つかりませんでした。\n", + "stderr": "", + "observed_at": "2026-10-03T15:01:20.627834+00:00" +} diff --git a/src/app/editor.rs b/src/app/editor.rs index 72cfa87f..ec0be9df 100644 --- a/src/app/editor.rs +++ b/src/app/editor.rs @@ -37,10 +37,11 @@ pub(super) fn running(root: &Path) -> Option { } pub(super) fn launch_command(editor: &Path, root: &Path, headless: bool) -> Command { + let root = unity_argument_path(root); let mut command = Command::new(editor); command .arg("-projectPath") - .arg(root) + .arg(&root) .arg("-logFile") .arg(root.join("Logs/unity-cli-editor.log")) .stdin(Stdio::null()) @@ -59,6 +60,21 @@ pub(super) fn launch_command(editor: &Path, root: &Path, headless: bool) -> Comm command } +pub(super) fn unity_argument_path(path: &Path) -> PathBuf { + #[cfg(windows)] + { + // Unity's command-line parser does not accept canonical Win32 verbatim paths. + let text = path.to_string_lossy(); + if let Some(unc) = text.strip_prefix(r"\\?\UNC\") { + return PathBuf::from(format!(r"\\{unc}")); + } + if let Some(local) = text.strip_prefix(r"\\?\") { + return PathBuf::from(local); + } + } + path.to_path_buf() +} + pub async fn open(cli: &Cli, headless: bool, wait_ready: u64) -> Result { let root = project(cli)?; let version = super::setup::project_unity_version(&root)?; @@ -85,8 +101,7 @@ pub async fn open(cli: &Cli, headless: bool, wait_ready: u64) -> Result { command.env("UNITY_CLI_PORT_OVERRIDE", port.to_string()); } Some( - command - .spawn() + crate::daemon::spawn::spawn_detached(&mut command) .with_context(|| format!("Failed to launch {}", editor.display()))?, ) } else { @@ -226,3 +241,29 @@ pub async fn status(cli: &Cli) -> Result { }; Ok(json!({"state": label, "projectPath": root, "diagnostic": diagnostic})) } + +#[cfg(all(test, windows))] +mod tests { + use super::*; + + #[test] + fn editor_launch_uses_paths_supported_by_unity() { + for (root, expected) in [ + (r"\\?\C:\Projects\With spaces", r"C:\Projects\With spaces"), + (r"\\?\UNC\server\share\Project", r"\\server\share\Project"), + ] { + let command = launch_command(Path::new("Unity.exe"), Path::new(root), true); + let args: Vec<_> = command + .get_args() + .map(|arg| arg.to_string_lossy()) + .collect(); + assert_eq!(args[1], expected); + assert_eq!( + args[3], + Path::new(expected) + .join("Logs/unity-cli-editor.log") + .to_string_lossy() + ); + } + } +} diff --git a/src/app/setup.rs b/src/app/setup.rs index 4733a7b5..b8cfda44 100644 --- a/src/app/setup.rs +++ b/src/app/setup.rs @@ -211,7 +211,7 @@ fn launch_editor(root: &Path, port: u16) -> Result { let mut command = std::process::Command::new(&editor); command .arg("-projectPath") - .arg(root) + .arg(super::editor::unity_argument_path(root)) .env("UNITY_CLI_PORT", port.to_string()) .stdin(std::process::Stdio::null()) .stdout(std::process::Stdio::null()) @@ -222,8 +222,7 @@ fn launch_editor(root: &Path, port: u16) -> Result { // Detach from the caller's process group so the Editor outlives it. command.process_group(0); } - let child = command - .spawn() + let child = crate::daemon::spawn::spawn_detached(&mut command) .with_context(|| format!("Failed to launch {}", editor.display()))?; Ok(json!({ "launched": true, diff --git a/src/app/test_runner.rs b/src/app/test_runner.rs index 031fdca8..76300032 100644 --- a/src/app/test_runner.rs +++ b/src/app/test_runner.rs @@ -37,7 +37,8 @@ pub async fn run(cli: &Cli, args: &TestArgs) -> Result<()> { if let Some(port) = cli.port { command.env("UNITY_CLI_PORT_OVERRIDE", port.to_string()); } - let child = command.spawn().context(FailureKind::Unreachable)?; + let child = + crate::daemon::spawn::spawn_detached(&mut command).context(FailureKind::Unreachable)?; eprintln!("Started headless Editor (pid {})", child.id()); Some(child) }; diff --git a/src/daemon/unityd.rs b/src/daemon/unityd.rs index ef77b788..0643dfbc 100644 --- a/src/daemon/unityd.rs +++ b/src/daemon/unityd.rs @@ -494,7 +494,7 @@ pub async fn try_batch( )) } -#[cfg(test)] +#[cfg(all(test, unix))] fn ping() -> Result<()> { let response = request(DaemonRequest::Ping)?; if response.ok { @@ -826,6 +826,7 @@ async fn handle_request( #[cfg(test)] mod tests { use super::*; + #[cfg(unix)] use std::io::{BufRead, BufReader, Write}; use tempfile::tempdir; diff --git a/src/lsp/client.rs b/src/lsp/client.rs index cfad58de..5a2d7fc1 100644 --- a/src/lsp/client.rs +++ b/src/lsp/client.rs @@ -1410,12 +1410,13 @@ mod tests { use std::sync::{Mutex, OnceLock}; use super::{ - build_remove_symbol_request, collect_document_symbols, execute_direct, file_uri, get_apply, - id_matches, is_retryable_session_error, kind_from_lsp, maybe_execute, - normalize_lsp_write_result, normalize_rel_path, path_matches_scope, read_message, ref_path, - require_name_path, require_relative_path, reset_cached_session, to_project_relative_or_raw, - uri_to_rel_path, + build_remove_symbol_request, collect_document_symbols, file_uri, get_apply, id_matches, + is_retryable_session_error, kind_from_lsp, normalize_lsp_write_result, normalize_rel_path, + path_matches_scope, ref_path, require_name_path, require_relative_path, + to_project_relative_or_raw, uri_to_rel_path, }; + #[cfg(unix)] + use super::{execute_direct, maybe_execute, read_message, reset_cached_session}; #[cfg(unix)] fn env_lock() -> &'static Mutex<()> { diff --git a/src/lsp/daemon.rs b/src/lsp/daemon.rs index 65cdaaf8..17f00cda 100644 --- a/src/lsp/daemon.rs +++ b/src/lsp/daemon.rs @@ -561,7 +561,9 @@ fn cleanup_stale_files_on_start() { mod tests { use super::*; use serde_json::json; - use std::io::{self, BufRead, BufReader, Write}; + use std::io::{self, Write}; + #[cfg(unix)] + use std::io::{BufRead, BufReader}; use tempfile::tempdir; fn env_lock() -> &'static std::sync::Mutex<()> { @@ -602,6 +604,7 @@ mod tests { (dir, env) } + #[cfg(unix)] fn ensure_local_lsp_binary() { let binary = crate::lsp_manager::binary_path().expect("binary path should resolve"); if let Some(parent) = binary.parent() { diff --git a/src/mcp/configure.rs b/src/mcp/configure.rs index 2f5500eb..4ac663d5 100644 --- a/src/mcp/configure.rs +++ b/src/mcp/configure.rs @@ -31,7 +31,16 @@ fn destination(client: McpClient, local: bool) -> Result { let base = if local { std::env::current_dir()? } else { - dirs::home_dir().context("Home directory unavailable")? + // Windows' shell API ignores a process-local USERPROFILE override. + // Honor it so configuration follows the selected profile, including tests. + #[cfg(windows)] + let home = std::env::var_os("USERPROFILE") + .filter(|value| !value.is_empty()) + .map(PathBuf::from) + .or_else(dirs::home_dir); + #[cfg(not(windows))] + let home = dirs::home_dir(); + home.context("Home directory unavailable")? } .canonicalize()?; if !local { diff --git a/src/skills/tests.rs b/src/skills/tests.rs index e1a3b968..7aacfd49 100644 --- a/src/skills/tests.rs +++ b/src/skills/tests.rs @@ -11,7 +11,9 @@ use tempfile::TempDir; use super::loader::load_skills; use super::model::{allowed_tool_set, RuleId, Severity, Violation}; use super::report::{render, ReportFormat}; -use super::rules::{rule_r18, rule_r19, rule_r20, rule_r21, run_all, RuleContext}; +use super::rules::{rule_r18, rule_r19, run_all, RuleContext}; +#[cfg(unix)] +use super::rules::{rule_r20, rule_r21}; use super::runner::{discover_root, lint, LintOptions, LintOutcome}; const VALID_DESC: &str = "Manage Unity prefab assets with unity-cli. Use when the user asks to create a prefab from a scene object or open a prefab in edit mode. Do not use for general scene object editing; use `unity-gameobject-edit` instead."; diff --git a/tests/mcp.rs b/tests/mcp.rs index 25979403..6b7af6b0 100644 --- a/tests/mcp.rs +++ b/tests/mcp.rs @@ -186,6 +186,11 @@ fn configure_all_clients_preserves_other_servers_and_dry_run() { "{client}: {}", String::from_utf8_lossy(&preview.stderr) ); + assert!( + String::from_utf8_lossy(&preview.stdout) + .contains(dir.path().canonicalize().unwrap().to_str().unwrap()), + "{client}: preview must target the isolated configuration directory" + ); assert!(String::from_utf8_lossy(&preview.stdout).contains("+")); assert_eq!(std::fs::read_to_string(&path).unwrap(), before); let write = run(false); @@ -195,6 +200,15 @@ fn configure_all_clients_preserves_other_servers_and_dry_run() { String::from_utf8_lossy(&write.stderr) ); let after = std::fs::read_to_string(&path).unwrap(); + if !toml { + let configured: Value = serde_json::from_str(&after).unwrap(); + let key = if client == "vscode" { + "servers" + } else { + "mcpServers" + }; + assert_eq!(configured[key]["unity-cli"]["command"], "unity-cli"); + } assert!(after.contains("keep")); assert!(after.contains("unity-cli")); assert!( diff --git a/tests/setup_dry_run.rs b/tests/setup_dry_run.rs index 9374bbb7..67c8c3c9 100644 --- a/tests/setup_dry_run.rs +++ b/tests/setup_dry_run.rs @@ -27,6 +27,91 @@ fn drain(mut pipe: impl Read + Send + 'static) -> std::thread::JoinHandle Date: Sun, 4 Oct 2026 06:00:34 +0900 Subject: [PATCH 05/73] fix(windows): validate Git skill links and observe E2E processes safely --- docs/verification/issue-386/README.md | 59 +++++++++++--- packaging/winget/README.md | 31 +++++++ .../0.18.1/akiojin.unity-cli.installer.yaml | 12 +++ .../akiojin.unity-cli.locale.en-US.yaml | 20 +++++ .../0.18.1/akiojin.unity-cli.yaml | 6 ++ scripts/bridge_auth.py | 35 +++++++- scripts/e2e-editor-lifecycle.py | 8 +- src/skills/rules.rs | 21 ++++- src/skills/tests.rs | 46 ++++++++++- tasks/lessons.md | 6 ++ tests/scripts/test_process_liveness.py | 81 +++++++++++++++++++ 11 files changed, 305 insertions(+), 20 deletions(-) create mode 100644 packaging/winget/README.md create mode 100644 packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.installer.yaml create mode 100644 packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.locale.en-US.yaml create mode 100644 packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.yaml create mode 100644 tests/scripts/test_process_liveness.py diff --git a/docs/verification/issue-386/README.md b/docs/verification/issue-386/README.md index 64fb274e..9c6d8755 100644 --- a/docs/verification/issue-386/README.md +++ b/docs/verification/issue-386/README.md @@ -11,16 +11,40 @@ MCP profile 修正後の [最終ソース・バイナリ SHA256](environment-fin **Overall: FAIL — Issue 全体は未完了。PR は未作成。** Windows の成功を Linux、通常の Domain Reload、winget 導入や原資料の全シナリオへ拡張しない。 +## 2026-10-04 の継続検証 + +前回の停止条件を解消する作業を継続した。Windows Git placeholder の参照を正しく検証する +修正後、native Cargo 全件は **607 PASS / 0 FAIL**、skills lint は **23 skills / 0 violations**。 +fmt / clippy と実 Unity の SceneHandlerTests 11件も成功した。 +公開23操作、実 Editor のモーダルによる GDI fallback、公開版 CLI の実 Editor ping を再実行した。 + +WSL Ubuntu 24.04 に各デスクトップ環境を導入し、実 CLI から grim / gnome-screenshot / +spectacle と X11 の import / scrot / maim で実 PNG を生成した。 +これらは応答しない TCP fixture を使う OS capture の検証で、Linux 実 Unity の成功とは区別する。 +公式 Linux Unity 6000.4.4f1 は展開・起動済みだが、ライセンスがなく exit 198 で停止した。 +Unity Hub 3.22.2 の checksum と起動を確認し、認証可能な環境を用意した。 + +winget 初回提出用の3ファイルを [packaging/winget](../../../packaging/winget/README.md) に用意し、 +`winget validate` が成功した。公開 source への提出・反映と `WINGET_TOKEN` 設定は未完了。 +正式 `verify.run` は再度1500秒待機して deferred。 +また、blocked 復旧用の `derive:true` が library のない本プロジェクトに `cargo test --workspace --lib` +を生成し、Cargo が `no library targets found` と拒否するツール側の問題も PM に報告した。 +派生記録の編集や空 library の追加による回避は行っていない。 + +スタッフ原資料の代替調査では #243–260 / #390–395 に、23操作以外の入力・bake・build・動画・ +Animation・InputActions・C# reference の確認項目があると分かった。原資料との一致は未確認で、 +Windows の追加検証を進めている。下記の旧605成功・1失敗などの証跡は初回検証の記録として残す。 + ## 受け入れ基準の実測状況 | AC | 結果 | 証跡・残る条件 | | --- | --- | --- | | 1: Windows lockfile / PID / 自動発見 | PASS | 実 Editor が `%USERPROFILE%\.unity-cli\editors` に発行した [lockfile(認証情報除去)](lockfiles.json)、`tasklist`、[自動発見](fresh-setup-summary.json)。 | | 2: 実 setup / Bridge 導入・接続 | PASS | 空の隔離プロジェクトで `setup --launch-editor --wait-secs 420` を実行。40.549秒、exit 0、`projectMatches: true`。[結果](setup.stdout.json)、[実行時間と ping](fresh-setup-summary.json)。dry-run ではない。 | -| 3: 証跡の Issue / PR 記録 | PASS | 本資料と [Issue コメント](https://github.com/akiojin/unity-cli/issues/386#issuecomment-5970471700) に成功・失敗・未検証条件を記録。全件ゲート未通過のため PR 未作成。 | -| 4: Windows / Linux OS フォールバック | Windows PASS / Linux 未検証 | 実 Editor の `EditorUtility.DisplayDialog` でメインスレッドを止め、PowerShell + GDI の OS キャプチャが成功。Linux の実 Editor と Wayland/X11 キャプチャツールは本環境で揃わない。 | +| 3: 証跡の Issue / PR 記録 | PASS | 本資料と [Issue コメント](https://github.com/akiojin/unity-cli/issues/386#issuecomment-5970471700) に成功・失敗・未検証条件を記録。正式検証記録が未取得のため PR 未作成。 | +| 4: Windows / Linux OS フォールバック | Windows PASS / Linux 部分 | Windows 実 Editor のモーダルで PowerShell + GDI が成功。Linux Wayland / X11 の6ツールは実 PNG 生成成功、Linux 実 Editor はライセンス認証待ち。 | | 5: スタッフ原資料の全シナリオ・比較表 | 部分 | 公開済み23操作は既存比較と同じ設定で23/23 PASS。[一覧](staff-final-operations.json)。原資料 `pm-scratch/staff-report.md` は未取得。公式 CLI の Windows 比較・原資料との網羅性確認は未実施。 | -| 6: 公開 install.ps1 / winget / ping | PowerShell PASS / winget 未検証 | 公開 installer で Release 0.18.1 を隔離 tools root へ導入し、実 Editor に ping 成功。winget source に `akiojin.unity-cli` がなく、repository に `WINGET_TOKEN` もない。 | +| 6: 公開 install.ps1 / winget / ping | PowerShell PASS / winget 未検証 | 公開 installer と実 Editor ping 成功。初回 manifest の validate 成功。公開 package / `WINGET_TOKEN` がなく、winget install / ping は未実施。 | ## 実機で発見して修正した問題 @@ -39,9 +63,6 @@ Windows の成功を Linux、通常の Domain Reload、winget 導入や原資料 AssetDatabase に渡す前に区切り文字を `/` に揃えた。 深いフォルダへの作成・保存の回帰テストを追加し、実 Unity で RED → GREEN を確認した。 -Windows の clippy で検出された既存の Unix 専用テストの未使用 import / helper には -`cfg(unix)` を付けた。LSP の動作変更はない。 - 4. 全件検証で MCP configure の Windows profile 解決も確認した。 `dirs::home_dir` の Windows shell API はプロセスの `USERPROFILE` 上書きを参照しないため、 Windsurf の設定テストが実ユーザープロファイルへ書き込んでいた。 @@ -52,6 +73,21 @@ Windows の clippy で検出された既存の Unix 専用テストの未使用 今回生成された実プロファイルの設定ファイルは、内容・SHA256・作成時刻で検証実行の生成物と 確認して削除した。[削除前のメタデータと削除結果](profile-audit.json)。 +5. Windows の `core.symlinks=false` checkout は、Git の symlink を参照先文字列の + 通常ファイルとして展開する。skills lint はこの正規の展開形式を誤った参照先と扱っていた。 + Windows ではこの相対参照を解決し、従来どおり canonical skill の実ディレクトリと照合する。 + 欠落・異なる skill・存在しない参照先・複数行の不正ファイルは回帰テストで拒否を確認した。 + checkout ファイル、Git index、Developer Mode の設定は変更していない。 + +Windows の clippy で検出された既存の Unix 専用テストの未使用 import / helper には +`cfg(unix)` を付けた。LSP の動作変更はない。 + +Windows の Python E2E helper も修正した。`os.kill(pid, 0)` は Windows では Unix の +生存確認と異なり、コンソール制御イベントになる。終了済み PID を生存扱いする RED を確認した。 +`OpenProcess(SYNCHRONIZE)` と `WaitForSingleObject(0)` に置き換え、実行中の子が終了しないこと、 +終了済み・無効 PID の拒否、終了コード259の判定を Windows native の4テストで確認した。 +既存 authentication の3テストと Linux の回帰テストも成功した。 + ## Windows OS キャプチャ 実 Editor PID 44232 に同期 `EditorUtility.DisplayDialog("Issue386FallbackProbe", ...)` を開き、 @@ -103,7 +139,7 @@ Release 0.18.1 の Windows バイナリを SHA256SUMS 検証後に導入し、 [repository secret の名前一覧](repository-secret-names.json) に `WINGET_TOKEN` はない。 トークン値は読み取っていない。winget での install / ping、初回公開提出とトークン設定は未実施。 -## Verification Report +## 初回の Verification Report(履歴) Mode: full。Launch mode: interactive (`launch_route: manual`)。 Baseline: `origin/develop` / HEAD `338f426119b61123567b74028e7e8fe3bd99caa5`。 @@ -147,8 +183,7 @@ Agent Visual Check: n/a(CLI と Editor 連携を検証。Web/TUI の表示変 ## 再開条件 -1. Windows checkout の正規 skill リンクを作成できる実行環境で、全件 test / lint を再実行する。 -2. 原資料 `pm-scratch/staff-report.md` の所在を確認し、公開23操作との差分を検証する。 -3. Linux の実 Unity Editor と Wayland / X11 のキャプチャ環境で AC-4 を実行する。 -4. winget 初回公開の担当と `WINGET_TOKEN` の設定を確定し、公開 source から install / ping を検証する。 -5. 共通検証枠を確保し、正式な自動ゲートと必要なユーザー確認が通ってから Ready PR を作成する。 +1. 原資料 `pm-scratch/staff-report.md` の所在を確認し、追加した Windows 検証との網羅性を照合する。 +2. 用意した Linux Editor / Unity Hub でライセンス認証し、実 Editor を含む AC-4 を実行する。 +3. winget 初回公開と `WINGET_TOKEN` の設定を行い、公開 source から install / ping を検証する。 +4. 派生検証の binary-only Cargo 対応と共通検証枠を確保し、正式記録と必要なユーザー確認後に Ready PR を作成する。 diff --git a/packaging/winget/README.md b/packaging/winget/README.md new file mode 100644 index 00000000..d1cc9d64 --- /dev/null +++ b/packaging/winget/README.md @@ -0,0 +1,31 @@ +# winget 初回公開用 manifest + +`akiojin.unity-cli/0.18.1/` は公開 Release v0.18.1 の Windows x64 portable +バイナリを対象にした初回提出用の3ファイル manifest です。 +InstallerSha256 は GitHub Release の asset digest と、インストーラで検証済みの +バイナリの SHA256 に一致します。 + +```powershell +winget validate --manifest packaging/winget/akiojin.unity-cli/0.18.1 +``` + +提出先は microsoft/winget-pkgs の +`manifests/a/akiojin/unity-cli/0.18.1/` です。公開 source への登録はまだ完了していません。 +[Microsoft の提出手順](https://learn.microsoft.com/en-us/windows/package-manager/package/repository) +に沿って、この3ファイルだけを初回 package PR に含めます。 + +後続リリースの自動更新には repository secret `WINGET_TOKEN` が必要です。 +既存の release workflow の `update-winget` job がこの secret を使います。 +[Microsoft の認証手順](https://github.com/microsoft/winget-create/blob/main/doc/token.md) +を参照し、公開リポジトリへ提出できる資格情報を設定します。トークン値は証跡や +コマンドライン引数に残さないでください。 + +公開 source への反映後に、次を実 Windows と開いた検証用 Editor で確認します。 + +```powershell +winget install --id akiojin.unity-cli --exact --source winget --scope user +unity-cli --version +unity-cli --port 6487 system ping +``` + +ローカル manifest の validate 成功は、公開 source からの install 成功とは別の証跡です。 diff --git a/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.installer.yaml b/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.installer.yaml new file mode 100644 index 00000000..8d0209e1 --- /dev/null +++ b/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.installer.yaml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.12.0.schema.json +PackageIdentifier: akiojin.unity-cli +PackageVersion: 0.18.1 +InstallerType: portable +Commands: + - unity-cli +Installers: + - Architecture: x64 + InstallerUrl: https://github.com/akiojin/unity-cli/releases/download/v0.18.1/unity-cli-win-x64.exe + InstallerSha256: EFCD697B940F78B6457829453888D9C608F19D2FCD331D0005B1FF47A7839357 +ManifestType: installer +ManifestVersion: 1.12.0 diff --git a/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.locale.en-US.yaml b/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.locale.en-US.yaml new file mode 100644 index 00000000..4d49bfe7 --- /dev/null +++ b/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.locale.en-US.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.12.0.schema.json +PackageIdentifier: akiojin.unity-cli +PackageVersion: 0.18.1 +PackageLocale: en-US +Publisher: akiojin +PublisherUrl: https://github.com/akiojin +PublisherSupportUrl: https://github.com/akiojin/unity-cli/issues +PackageName: unity-cli +PackageUrl: https://github.com/akiojin/unity-cli +License: MIT +LicenseUrl: https://github.com/akiojin/unity-cli/blob/v0.18.1/LICENSE +ShortDescription: CLI for Unity Editor automation over the Unity TCP protocol +Moniker: unity-cli +Tags: + - automation + - unity + - unity-editor +ReleaseNotesUrl: https://github.com/akiojin/unity-cli/releases/tag/v0.18.1 +ManifestType: defaultLocale +ManifestVersion: 1.12.0 diff --git a/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.yaml b/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.yaml new file mode 100644 index 00000000..7e9a55c2 --- /dev/null +++ b/packaging/winget/akiojin.unity-cli/0.18.1/akiojin.unity-cli.yaml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.12.0.schema.json +PackageIdentifier: akiojin.unity-cli +PackageVersion: 0.18.1 +DefaultLocale: en-US +ManifestType: version +ManifestVersion: 1.12.0 diff --git a/scripts/bridge_auth.py b/scripts/bridge_auth.py index 8032d07f..279e9c43 100644 --- a/scripts/bridge_auth.py +++ b/scripts/bridge_auth.py @@ -4,6 +4,38 @@ from pathlib import Path +def process_alive(pid): + """Observe a process without sending Windows console-control events.""" + if pid <= 0 or pid > 0xFFFFFFFF: + return False + if os.name == "nt": + import ctypes + from ctypes import wintypes + + kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) + kernel32.OpenProcess.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.DWORD] + kernel32.OpenProcess.restype = wintypes.HANDLE + kernel32.WaitForSingleObject.argtypes = [wintypes.HANDLE, wintypes.DWORD] + kernel32.WaitForSingleObject.restype = wintypes.DWORD + kernel32.CloseHandle.argtypes = [wintypes.HANDLE] + kernel32.CloseHandle.restype = wintypes.BOOL + handle = kernel32.OpenProcess(0x00100000, False, pid) # SYNCHRONIZE only + if not handle: + return ctypes.get_last_error() == 5 # Access denied to an existing process + try: + state = kernel32.WaitForSingleObject(handle, 0) + if state == 0xFFFFFFFF: # WAIT_FAILED + raise ctypes.WinError(ctypes.get_last_error()) + return state == 258 # WAIT_TIMEOUT: the process has not exited + finally: + kernel32.CloseHandle(handle) + try: + os.kill(pid, 0) + return True + except (ProcessLookupError, OverflowError): + return False + + def auth_fields(port, editors_dir=None, pid=None): folder = Path(editors_dir or os.environ.get("UNITY_CLI_EDITORS_DIR", Path.home() / ".unity-cli/editors")) matches = [] @@ -19,7 +51,8 @@ def auth_fields(port, editors_dir=None, pid=None): or int(lock.get("port", 0)) != int(port) or not isinstance(token, str) or not token): continue - os.kill(editor_pid, 0) + if not process_alive(editor_pid): + continue matches.append(token) except (OSError, ValueError, TypeError): continue diff --git a/scripts/e2e-editor-lifecycle.py b/scripts/e2e-editor-lifecycle.py index 6c24d951..4d83ae20 100644 --- a/scripts/e2e-editor-lifecycle.py +++ b/scripts/e2e-editor-lifecycle.py @@ -10,15 +10,13 @@ import tempfile import time +from bridge_auth import process_alive + ROOT = Path(__file__).resolve().parents[1] def alive(pid): - try: - os.kill(pid, 0) - return True - except ProcessLookupError: - return False + return process_alive(pid) def data(value): diff --git a/src/skills/rules.rs b/src/skills/rules.rs index 39063315..ddb2b686 100644 --- a/src/skills/rules.rs +++ b/src/skills/rules.rs @@ -576,6 +576,25 @@ pub fn rule_r21(skill: &Skill, ctx: &RuleContext<'_>) -> Vec { check_symlink(skill, &link, RuleId::R21AgentsSymlink) } +fn canonical_skill_link(link: &Path) -> std::io::Result { + #[cfg(windows)] + if link.is_file() && !link.is_symlink() { + // Git with core.symlinks=false checks out a symlink as a file containing + // its relative target. Validate that target against the canonical skill + // below, without requiring Developer Mode or changing checkout files. + let text = fs::read_to_string(link)?; + let target = Path::new(&text); + if !text.is_empty() && !text.chars().any(char::is_control) && target.is_relative() { + return link + .parent() + .unwrap_or(Path::new(".")) + .join(target) + .canonicalize(); + } + } + link.canonicalize() +} + fn check_symlink(skill: &Skill, link: &Path, rule: RuleId) -> Vec { if !link.exists() && !link.is_symlink() { return vec![Violation::new( @@ -586,7 +605,7 @@ fn check_symlink(skill: &Skill, link: &Path, rule: RuleId) -> Vec { format!("symlink `{}` is missing", link.display()), )]; } - let target = match link.canonicalize() { + let target = match canonical_skill_link(link) { Ok(p) => p, Err(_) => { return vec![Violation::new( diff --git a/src/skills/tests.rs b/src/skills/tests.rs index 7aacfd49..a389ef78 100644 --- a/src/skills/tests.rs +++ b/src/skills/tests.rs @@ -12,7 +12,6 @@ use super::loader::load_skills; use super::model::{allowed_tool_set, RuleId, Severity, Violation}; use super::report::{render, ReportFormat}; use super::rules::{rule_r18, rule_r19, run_all, RuleContext}; -#[cfg(unix)] use super::rules::{rule_r20, rule_r21}; use super::runner::{discover_root, lint, LintOptions, LintOutcome}; @@ -574,6 +573,51 @@ fn r20_and_r21_symlink_rules_cover_missing_and_valid_targets() { assert!(rule_r21(skill, &ctx).is_empty()); } +#[cfg(windows)] +#[test] +fn r20_and_r21_validate_windows_git_symlink_placeholders() { + let tmp = TempDir::new().unwrap(); + write_skill( + tmp.path(), + "unity-symlinked", + &valid_frontmatter("unity-symlinked"), + &valid_body(), + ); + write_skill( + tmp.path(), + "unity-gameobject-edit", + &sibling_frontmatter("unity-gameobject-edit", "unity-symlinked"), + &valid_body(), + ); + let skills = load_skills(tmp.path()).unwrap(); + let skill = skills.iter().find(|s| s.name == "unity-symlinked").unwrap(); + let ctx = RuleContext { + skills: &skills, + repo_root: tmp.path(), + }; + type Check = fn(&super::model::Skill, &RuleContext<'_>) -> Vec; + for (parent, rule) in [ + (".claude/skills", rule_r20 as Check), + (".agents/skills", rule_r21 as Check), + ] { + let parent = tmp.path().join(parent); + fs::create_dir_all(&parent).unwrap(); + let link = parent.join("unity-symlinked"); + assert!(!rule(skill, &ctx).is_empty(), "missing placeholder"); + fs::write(&link, "../../unity-symlinked").unwrap(); + assert!(rule(skill, &ctx).is_empty(), "valid Git placeholder"); + for invalid in [ + "../../unity-gameobject-edit", + "../../missing-skill", + "../../unity-symlinked\nadditional content", + "", + ] { + fs::write(&link, invalid).unwrap(); + assert!(!rule(skill, &ctx).is_empty(), "accepted {invalid:?}"); + } + } +} + #[test] fn report_and_runner_cover_text_json_discovery_and_error_paths() { let tmp = TempDir::new().unwrap(); diff --git a/tasks/lessons.md b/tasks/lessons.md index e66ceee5..e6e8ba62 100644 --- a/tasks/lessons.md +++ b/tasks/lessons.md @@ -10,6 +10,12 @@ ## Entries +### 2026-10-04 — #386 環境不足の解消を先に試す + +- Context: 実機検証を一部完了後、ユーザーから「全部終わらせて」と継続を指示された。 +- Rule: ツール未導入やリンク作成エラーを即座に最終 blocker にせず、管理者不要の代替、隔離インストール、既存認証、原資料の別保存先を試す。成功条件を緩めたり、未実施を PASS にしたりはしない。 +- Checkpoint: 実行可能な残作業を完了し、外部入力が必須な条件だけ具体的な場所・認証・結果とともに残す。Markdown を含む gwtd body は literal JSON ファイルから渡し、shell の command substitution を起こさない。 + ### 2026-02-27 - Context: Markdown Lint を `npm run lint:md` で実行した際、ローカルに `markdownlint` が存在しなかった。 diff --git a/tests/scripts/test_process_liveness.py b/tests/scripts/test_process_liveness.py new file mode 100644 index 00000000..8d702b3d --- /dev/null +++ b/tests/scripts/test_process_liveness.py @@ -0,0 +1,81 @@ +"""Editor authentication and lifecycle probes must only observe processes.""" +import importlib.util +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(ROOT / "scripts")) +import bridge_auth + +spec = importlib.util.spec_from_file_location( + "editor_lifecycle", ROOT / "scripts/e2e-editor-lifecycle.py") +lifecycle = importlib.util.module_from_spec(spec) +spec.loader.exec_module(lifecycle) + + +class ProcessLivenessTests(unittest.TestCase): + def child(self, code): + process = subprocess.Popen( + [sys.executable, "-c", code], stdout=subprocess.PIPE, + stderr=subprocess.PIPE, text=True) + + def cleanup(): + if process.poll() is None: + process.terminate() + process.communicate(timeout=10) + + self.addCleanup(cleanup) + return process + + def probe(self, kind, pid): + if kind == "lifecycle": + return lifecycle.alive(pid) + with tempfile.TemporaryDirectory() as directory: + (Path(directory) / "editor.json").write_text(json.dumps({ + "pid": pid, "host": "127.0.0.1", "port": 6540, + "authToken": "fixture-token"})) + return bool(bridge_auth.auth_fields(6540, directory)) + + def test_live_process_survives_authentication_and_lifecycle_probes(self): + for kind in ("auth", "lifecycle"): + with self.subTest(kind=kind): + process = self.child( + 'import time; print("ready", flush=True); time.sleep(60)') + self.assertEqual(process.stdout.readline().strip(), "ready") + self.assertTrue(self.probe(kind, process.pid)) + try: + process.wait(timeout=0.2) + except subprocess.TimeoutExpired: + pass + else: + self.fail(f"{kind} liveness probe terminated its live child") + + def test_exited_process_is_not_alive_or_eligible_for_authentication(self): + process = self.child("pass") + process.wait(timeout=10) + for kind in ("auth", "lifecycle"): + with self.subTest(kind=kind): + self.assertFalse(self.probe(kind, process.pid)) + + def test_invalid_process_ids_are_not_alive_or_eligible_for_authentication(self): + for kind in ("auth", "lifecycle"): + for pid in (0, -1, 0xFFFFFFFF, 0x100000000): + with self.subTest(kind=kind, pid=pid): + self.assertFalse(self.probe(kind, pid)) + + @unittest.skipUnless(os.name == "nt", "Windows process exit code contract") + def test_exit_code_still_active_does_not_mean_process_is_running(self): + process = self.child("import sys; sys.exit(259)") + self.assertEqual(process.wait(timeout=10), 259) + for kind in ("auth", "lifecycle"): + with self.subTest(kind=kind): + self.assertFalse(self.probe(kind, process.pid)) + + +if __name__ == "__main__": + unittest.main() From d0c5ce21d85d171b285162b06edff03acdef53c9 Mon Sep 17 00:00:00 2001 From: akiojin Date: Sun, 4 Oct 2026 09:10:08 +0900 Subject: [PATCH 06/73] fix(windows): repair reference fetch, bake validation and input verification --- Cargo.lock | 1 + Cargo.toml | 1 + .../Editor/Handlers/BakeHandler.cs | 2 +- .../Tests/Editor/Handlers/BakeHandlerTests.cs | 16 + .../InputSimulationAutomationPlayModeTests.cs | 16 +- .../PlayMode/TouchGesturePlayModeTests.cs | 9 + docs/comparison.md | 23 +- docs/hot-reload.md | 6 +- docs/verification/issue-386/README.md | 21 +- .../resume/AnimationCurveHandlerTests.xml | 522 +++ .../issue-386/resume/BakeHandlerTests.xml | 32 + .../resume/GamepadStickInputPlayModeTests.xml | 98 + .../resume/InputActionNotificationTests.xml | 104 + .../resume/InputActionsHandlerTests.xml | 38 + ...nAutomationPlayModeTests-counter-green.xml | 38 + ...ionAutomationPlayModeTests-counter-red.xml | 131 + ...InputSimulationAutomationPlayModeTests.xml | 366 ++ docs/verification/issue-386/resume/README.md | 98 + .../issue-386/resume/SceneHandlerTests.xml | 266 ++ .../TouchGesturePlayModeTests-fresh.xml | 29 + .../issue-386/resume/animation-curves.txt | 26 + .../resume/auth-warning-offline-green.txt | 8 + .../resume/bake-artifact-metadata.json | 67 + .../issue-386/resume/bake-fixed-final.txt | 35 + .../issue-386/resume/bake-fresh-0.txt | 11 + .../issue-386/resume/bake-headed-final.txt | 164 + .../issue-386/resume/bake-headed-result.json | 47 + .../issue-386/resume/bake-preview-green.xml | 3 + .../issue-386/resume/bake-preview-red.xml | 25 + .../issue-386/resume/batch-message-green.txt | 8 + .../issue-386/resume/batch-message-red.txt | 22 + .../resume/canonical-verify-second.txt | 2 + .../issue-386/resume/canonical-verify.txt | 8 + .../issue-386/resume/cargo-all-final.txt | 706 ++++ .../resume/cargo-test-inventory.json | 3057 +++++++++++++++++ .../resume/clippy-all-features-final.txt | 1 + docs/verification/issue-386/resume/clippy.txt | 2 + .../resume/comparison-unit-linux.txt | 20 + .../issue-386/resume/derived-lib-error.txt | 1 + .../issue-386/resume/domain-reload.json | 347 ++ .../issue-386/resume/domain-reload.txt | 3 + docs/verification/issue-386/resume/eval.txt | 21 + .../issue-386/resume/final-checks.json | 58 + .../issue-386/resume/final-doc-checks.json | 45 + .../resume/final-markdown-check.json | 16 + docs/verification/issue-386/resume/fmt.txt | 1 + .../issue-386/resume/fresh-play-results.json | 56 + .../issue-386/resume/fsr-package.json | 9 + .../issue-386/resume/hot-reload-results.txt | 28 + .../issue-386/resume/hot-reload-summary.json | 49 + .../resume/input-actions-persistence.txt | 54 + .../issue-386/resume/input-counter-green.json | 25 + .../issue-386/resume/input-counter-green.txt | 2 + .../issue-386/resume/input-counter-red.json | 25 + .../issue-386/resume/input-counter-red.txt | 3 + .../resume/linux-gnome-fallback-result.json | 34 + .../issue-386/resume/linux-license.json | 7 + .../resume/linux-wayland-extra-results.json | 35 + .../resume/linux-wayland-first-results.json | 60 + .../issue-386/resume/linux-x11-platform.txt | 14 + .../issue-386/resume/markdownlint-final.txt | 4 + .../resume/mcp-live-editor-green.txt | 10 + .../issue-386/resume/modal-summary.json | 49 + .../issue-386/resume/more-e2e-results.json | 255 ++ .../resume/official-windows-binary.json | 11 + .../official-windows-comparison-resident.txt | 23 + .../resume/official-windows-comparison.txt | 9 + .../official-windows-process-background.json | 725 ++++ .../official-windows-process-frontmost.json | 724 ++++ ...sident-frontmost-search-array-failure.json | 47 + .../official-windows-resident-frontmost.json | 47 + .../resume/official-windows-summary.json | 61 + .../issue-386/resume/prefab-results.json | 17 + docs/verification/issue-386/resume/prefab.txt | 65 + .../resume/process-liveness-final.txt | 9 + .../issue-386/resume/python-linux.txt | 9 + .../issue-386/resume/python-windows.txt | 9 + .../issue-386/resume/reference-auth-green.txt | 9 + .../resume/reference-auth-probe.json | 27 + .../issue-386/resume/reference-auth-red.txt | 21 + .../resume/reference-fetch-summary.json | 26 + .../issue-386/resume/reference-fetch.txt | 8 + .../resume/reference-longpath-green.txt | 8 + .../resume/reference-longpath-red.txt | 22 + .../resume/reference-resolution-summary.json | 22 + .../issue-386/resume/reference-resolution.txt | 6 + .../issue-386/resume/rustdoc-final.txt | 3 + .../issue-386/resume/skills-lint-final.txt | 5 + .../issue-386/resume/source-snapshot.json | 35 + .../resume/staff-binary-environment.json | 26 + .../issue-386/resume/staff-extra-results.json | 126 + .../resume/staff-final-operations.json | 140 + .../issue-386/resume/staff-final-summary.json | 646 ++++ .../resume/staff-scope-reconstruction.md | 144 + .../issue-386/resume/timeline.txt | 42 + .../issue-386/resume/video-formats.txt | 13 + .../issue-386/resume/video-summary.json | 8 + .../resume/windows-comparison-adapter.py | 177 + .../resume/windows-player-graphical.json | 26 + .../resume/windows-player-result.json | 231 ++ .../resume/winget-manifest-validate.txt | 1 + scripts/bench-compare-official.py | 2 +- src/core/failure.rs | 30 +- src/reference/fetcher.rs | 110 +- tasks/lessons.md | 7 + tests/auth_warning.rs | 2 +- tests/mcp.rs | 5 +- 107 files changed, 10893 insertions(+), 31 deletions(-) create mode 100644 docs/verification/issue-386/resume/AnimationCurveHandlerTests.xml create mode 100644 docs/verification/issue-386/resume/BakeHandlerTests.xml create mode 100644 docs/verification/issue-386/resume/GamepadStickInputPlayModeTests.xml create mode 100644 docs/verification/issue-386/resume/InputActionNotificationTests.xml create mode 100644 docs/verification/issue-386/resume/InputActionsHandlerTests.xml create mode 100644 docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-green.xml create mode 100644 docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-red.xml create mode 100644 docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests.xml create mode 100644 docs/verification/issue-386/resume/README.md create mode 100644 docs/verification/issue-386/resume/SceneHandlerTests.xml create mode 100644 docs/verification/issue-386/resume/TouchGesturePlayModeTests-fresh.xml create mode 100644 docs/verification/issue-386/resume/animation-curves.txt create mode 100644 docs/verification/issue-386/resume/auth-warning-offline-green.txt create mode 100644 docs/verification/issue-386/resume/bake-artifact-metadata.json create mode 100644 docs/verification/issue-386/resume/bake-fixed-final.txt create mode 100644 docs/verification/issue-386/resume/bake-fresh-0.txt create mode 100644 docs/verification/issue-386/resume/bake-headed-final.txt create mode 100644 docs/verification/issue-386/resume/bake-headed-result.json create mode 100644 docs/verification/issue-386/resume/bake-preview-green.xml create mode 100644 docs/verification/issue-386/resume/bake-preview-red.xml create mode 100644 docs/verification/issue-386/resume/batch-message-green.txt create mode 100644 docs/verification/issue-386/resume/batch-message-red.txt create mode 100644 docs/verification/issue-386/resume/canonical-verify-second.txt create mode 100644 docs/verification/issue-386/resume/canonical-verify.txt create mode 100644 docs/verification/issue-386/resume/cargo-all-final.txt create mode 100644 docs/verification/issue-386/resume/cargo-test-inventory.json create mode 100644 docs/verification/issue-386/resume/clippy-all-features-final.txt create mode 100644 docs/verification/issue-386/resume/clippy.txt create mode 100644 docs/verification/issue-386/resume/comparison-unit-linux.txt create mode 100644 docs/verification/issue-386/resume/derived-lib-error.txt create mode 100644 docs/verification/issue-386/resume/domain-reload.json create mode 100644 docs/verification/issue-386/resume/domain-reload.txt create mode 100644 docs/verification/issue-386/resume/eval.txt create mode 100644 docs/verification/issue-386/resume/final-checks.json create mode 100644 docs/verification/issue-386/resume/final-doc-checks.json create mode 100644 docs/verification/issue-386/resume/final-markdown-check.json create mode 100644 docs/verification/issue-386/resume/fmt.txt create mode 100644 docs/verification/issue-386/resume/fresh-play-results.json create mode 100644 docs/verification/issue-386/resume/fsr-package.json create mode 100644 docs/verification/issue-386/resume/hot-reload-results.txt create mode 100644 docs/verification/issue-386/resume/hot-reload-summary.json create mode 100644 docs/verification/issue-386/resume/input-actions-persistence.txt create mode 100644 docs/verification/issue-386/resume/input-counter-green.json create mode 100644 docs/verification/issue-386/resume/input-counter-green.txt create mode 100644 docs/verification/issue-386/resume/input-counter-red.json create mode 100644 docs/verification/issue-386/resume/input-counter-red.txt create mode 100644 docs/verification/issue-386/resume/linux-gnome-fallback-result.json create mode 100644 docs/verification/issue-386/resume/linux-license.json create mode 100644 docs/verification/issue-386/resume/linux-wayland-extra-results.json create mode 100644 docs/verification/issue-386/resume/linux-wayland-first-results.json create mode 100644 docs/verification/issue-386/resume/linux-x11-platform.txt create mode 100644 docs/verification/issue-386/resume/markdownlint-final.txt create mode 100644 docs/verification/issue-386/resume/mcp-live-editor-green.txt create mode 100644 docs/verification/issue-386/resume/modal-summary.json create mode 100644 docs/verification/issue-386/resume/more-e2e-results.json create mode 100644 docs/verification/issue-386/resume/official-windows-binary.json create mode 100644 docs/verification/issue-386/resume/official-windows-comparison-resident.txt create mode 100644 docs/verification/issue-386/resume/official-windows-comparison.txt create mode 100644 docs/verification/issue-386/resume/official-windows-process-background.json create mode 100644 docs/verification/issue-386/resume/official-windows-process-frontmost.json create mode 100644 docs/verification/issue-386/resume/official-windows-resident-frontmost-search-array-failure.json create mode 100644 docs/verification/issue-386/resume/official-windows-resident-frontmost.json create mode 100644 docs/verification/issue-386/resume/official-windows-summary.json create mode 100644 docs/verification/issue-386/resume/prefab-results.json create mode 100644 docs/verification/issue-386/resume/prefab.txt create mode 100644 docs/verification/issue-386/resume/process-liveness-final.txt create mode 100644 docs/verification/issue-386/resume/python-linux.txt create mode 100644 docs/verification/issue-386/resume/python-windows.txt create mode 100644 docs/verification/issue-386/resume/reference-auth-green.txt create mode 100644 docs/verification/issue-386/resume/reference-auth-probe.json create mode 100644 docs/verification/issue-386/resume/reference-auth-red.txt create mode 100644 docs/verification/issue-386/resume/reference-fetch-summary.json create mode 100644 docs/verification/issue-386/resume/reference-fetch.txt create mode 100644 docs/verification/issue-386/resume/reference-longpath-green.txt create mode 100644 docs/verification/issue-386/resume/reference-longpath-red.txt create mode 100644 docs/verification/issue-386/resume/reference-resolution-summary.json create mode 100644 docs/verification/issue-386/resume/reference-resolution.txt create mode 100644 docs/verification/issue-386/resume/rustdoc-final.txt create mode 100644 docs/verification/issue-386/resume/skills-lint-final.txt create mode 100644 docs/verification/issue-386/resume/source-snapshot.json create mode 100644 docs/verification/issue-386/resume/staff-binary-environment.json create mode 100644 docs/verification/issue-386/resume/staff-extra-results.json create mode 100644 docs/verification/issue-386/resume/staff-final-operations.json create mode 100644 docs/verification/issue-386/resume/staff-final-summary.json create mode 100644 docs/verification/issue-386/resume/staff-scope-reconstruction.md create mode 100644 docs/verification/issue-386/resume/timeline.txt create mode 100644 docs/verification/issue-386/resume/video-formats.txt create mode 100644 docs/verification/issue-386/resume/video-summary.json create mode 100644 docs/verification/issue-386/resume/windows-comparison-adapter.py create mode 100644 docs/verification/issue-386/resume/windows-player-graphical.json create mode 100644 docs/verification/issue-386/resume/windows-player-result.json create mode 100644 docs/verification/issue-386/resume/winget-manifest-validate.txt diff --git a/Cargo.lock b/Cargo.lock index 5972bb11..2518956d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2670,6 +2670,7 @@ name = "unity-cli" version = "0.18.1" dependencies = [ "anyhow", + "base64 0.22.1", "bincode", "clap", "dirs 7.0.0", diff --git a/Cargo.toml b/Cargo.toml index edbfb2cb..f0ff0b7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ path = "src/main.rs" [dependencies] anyhow = "1.0" +base64 = "0.22" clap = { version = "4.6", features = ["derive"] } dirs = "7.0" serde = { version = "1.0", features = ["derive"] } diff --git a/UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/BakeHandler.cs b/UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/BakeHandler.cs index 2bcd15d3..29d2c7a9 100644 --- a/UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/BakeHandler.cs +++ b/UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/BakeHandler.cs @@ -77,7 +77,7 @@ public static object StartBake(JObject args) string path = args?["scenePath"]?.Value(); if (string.IsNullOrEmpty(path) || !path.StartsWith("Assets/", StringComparison.Ordinal) || !path.EndsWith(".unity", StringComparison.Ordinal) || path != scene.path || !File.Exists(path)) return Error("SCENE_MISMATCH", "scenePath must identify the saved active scene under Assets/."); - if (SceneManager.sceneCount != 1 || EditorSceneManager.previewSceneCount != 0) + if (SceneManager.sceneCount != 1 || EditorSceneManager.IsPreviewScene(scene)) return Error("MULTIPLE_SCENES", "Load only the target scene before baking."); if (scene.isDirty) return Error("SCENE_DIRTY", "Save the scene before baking."); Component surface = null; diff --git a/UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/BakeHandlerTests.cs b/UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/BakeHandlerTests.cs index a3b4562d..f76416bb 100644 --- a/UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/BakeHandlerTests.cs +++ b/UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/BakeHandlerTests.cs @@ -133,6 +133,22 @@ [Test] public void AdditiveSceneIsRejectedWithoutSwitchingActiveScene() Assert.That(UnityEngine.SceneManagement.SceneManager.GetActiveScene(), Is.EqualTo(original)); } + [Test] public void PreviewSceneDoesNotBlockSavedScene() + { + var preview = EditorSceneManager.NewPreviewScene(); + try + { + Assert.That(UnityEngine.SceneManagement.SceneManager.sceneCount, Is.EqualTo(1)); + Assert.That(EditorSceneManager.previewSceneCount, Is.GreaterThan(0)); + var accepted = QueueBake(); + Assert.That((string)accepted["status"], Is.EqualTo("running"), accepted.ToString()); + } + finally + { + EditorSceneManager.ClosePreviewScene(preview); + } + } + [Test] public void DirtySceneIsRejected() { EditorSceneManager.MarkSceneDirty(UnityEngine.SceneManagement.SceneManager.GetActiveScene()); diff --git a/UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/InputSimulationAutomationPlayModeTests.cs b/UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/InputSimulationAutomationPlayModeTests.cs index 53b3bcbe..bd1cffc2 100644 --- a/UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/InputSimulationAutomationPlayModeTests.cs +++ b/UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/InputSimulationAutomationPlayModeTests.cs @@ -458,7 +458,21 @@ private static string GetStatusText() private static int GetStatusInt(string key) { - var match = Regex.Match(GetStatusText(), "^" + Regex.Escape(key) + "=(\\d+)$", RegexOptions.Multiline); + return ParseStatusInt(GetStatusText(), key); + } + + [TestCase("MouseReleases=1\r\n", "MouseReleases", 1)] + [TestCase("TouchPresses=2\nTouchReleases=1\n", "TouchReleases", 1)] + [TestCase("MouseReleases=1", "MouseReleases", 1)] + [TestCase("MouseReleases=1\r\n", "TouchReleases", 0)] + public void StatusCounterParser_HandlesLineEndings(string status, string key, int expected) + { + Assert.That(ParseStatusInt(status, key), Is.EqualTo(expected)); + } + + private static int ParseStatusInt(string status, string key) + { + var match = Regex.Match(status, "^" + Regex.Escape(key) + "=(\\d+)\\r?$", RegexOptions.Multiline); return match.Success ? int.Parse(match.Groups[1].Value) : 0; } } diff --git a/UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/TouchGesturePlayModeTests.cs b/UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/TouchGesturePlayModeTests.cs index e088ea6b..66fec0e6 100644 --- a/UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/TouchGesturePlayModeTests.cs +++ b/UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/TouchGesturePlayModeTests.cs @@ -66,6 +66,7 @@ public sealed class TouchGesturePlayModeTests public void SetUp() { Assert.IsTrue(Application.isPlaying); + Application.logMessageReceived += ExpectBridgeConnectionLog; previousFrameRate = Application.targetFrameRate; previousVSync = QualitySettings.vSyncCount; previousRunInBackground = Application.runInBackground; @@ -105,6 +106,14 @@ public IEnumerator TearDown() InputSystem.settings.editorInputBehaviorInPlayMode = previousEditorInputBehavior; InputSystem.settings.updateMode = previousUpdateMode; Time.fixedDeltaTime = previousFixedDeltaTime; + Application.logMessageReceived -= ExpectBridgeConnectionLog; + } + + private static void ExpectBridgeConnectionLog(string message, string stackTrace, LogType type) + { + if (type == LogType.Log && System.Text.RegularExpressions.Regex.IsMatch(message, + @"^\[unity-cli-bridge\] Client connected from 127\.0\.0\.1:\d+$")) + LogAssert.Expect(type, message); } [UnityTest] diff --git a/docs/comparison.md b/docs/comparison.md index d88fa589..54ee44d5 100644 --- a/docs/comparison.md +++ b/docs/comparison.md @@ -46,9 +46,17 @@ Each table row links to its evidence: Windows validation was added separately in [Issue #386 evidence](verification/issue-386/README.md): CLI / Bridge 0.18.1 with Unity 6000.4.4f1 verified real setup, lockfile discovery, OS screenshot fallback during an Editor modal, and all 23 listed operations with -DisableDomainReload / PlayUnfocused. The official CLI was not rerun on Windows; -the timings below remain macOS measurements. Normal Domain Reload still produced -connection errors, and Linux, winget and the original staff report remain unverified. +DisableDomainReload / PlayUnfocused. A separate Windows comparison with official CLI +1.0.0-beta.11 and Pipeline 0.8.0-exp.1 measured 100 process samples per operation +with the Editor frontmost and minimized; resident measurements are in progress. +The timings below remain macOS measurements. [Additional functional evidence](verification/issue-386/resume/README.md) +includes successful dedicated checks with Domain Reload enabled and disabled, +Prefab, Timeline, InputActions persistence, animation, video, reference fetching, +baking, real Hot Reload, and a built Windows Player. Complex input passed 11 checks +after correcting the test's CRLF counter parsing. +Linux screenshot tools produced real images using TCP fixtures; a licensed Linux +Unity Editor, winget installation, and comparison with the original staff report +remain unverified. ### Coexistence @@ -175,8 +183,13 @@ Editor 側の **Pipeline**(`com.unity.pipeline`)を提供しています。 Windows の実機確認は [Issue #386 の証跡](verification/issue-386/README.md) を追加しました。 CLI / Bridge 0.18.1、Unity 6000.4.4f1 で実 setup、lockfile 発見、Editor モーダル中の OS 画面取得、および DisableDomainReload / PlayUnfocused 条件で公開23操作を確認しています。 -公式 CLI の Windows 再測定は行っておらず、下の速度比較は macOS の計測です。 -通常の Domain Reload では接続エラーが出ており、Linux、winget、スタッフ原資料との網羅性確認は未検証です。 +公式 CLI 1.0.0-beta.11 / Pipeline 0.8.0-exp.1 の Windows 比較では、プロセス方式を +各操作100回、Editor 前面・最小化の2条件で計測しました。常駐方式は計測中です。 +下の速度比較は macOS の計測です。 +[追加の機能検証](verification/issue-386/resume/README.md)では、Domain Reload 有効・無効の専用検証、 +Prefab、Timeline、InputActions 保存、Animation、Video、Reference、Bake、実 Hot Reload、実 Windows Player が成功しました。 +複合入力はテストのCRLFカウンター読取を修正して11件成功しました。Linux の画面取得ツールは TCP fixture で実画像を生成しましたが、 +認証済み Linux Unity Editor、winget 導入、スタッフ原資料との網羅性確認は未検証です。 ### 同一プロジェクトでの併用 diff --git a/docs/hot-reload.md b/docs/hot-reload.md index 5bf960eb..f36d440c 100644 --- a/docs/hot-reload.md +++ b/docs/hot-reload.md @@ -23,8 +23,10 @@ Silicon (ARM64) macOS**. Real method replacement is verified on macOS with 6000.3.25f1 and 2022.3.62f3, both as native ARM64 Editors and as x64 Editors under Rosetta 2. Any other host is rejected before compilation or native patching with `HOT_RELOAD_PLATFORM_UNSUPPORTED`; on such a host use an x64 -build of the Editor. Windows and Linux hardware verification is tracked in -Issue #386. +build of the Editor. Windows x64 Unity 6000.4.4f1 also passed 25 real replacement, +state preservation, failure and recovery checks with FSR 1.8.0: +[Issue #386 evidence](verification/issue-386/resume/hot-reload-results.txt). +Linux hardware verification remains pending in Issue #386. Disable Fast Script Reload's automatic and on-demand reload before beginning. The Bridge rejects concurrent ownership instead of changing those preferences. diff --git a/docs/verification/issue-386/README.md b/docs/verification/issue-386/README.md index 9c6d8755..133e30f2 100644 --- a/docs/verification/issue-386/README.md +++ b/docs/verification/issue-386/README.md @@ -9,15 +9,23 @@ MCP profile 修正後の [最終ソース・バイナリ SHA256](environment-fin 先に測定した Windows 操作にはその測定時点のバイナリ SHA256 を残している。 **Overall: FAIL — Issue 全体は未完了。PR は未作成。** -Windows の成功を Linux、通常の Domain Reload、winget 導入や原資料の全シナリオへ拡張しない。 +個別の成功を Linux 実 Editor、winget 導入や原資料の全シナリオへ拡張しない。 ## 2026-10-04 の継続検証 前回の停止条件を解消する作業を継続した。Windows Git placeholder の参照を正しく検証する -修正後、native Cargo 全件は **607 PASS / 0 FAIL**、skills lint は **23 skills / 0 violations**。 +修正後、native Cargo 全件は **610 PASS / 0 FAIL**、skills lint は **23 skills / 0 violations**。 fmt / clippy と実 Unity の SceneHandlerTests 11件も成功した。 公開23操作、実 Editor のモーダルによる GDI fallback、公開版 CLI の実 Editor ping を再実行した。 +[継続検証の全コマンド・テスト名・証跡](resume/README.md)を追加した。 +Prefab45+22、Timeline40、eval18+1000連続実行、InputActions保存/再起動50、動画6、Animation25+26、 +参照取得/解決9、Bake4 backendの101チェック、Windows Playerの実ビルドとGUI描画が成功した。 +Domain Reload有効/無効の4件、InputActions型12・通知4、Gamepad2・Touch15も成功した。 +隔離したWindows x64 / FSR1.8.0で実Hot Reload25件が成功し、状態保持・部分適用・復旧を確認した。 +複合入力の失敗はCRLFを読めないテストhelperが原因で、改行回帰4件を含む11件がheadlessで成功した。 +原資料との網羅性と公式CLIのWindows比較の全条件は未確認である。 + WSL Ubuntu 24.04 に各デスクトップ環境を導入し、実 CLI から grim / gnome-screenshot / spectacle と X11 の import / scrot / maim で実 PNG を生成した。 これらは応答しない TCP fixture を使う OS capture の検証で、Linux 実 Unity の成功とは区別する。 @@ -33,7 +41,7 @@ winget 初回提出用の3ファイルを [packaging/winget](../../../packaging/ スタッフ原資料の代替調査では #243–260 / #390–395 に、23操作以外の入力・bake・build・動画・ Animation・InputActions・C# reference の確認項目があると分かった。原資料との一致は未確認で、 -Windows の追加検証を進めている。下記の旧605成功・1失敗などの証跡は初回検証の記録として残す。 +Windows の追加検証を収録した。下記の旧605成功・1失敗などの証跡は初回検証の記録として残す。 ## 受け入れ基準の実測状況 @@ -43,7 +51,7 @@ Windows の追加検証を進めている。下記の旧605成功・1失敗な | 2: 実 setup / Bridge 導入・接続 | PASS | 空の隔離プロジェクトで `setup --launch-editor --wait-secs 420` を実行。40.549秒、exit 0、`projectMatches: true`。[結果](setup.stdout.json)、[実行時間と ping](fresh-setup-summary.json)。dry-run ではない。 | | 3: 証跡の Issue / PR 記録 | PASS | 本資料と [Issue コメント](https://github.com/akiojin/unity-cli/issues/386#issuecomment-5970471700) に成功・失敗・未検証条件を記録。正式検証記録が未取得のため PR 未作成。 | | 4: Windows / Linux OS フォールバック | Windows PASS / Linux 部分 | Windows 実 Editor のモーダルで PowerShell + GDI が成功。Linux Wayland / X11 の6ツールは実 PNG 生成成功、Linux 実 Editor はライセンス認証待ち。 | -| 5: スタッフ原資料の全シナリオ・比較表 | 部分 | 公開済み23操作は既存比較と同じ設定で23/23 PASS。[一覧](staff-final-operations.json)。原資料 `pm-scratch/staff-report.md` は未取得。公式 CLI の Windows 比較・原資料との網羅性確認は未実施。 | +| 5: スタッフ原資料の全シナリオ・比較表 | 部分 | 公開済み23操作と、多数の[追加実機シナリオ](resume/README.md)が成功。複合入力も改行修正後11件成功。原資料 `pm-scratch/staff-report.md` は未取得。公式 CLI の Windows 比較は全条件未達で、原資料との網羅性は未確認。 | | 6: 公開 install.ps1 / winget / ping | PowerShell PASS / winget 未検証 | 公開 installer と実 Editor ping 成功。初回 manifest の validate 成功。公開 package / `WINGET_TOKEN` がなく、winget install / ping は未実施。 | ## 実機で発見して修正した問題 @@ -88,6 +96,10 @@ Windows の Python E2E helper も修正した。`os.kill(pid, 0)` は Windows 終了済み・無効 PID の拒否、終了コード259の判定を Windows native の4テストで確認した。 既存 authentication の3テストと Linux の回帰テストも成功した。 +継続検証ではGit HTTP認証形式、Windowsの長いreferenceパス、batchの診断喪失、 +Preview SceneによるBakeの誤判定も再現して修正した。 +各RED→GREENと実取得・実アセットの証跡は[継続検証](resume/README.md)に収録した。 + ## Windows OS キャプチャ 実 Editor PID 44232 に同期 `EditorUtility.DisplayDialog("Issue386FallbackProbe", ...)` を開き、 @@ -187,3 +199,4 @@ Agent Visual Check: n/a(CLI と Editor 連携を検証。Web/TUI の表示変 2. 用意した Linux Editor / Unity Hub でライセンス認証し、実 Editor を含む AC-4 を実行する。 3. winget 初回公開と `WINGET_TOKEN` の設定を行い、公開 source から install / ping を検証する。 4. 派生検証の binary-only Cargo 対応と共通検証枠を確保し、正式記録と必要なユーザー確認後に Ready PR を作成する。 +5. 原資料の全シナリオと公式CLIのWindows比較の全条件を照合する。 diff --git a/docs/verification/issue-386/resume/AnimationCurveHandlerTests.xml b/docs/verification/issue-386/resume/AnimationCurveHandlerTests.xml new file mode 100644 index 00000000..6ddafa4a --- /dev/null +++ b/docs/verification/issue-386/resume/AnimationCurveHandlerTests.xml @@ -0,0 +1,522 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ChildComponentCurve_AndFilter +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ExistingUnimportedFile_IsNotOverwritten +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("binding") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("path") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("component") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("root") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("duplicate") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("negative") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("mode") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("infinity") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("packages") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidInput_DoesNotCreateAsset("extension") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.InvalidLaterKey_IsAtomicForExistingClip +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("upsert_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.KeyEdits_RecalculateNeighboringLinearTangents("remove_keys") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.MissingRemovalKey_DoesNotPartiallyWrite +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Sprite","UnityEngine.SpriteRenderer") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.NonNumericBinding_IsRejected("m_Enabled","UnityEngine.BoxCollider") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.PlayModePolicy_RejectsEditsAllowsReads +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.ReadOnlyClip_IsRejectedWithoutMutation +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.Set_LinearMidpointAndReimport_PreserveKeysAndTangents +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Constant") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Auto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("ClampedAuto") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.TangentModes_RoundTripAndOmittedUpdatesPreserve("Free") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.AnimationCurveHandlerTests.UpsertRemove_PreserveOtherBindingsEventsAndSettings + diff --git a/docs/verification/issue-386/resume/BakeHandlerTests.xml b/docs/verification/issue-386/resume/BakeHandlerTests.xml new file mode 100644 index 00000000..84d1295b --- /dev/null +++ b/docs/verification/issue-386/resume/BakeHandlerTests.xml @@ -0,0 +1,32 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.AdditiveSceneIsRejectedWithoutSwitchingActiveScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.AdditiveSceneIsRejectedWithoutSwitchingActiveScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.ConcurrentBakeIsRejectedBeforeEditorTick +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.ConcurrentBakeIsRejectedBeforeEditorTick +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.DifferentSceneIsRejected +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.DifferentSceneIsRejected +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.DirtySceneIsRejected +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.DirtySceneIsRejected +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.EmptySceneIsRejected("lighting") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.EmptySceneIsRejected("lighting") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.EmptySceneIsRejected("navmesh-legacy") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.EmptySceneIsRejected("navmesh-legacy") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.EmptySceneIsRejected("occlusion") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.EmptySceneIsRejected("occlusion") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.LegacyRejectsSurfaceOwnedNavigationData +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.LegacyRejectsSurfaceOwnedNavigationData +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.MissingTargetIsRejected +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.MissingTargetIsRejected +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.PreviewSceneDoesNotBlockSavedScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.PreviewSceneDoesNotBlockSavedScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.QueuedJobIsRunningAndHasNoArtifacts +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.QueuedJobIsRunningAndHasNoArtifacts +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.SceneChangeFailsAcceptedJobWithoutSuccessArtifacts +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.SceneChangeFailsAcceptedJobWithoutSuccessArtifacts +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.SceneEditedAfterAcceptanceFailsBeforeBaking +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.SceneEditedAfterAcceptanceFailsBeforeBaking +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.SurfaceRequiresExplicitPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.SurfaceRequiresExplicitPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.UnknownJobDoesNotReportSuccess +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.UnknownJobDoesNotReportSuccess + diff --git a/docs/verification/issue-386/resume/GamepadStickInputPlayModeTests.xml b/docs/verification/issue-386/resume/GamepadStickInputPlayModeTests.xml new file mode 100644 index 00000000..295115f1 --- /dev/null +++ b/docs/verification/issue-386/resume/GamepadStickInputPlayModeTests.xml @@ -0,0 +1,98 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.LeftStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.GamepadStickInputPlayModeTests.RightStick_ProcessedAxesMatchRequestedValuesInGameUpdate + diff --git a/docs/verification/issue-386/resume/InputActionNotificationTests.xml b/docs/verification/issue-386/resume/InputActionNotificationTests.xml new file mode 100644 index 00000000..d92b8622 --- /dev/null +++ b/docs/verification/issue-386/resume/InputActionNotificationTests.xml @@ -0,0 +1,104 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverKeyboardMouseAndGamepadPressAndRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverKeyboardMouseAndGamepadPressAndRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverKeyboardMouseAndGamepadPressAndRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverKeyboardMouseAndGamepadPressAndRelease +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls + diff --git a/docs/verification/issue-386/resume/InputActionsHandlerTests.xml b/docs/verification/issue-386/resume/InputActionsHandlerTests.xml new file mode 100644 index 00000000..c1db46a7 --- /dev/null +++ b/docs/verification/issue-386/resume/InputActionsHandlerTests.xml @@ -0,0 +1,38 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("Button","Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("Button","Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("Button","Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("PassThrough","PassThrough","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("PassThrough","PassThrough","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("PassThrough","PassThrough","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("Value","Value","Vector2") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("Value","Value","Vector2") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("Value","Value","Vector2") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType(null,"Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType(null,"Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType(null,"Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("invalid","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("invalid","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("invalid","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("999","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("999","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.AddInputAction_PreservesActionType("999","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("Button","Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("Button","Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("Button","Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("PassThrough","PassThrough","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("PassThrough","PassThrough","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("PassThrough","PassThrough","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("Value","Value","Vector2") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("Value","Value","Vector2") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("Value","Value","Vector2") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType(null,"Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType(null,"Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType(null,"Button","Button") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("invalid","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("invalid","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("invalid","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("999","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("999","Value","") +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionsHandlerTests.CreateActionMap_PreservesActionType("999","Value","") + diff --git a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-green.xml b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-green.xml new file mode 100644 index 00000000..ab926a83 --- /dev/null +++ b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-green.xml @@ -0,0 +1,38 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: A (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: A (UnityCliVirtualKeyboard) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating text input: "Hi" (UnityCliVirtualKeyboard) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +targetFrameRate=120, elapsed=1.005047s, frames=100 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +targetFrameRate=30, elapsed=1.004716s, frames=28 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +targetFrameRate=60, elapsed=1.011087s, frames=55 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +targetFrameRate=-1, elapsed=1.002694s, frames=2028 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","MouseReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("TouchPresses=2\nTouchReleases=1\n","TouchReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1","MouseReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","TouchReleases",0) + diff --git a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-red.xml b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-red.xml new file mode 100644 index 00000000..ca0a219b --- /dev/null +++ b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-red.xml @@ -0,0 +1,131 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: A (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: A (UnityCliVirtualKeyboard) +Timed out waiting for condition. Status: +Ready=True +CaptureCount=602 +TextInput=(empty) +KeyboardPressed=(none) +KeyboardPresses=0 +KeyboardReleases=0 +MousePosition=222.0,111.0 +MouseLeftPressed=False +MousePresses=0 +MouseReleases=0 +MouseScroll=0.0,0.0 +GamepadButtonA=False +GamepadButtonPresses=1 +GamepadButtonReleases=1 +GamepadLeftStick=0.25,0.50 +GamepadLeftTrigger=0.00 +GamepadDpad=0.00,0.00 +TouchPresses=0 +TouchReleases=0 +TouchMaxSimultaneous=0 +TouchLast=none +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +Timed out waiting for condition. Status: +Ready=True +CaptureCount=606 +TextInput=Hi +KeyboardPressed=(none) +KeyboardPresses=0 +KeyboardReleases=0 +MousePosition=120.0,140.0 +MouseLeftPressed=False +MousePresses=1 +MouseReleases=1 +MouseScroll=0.0,0.0 +GamepadButtonA=False +GamepadButtonPresses=0 +GamepadButtonReleases=0 +GamepadLeftStick=0.25,0.50 +GamepadLeftTrigger=0.00 +GamepadDpad=0.00,0.00 +TouchPresses=0 +TouchReleases=0 +TouchMaxSimultaneous=0 +TouchLast=none +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating text input: "Hi" (UnityCliVirtualKeyboard) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +targetFrameRate=120, elapsed=1.011509s, frames=98 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +targetFrameRate=30, elapsed=1.028968s, frames=29 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +targetFrameRate=60, elapsed=1.009028s, frames=55 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Created virtual keyboard device +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) +targetFrameRate=-1, elapsed=1.002823s, frames=2181 + Expected: 1 + But was: 0 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","MouseReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("TouchPresses=2\nTouchReleases=1\n","TouchReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1","MouseReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","TouchReleases",0) + diff --git a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests.xml b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests.xml new file mode 100644 index 00000000..e13936d7 --- /dev/null +++ b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests.xml @@ -0,0 +1,366 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][InputSystemHandler] Simulating key press: A (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: A (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: A (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: A (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: A (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: A (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: A (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: A (Keyboard) +Timed out waiting for condition. Status: +Ready=True +CaptureCount=602 +TextInput=(empty) +KeyboardPressed=(none) +KeyboardPresses=0 +KeyboardReleases=0 +MousePosition=222.0,111.0 +MouseLeftPressed=False +MousePresses=0 +MouseReleases=0 +MouseScroll=0.0,0.0 +GamepadButtonA=False +GamepadButtonPresses=1 +GamepadButtonReleases=1 +GamepadLeftStick=0.25,0.50 +GamepadLeftTrigger=0.00 +GamepadDpad=0.00,0.00 +TouchPresses=3 +TouchReleases=3 +TouchMaxSimultaneous=1 +TouchLast=0:Ended@100.0,200.0 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +Timed out waiting for condition. Status: +Ready=True +CaptureCount=606 +TextInput=Hi +KeyboardPressed=(none) +KeyboardPresses=0 +KeyboardReleases=0 +MousePosition=120.0,140.0 +MouseLeftPressed=False +MousePresses=1 +MouseReleases=1 +MouseScroll=0.0,0.0 +GamepadButtonA=False +GamepadButtonPresses=0 +GamepadButtonReleases=0 +GamepadLeftStick=0.25,0.50 +GamepadLeftTrigger=0.00 +GamepadDpad=0.00,0.00 +TouchPresses=3 +TouchReleases=3 +TouchMaxSimultaneous=1 +TouchLast=0:Ended@100.0,200.0 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating text input: "Hi" (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating text input: "Hi" (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating text input: "Hi" (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating text input: "Hi" (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +targetFrameRate=120, elapsed=1.008113s, frames=86 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +targetFrameRate=30, elapsed=1.034271s, frames=28 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +targetFrameRate=60, elapsed=1.021651s, frames=51 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +targetFrameRate=-1, elapsed=1.003568s, frames=566 + diff --git a/docs/verification/issue-386/resume/README.md b/docs/verification/issue-386/resume/README.md new file mode 100644 index 00000000..211661bc --- /dev/null +++ b/docs/verification/issue-386/resume/README.md @@ -0,0 +1,98 @@ +# #386 継続検証の記録 + +2026-10-04 JST。Windows 11 x64 / Unity 6000.4.4f1 / CLI・Bridge 0.18.1。 +成功した独立検証と、Issue 全体の未達条件を区別する。 + +**Overall: FAIL — Issue 全体は未完了、PR 未作成。** + +## 実行した検証 + +| 対象 | 実測 | 証跡 | +| --- | --- | --- | +| Windows native Rust | 610 PASS / 0 FAIL(558 unit +52 integration) | [全件ログ](cargo-all-final.txt)、[全610テスト名](cargo-test-inventory.json)、[コマンド・exit・時刻](final-checks.json) | +| fmt / clippy / skills lint | PASS、23 skills / 0 violations | [fmt](fmt.txt)、[clippy](clippy.txt)、[skills](skills-lint-final.txt) | +| all-features clippy / rustdoc / Markdown | warningsをエラーとして全件成功 | [コマンド・exit・時刻](final-doc-checks.json) | +| Python の PID 生存確認 | Windows4件、Linux3件成功・Windows専用1件skip | [Windows](python-windows.txt)、[Linux](python-linux.txt)、[最終Windows4件](process-liveness-final.txt) | +| 実 Editor の公開23操作 | 23/23、各1回の機能確認 | [操作と結果](staff-final-operations.json)、[条件・バイナリ](staff-final-summary.json) | +| Windows 公式 CLI 比較・プロセス方式 | 作成・階層・evalを両CLIで各100回、前面・最小化の2条件。3 warmup | [前面](official-windows-process-frontmost.json)、[最小化](official-windows-process-background.json)、[公式binary検証](official-windows-binary.json) | +| 実 Editor モーダル / Windows GDI fallback | PNG生成、無効時 TIMEOUT | [結果](modal-summary.json) | +| Prefab | 45 runtime +22 EditMode、失敗0 | [結果](prefab-results.json)、[実行ログ](prefab.txt) | +| Timeline | 40 PASS / 0 FAIL | [実行ログ](timeline.txt) | +| C# eval | 18 PASS / 0 FAIL、1000連続実行 | [実行ログ](eval.txt)。追加assembly4、管理memory増加2,658,304 bytes | +| Domain Reload | 有効2件・無効2件とも成功、設定復元 | [全テスト・実行条件](domain-reload.json) | +| 実 Hot Reload | Windows x64 / FSR1.8.0、25 PASS / 0 FAIL | [実行ログ](hot-reload-results.txt)、[条件・終了処理](hot-reload-summary.json) | +| InputActions の保存・再起動 | 50 PASS / 0 FAIL、Editor2回起動 | [実行ログ](input-actions-persistence.txt) | +| InputActions の型 / 通知 | 型12件、通知4件とも成功 | [型](InputActionsHandlerTests.xml)、[通知](InputActionNotificationTests.xml) | +| Animation Curves | 数値・reimport等25項目、EditMode26件成功 | [runtime](animation-curves.txt)、[EditMode](AnimationCurveHandlerTests.xml) | +| 動画形式 | mp4 / webm / PNG sequence / 再実行・拒否を含む6項目成功 | [結果](video-summary.json)、[実行ログ](video-formats.txt) | +| C# reference | 実fetch5項目 + ref選択/status/grep/cache4項目成功 | [fetch](reference-fetch-summary.json)、[解決](reference-resolution-summary.json) | +| Bake | 4 backend、101チェック成功。保存・再読込・実NavMesh問い合わせを確認 | [実行ログ](bake-headed-final.txt)、[操作条件](bake-headed-result.json)、[実ファイルSHA256](bake-artifact-metadata.json) | +| Bake / Scene の回帰テスト | 15件 /11件成功 | [Bake](BakeHandlerTests.xml)、[Scene](SceneHandlerTests.xml) | +| Windows Player | 実ビルド、exe / Data / BuildReport一致、headless起動5秒、GUI描画 | [ビルド・起動](windows-player-result.json)、[640×360の描画観測](windows-player-graphical.json)。ゲーム入力は未確認 | +| Gamepad Stick / Touch | 2件 /15件成功 | [Gamepad](GamepadStickInputPlayModeTests.xml)、[Touch](TouchGesturePlayModeTests-fresh.xml) | +| 複合入力・カウンター読取 | Windows headlessで11/11成功。元の7件と改行回帰4件 | [RED: 11件中3失敗](InputSimulationAutomationPlayModeTests-counter-red.xml)、[GREEN: 11件成功](InputSimulationAutomationPlayModeTests-counter-green.xml)、[コマンド・exit](input-counter-green.json) | +| Linux X11 | import / scrot / maim、12チェック成功 | [実行ログ](linux-x11-platform.txt) | +| Linux Wayland | GNOME / sway(grim) / KWin(spectacle) の実PNG生成成功 | [GNOME](linux-gnome-fallback-result.json)、[grim](linux-wayland-first-results.json)、[spectacle](linux-wayland-extra-results.json) | +| Linux 実 Unity | 起動exit198、認証未完了 | [匿名化した結果](linux-license.json)。上記captureはsilent TCP fixtureであり実Editorの証明ではない | +| winget初回manifest | validate PASS | [結果](winget-manifest-validate.txt)。公開sourceからのinstall / pingは未実施 | + +## 確認して修正した原因 + +- Git smart HTTP に `Authorization: token` を渡すと有効なGitHub tokenでも失敗した。 + 同じtokenのBasic形式で成功を確認し、HTTP fixtureの回帰テストをRED→GREENにした。 + [RED](reference-auth-red.txt)、[GREEN](reference-auth-green.txt)、[値を含まない実transport検証](reference-auth-probe.json)。 +- Windowsの深いC# referenceキャッシュでcheckoutが`Filename too long`になった。 + Gitの子プロセスだけに`core.longpaths=true`を指定し、設定falseの環境でも実checkoutできる + [RED](reference-longpath-red.txt)→[GREEN](reference-longpath-green.txt)を確認した。 +- batch失敗時に配列から診断を読めず`UNKNOWN_ERROR`になった。 + 最初の失敗項目からmessage/codeを読み、全結果の配列を保持する。 + [RED](batch-message-red.txt)、[GREEN](batch-message-green.txt)。 +- 保存シーン1つでも内部Preview SceneがあるとBakeを拒否していた。 + 対象シーンのPreview判定と通常シーン数を確認するよう修正した。 + [RED](bake-preview-red.xml)、[GREEN](bake-preview-green.xml)。追加ロードした通常シーンの拒否も15件のsuiteで確認した。 +- offlineのMCP / warningテストが実Editorを自動発見していた。 + 期待値のCLIも同じ未接続port1を指定し、実Editor起動中に検証した。 +- Touchの端末除去テストは通常のCLI接続ログを予期しないログと扱っていた。 + loopbackからの接続を示す既知のLogだけを期待値として登録する。 + Warning / Error / Exceptionの検出を保ったまま15件すべて成功した。 + +Bakeのheaded検証では、Unityが生成シーンの外部変更確認を5回表示した。 +自分が起動したEditorのPID、ダイアログ名、生成シーン1つだけのパスを照合し、 +`Ignore`を選択してtracked sceneを維持した。操作履歴を上表の条件JSONに残している。 +UI操作なしの最初の実行はTIMEOUTだった。無人実行での成功とは扱わない。 + +複合入力の初回[7件中2失敗](InputSimulationAutomationPlayModeTests.xml)は、テストがWindowsの +CRLF表示からカウンターを読み取れず0にしたことが原因だった。数値読取の`$`の前に任意の +`\r`を認め、CRLF / LF / 末尾改行なし / キー欠落の4ケースを追加した。 +旧正規表現では新CRLFケースと複合2件が失敗し、修正後は元の入力シナリオを含む11件が成功した。 +入力runtime、50msのhold、ミリ秒単位のswipe20ms、元のアサーションは変更していない。 +調査用のruntime変更や一時fixtureは製品差分から除外した。 + +## 証跡の帰属と残る条件 + +[ソース・最新Windows CLI・公開Linux CLIのSHA256](source-snapshot.json)を保存した。 +公開Linux CLIのSHA256はRelease 0.18.1の`SHA256SUMS`と一致する。 +先に実行した23操作・Prefab等には、その時点のバイナリSHA256を別のJSONに保持している。 +全結果を同一バイナリの実行と扱わない。 + +[スタッフ範囲の再構成](staff-scope-reconstruction.md)は#243–260 / #390–395からの推論であり、 +未取得の`pm-scratch/staff-report.md`そのものではない。元の全行・印・正のシナリオとの一致は未確認。 +Windowsでの公式CLIプロセス比較は上表の2条件で計測済み、常駐23操作は計測中である。 +同じUnity6000.4.4f1のプロジェクトにBridge0.18.1とPipeline0.8.0-exp.1を入れ、 +両CLIの応答からプロジェクトとUnityバージョンの一致を確認した。 +背景条件は、Windowsが既存GWTウィンドウの前面化を拒否したため、自分のEditorだけを最小化した。 +macOSの表示したままの背景条件とは異なる。ほかのプロジェクトの正式検証が稼働中のhostであり、 +Windowsの性能予算や過去のbaselineを満たしたという結果ではない。 +常駐方式の初回は、公式`find_assets`の文字列`search_in`に配列を渡して失敗した。 +[失敗記録](official-windows-resident-frontmost-search-array-failure.json)を残し、 +導入済みPipelineの実メソッド定義に合わせて文字列を渡すよう修正した。 +[比較スクリプトの15件の回帰テスト](comparison-unit-linux.txt)も成功した。 + +正式な`verify.run`は共通host leaseを1500秒待って2回ともdeferred。 +[1回目](canonical-verify.txt)、[2回目](canonical-verify-second.txt)。通常の直接実行とは区別する。 +同一sessionのblocked復旧用deriveはbinary-only Cargoに`--lib`を生成し、 +[実Cargoがno library targets foundで拒否する](derived-lib-error.txt)。PMに修復裁定を依頼済み。 + +User Verification Result: pending。Agentの描画観測を人の確認済みとは扱わない。 +不足するLinux認証・スタッフ原資料・winget公開/Secretの操作経路・正式検証復旧が揃った後、 +元資料と照合して必要なユーザー確認とReady PRへ進む。 diff --git a/docs/verification/issue-386/resume/SceneHandlerTests.xml b/docs/verification/issue-386/resume/SceneHandlerTests.xml new file mode 100644 index 00000000..d821dc8e --- /dev/null +++ b/docs/verification/issue-386/resume/SceneHandlerTests.xml @@ -0,0 +1,266 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldAddToBuildSettings_WhenRequested +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForEmptySceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForExistingScene +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldFailForInvalidSceneName +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldHandleMissingParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldNotLoadScene_WhenLoadSceneIsFalse +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithCustomPath +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.CreateScene_ShouldWorkWithMinimalParameters +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.SceneHandlerTests.SaveScene_ShouldCreateNestedFolders + diff --git a/docs/verification/issue-386/resume/TouchGesturePlayModeTests-fresh.xml b/docs/verification/issue-386/resume/TouchGesturePlayModeTests-fresh.xml new file mode 100644 index 00000000..4667fe12 --- /dev/null +++ b/docs/verification/issue-386/resume/TouchGesturePlayModeTests-fresh.xml @@ -0,0 +1,29 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.DefaultTap_IsObservedAndReleased +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.DistinctSlots_OverlapAndRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.NativeTouchControl_IsVisibleToUpdateProbe +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.RemovedDevice_DoesNotBreakSubsequentGesture +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.RemovingDevice_CancelsOnlyStartedGesture +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.SameSlotGestures_AreQueuedInOrder +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.SparseTouchId_HasOneLogicalStateEntry +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_120Fps +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_30Fps +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_Uncapped +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_120Fps +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_30Fps +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_FixedInputUpdate +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_Uncapped +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.ZeroDurationSwipe_ExposesStartEndpointAndRelease +[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) + diff --git a/docs/verification/issue-386/resume/animation-curves.txt b/docs/verification/issue-386/resume/animation-curves.txt new file mode 100644 index 00000000..4819a37a --- /dev/null +++ b/docs/verification/issue-386/resume/animation-curves.txt @@ -0,0 +1,26 @@ +PASS: refresh_assets succeeds +PASS: create_gameobject succeeds +PASS: created root has integer id +PASS: edit_animation_curve succeeds +PASS: get_animation_curves succeeds +PASS: linear keys and slope encode midpoint value 1 +PASS: manage_asset_import_settings succeeds +PASS: get_animation_curves succeeds +PASS: saved keys and interpolation survive reimport +PASS: edit_animation_curve succeeds +PASS: get_animation_curves succeeds +PASS: edit_animation_curve succeeds +PASS: get_animation_curves succeeds +PASS: existing key updated and new key inserted +PASS: edit_animation_curve succeeds +PASS: get_animation_curves succeeds +PASS: requested key removed +PASS: other binding preserved after key updates and removal +PASS: edit_animation_curve succeeds +PASS: get_animation_curves succeeds +PASS: curve removed while other binding preserved +PASS: invalid binding returns clear error +PASS: unsupported clip returns clear error +PASS: get_animation_curves succeeds +PASS: rejected edits preserve the original clip +Animation curves E2E: 25 passed, 0 failed; log: /tmp/unity-cli-animation-curves-20261004-064617-3937.log diff --git a/docs/verification/issue-386/resume/auth-warning-offline-green.txt b/docs/verification/issue-386/resume/auth-warning-offline-green.txt new file mode 100644 index 00000000..22d50653 --- /dev/null +++ b/docs/verification/issue-386/resume/auth-warning-offline-green.txt @@ -0,0 +1,8 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 1.30s + Running tests\auth_warning.rs (target\debug\deps\auth_warning-c35c20bac6c142a9.exe) + +running 1 test +test legacy_opt_out_warns_on_stderr_only_for_exact_one ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 13.30s diff --git a/docs/verification/issue-386/resume/bake-artifact-metadata.json b/docs/verification/issue-386/resume/bake-artifact-metadata.json new file mode 100644 index 00000000..73a8d863 --- /dev/null +++ b/docs/verification/issue-386/resume/bake-artifact-metadata.json @@ -0,0 +1,67 @@ +[ + { + "path": "Assets/Scenes/Generated/E2E/Baking/Empty/Empty.unity", + "bytes": 3606, + "sha256": "5c276ea6c3621876c7d993fb924cd28e0fbf4a688c6a1aa3836649bdbbbae0c5" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy/NavMesh.asset", + "bytes": 7720, + "sha256": "5595c0b9bdf772fc4672d56969c5fc7d2fbb9a5d35de049dabf8b6f4cafffc53" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy.unity", + "bytes": 18413, + "sha256": "3a4568641fd655197c5d45c3862f833ece3905ea964a94d290e89a4d1dffb0d6" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/LightingData.asset", + "bytes": 18177, + "sha256": "09a2d12600d0e84ab0c33112ec7078fa486734ade2150e7d038be9490d16e36d" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_light.exr", + "bytes": 30656, + "sha256": "a5e264877518b72fce6a4ff6a850aa75233f3d2f35fbcbb6999ce2ee7f0b9652" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/ReflectionProbe-0.exr", + "bytes": 133557, + "sha256": "2fd8c777d30adf04ea0853a0ad64f45313477598f5610fd8738bc1603777b2a2" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", + "bytes": 18375, + "sha256": "d465ae4dc335123d9274353fe445528e529d4a0fe7bfdfdfe81c0dde3c3b8969" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/NoOutput/NoOutput.unity", + "bytes": 20158, + "sha256": "17f43b216c331933e81ed6e7b8e346e76ea312b58d6e42cd37b8e7e0f3f90aab" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion/OcclusionCullingData.asset", + "bytes": 3297, + "sha256": "1fb2419647675b3e4d40f3a9880b326031f3cf031dfa55f11089ab00ac1529da" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion.unity", + "bytes": 18427, + "sha256": "706a0bfa069e223625b7831918a2ae88edf5341f572e0a84a4e6e943421fe522" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-1460193e843a4c22b9df488c8680ff44.asset", + "bytes": 7752, + "sha256": "e86eec5ffa392d5a5f86c9563002ffc838eef368b108c673e21dc2f064ae5b03" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-e93b59e165ad4e07a7d2c53838f25092.asset", + "bytes": 7752, + "sha256": "8902cfa09d93a255529a92f8b2246134907d86f8e064c6d3171da456eb967537" + }, + { + "path": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", + "bytes": 20246, + "sha256": "c35c9f2f3ca249d1dc8051bef48e5feb80e63ba3e4fbf1dc454bdb58e4edbe78" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/bake-fixed-final.txt b/docs/verification/issue-386/resume/bake-fixed-final.txt new file mode 100644 index 00000000..ce935728 --- /dev/null +++ b/docs/verification/issue-386/resume/bake-fixed-final.txt @@ -0,0 +1,35 @@ +get_editor_info {"assetsPath": "/.cache/issue-386/staff-project/Assets", "codeIndexRoot": "/.cache/issue-386/staff-project/.unity/cache/code-index", "packagesPath": "/.cache/issue-386/staff-project/Packages", "projectRoot": "/.cache/issue-386/staff-project", "unity": {"platform": "WindowsEditor", "productName": "staff-project", "unityVersion": "6000.4.4f1"}} +PASS get_scene_bake_status returns a genuine error +PASS get_scene_bake_status rejects with JOB_NOT_FOUND: {"command":"raw get_scene_bake_status","data":{"code":"JOB_NOT_FOUND","error":"No bake job exists for this jobId in this Editor session.","reason":"No bake job exists for this jobId in this Editor session.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"JOB_NOT_FOUND","message":"No bake job exists for this jobId in this Editor session. (code: JOB_NOT_FOUND)"}],"success":false,"warnings":[]} + +execute_menu_item {"executed": true, "executionTime": 460, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Prepare Lighting", "message": "Menu item executed successfully", "success": true} +PASS Prepare Lighting +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with SCENE_MISMATCH: {"command":"raw start_scene_bake","data":{"code":"SCENE_MISMATCH","error":"scenePath must identify the saved active scene under Assets/.","reason":"scenePath must identify the saved active scene under Assets/.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"SCENE_MISMATCH","message":"scenePath must identify the saved active scene under Assets/. (code: SCENE_MISMATCH)"}],"success":false,"warnings":[]} + +start_scene_bake {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "queued", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS lighting starts tracked asynchronous job +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "76215e87e1564dd3b2f947467c9870b0", "phase": "finalizing", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +FAIL TimeoutExpired(['\\target\\debug\\unity-cli.exe', 'raw', 'get_scene_bake_status', '--json', '{"jobId": "76215e87e1564dd3b2f947467c9870b0"}', '--host', '127.0.0.1', '--port', '6487', '--timeout-ms', '120000', '--output', 'json'], 150) +Baking E2E: passed=17 failed=1 diff --git a/docs/verification/issue-386/resume/bake-fresh-0.txt b/docs/verification/issue-386/resume/bake-fresh-0.txt new file mode 100644 index 00000000..dd85b91b --- /dev/null +++ b/docs/verification/issue-386/resume/bake-fresh-0.txt @@ -0,0 +1,11 @@ +get_editor_info {"assetsPath": "/.cache/issue-386/staff-project/Assets", "codeIndexRoot": "/.cache/issue-386/staff-project/.unity/cache/code-index", "packagesPath": "/.cache/issue-386/staff-project/Packages", "projectRoot": "/.cache/issue-386/staff-project", "unity": {"platform": "WindowsEditor", "productName": "staff-project", "unityVersion": "6000.4.4f1"}} +PASS get_scene_bake_status returns a genuine error +PASS get_scene_bake_status rejects with JOB_NOT_FOUND: {"command":"raw get_scene_bake_status","data":{"code":"JOB_NOT_FOUND","error":"No bake job exists for this jobId in this Editor session.","reason":"No bake job exists for this jobId in this Editor session.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"JOB_NOT_FOUND","message":"No bake job exists for this jobId in this Editor session. (code: JOB_NOT_FOUND)"}],"success":false,"warnings":[]} + +execute_menu_item {"executed": true, "executionTime": 595, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Prepare Lighting", "message": "Menu item executed successfully", "success": true} +PASS Prepare Lighting +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with SCENE_MISMATCH: {"command":"raw start_scene_bake","data":{"code":"SCENE_MISMATCH","error":"scenePath must identify the saved active scene under Assets/.","reason":"scenePath must identify the saved active scene under Assets/.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"SCENE_MISMATCH","message":"scenePath must identify the saved active scene under Assets/. (code: SCENE_MISMATCH)"}],"success":false,"warnings":[]} + +FAIL AssertionError(('start_scene_bake', '{"command":"raw start_scene_bake","data":{"code":"MULTIPLE_SCENES","error":"Load only the target scene before baking.","reason":"Load only the target scene before baking.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"MULTIPLE_SCENES","message":"Load only the target scene before baking. (code: MULTIPLE_SCENES)"}],"success":false,"warnings":[]}\n')) +Baking E2E: passed=5 failed=1 diff --git a/docs/verification/issue-386/resume/bake-headed-final.txt b/docs/verification/issue-386/resume/bake-headed-final.txt new file mode 100644 index 00000000..0118bd75 --- /dev/null +++ b/docs/verification/issue-386/resume/bake-headed-final.txt @@ -0,0 +1,164 @@ +get_editor_info {"assetsPath": "/.cache/issue-386/staff-project/Assets", "codeIndexRoot": "/.cache/issue-386/staff-project/.unity/cache/code-index", "packagesPath": "/.cache/issue-386/staff-project/Packages", "projectRoot": "/.cache/issue-386/staff-project", "unity": {"platform": "WindowsEditor", "productName": "staff-project", "unityVersion": "6000.4.4f1"}} +PASS get_scene_bake_status returns a genuine error +PASS get_scene_bake_status rejects with JOB_NOT_FOUND: {"command":"raw get_scene_bake_status","data":{"code":"JOB_NOT_FOUND","error":"No bake job exists for this jobId in this Editor session.","reason":"No bake job exists for this jobId in this Editor session.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"JOB_NOT_FOUND","message":"No bake job exists for this jobId in this Editor session. (code: JOB_NOT_FOUND)"}],"success":false,"warnings":[]} + +execute_menu_item {"executed": true, "executionTime": 400, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Prepare Lighting", "message": "Menu item executed successfully", "success": true} +PASS Prepare Lighting +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with SCENE_MISMATCH: {"command":"raw start_scene_bake","data":{"code":"SCENE_MISMATCH","error":"scenePath must identify the saved active scene under Assets/.","reason":"scenePath must identify the saved active scene under Assets/.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"SCENE_MISMATCH","message":"scenePath must identify the saved active scene under Assets/. (code: SCENE_MISMATCH)"}],"success":false,"warnings":[]} + +start_scene_bake {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "queued", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS lighting starts tracked asynchronous job +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "lighting", "code": "BAKE_STARTED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "finalizing", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/LightingData.asset", "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_light.exr", "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_dir.png"], "backend": "lighting", "code": "BAKE_SUCCEEDED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": null, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS stable job identity +PASS lighting genuine success: {'artifacts': ['Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/LightingData.asset', 'Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_light.exr', 'Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_dir.png'], 'backend': 'lighting', 'code': 'BAKE_SUCCEEDED', 'jobId': '3749cee9acaf46a1a1eba2fc20402ae1', 'phase': 'complete', 'reason': 'Bake artifacts and saved scene references verified.', 'scenePath': 'Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity', 'status': 'succeeded', 'unityVersion': '6000.4.4f1', 'verification': {'generatedThisRun': True, 'navigationQuery': None, 'passed': True, 'persisted': True, 'sceneReferenced': True}} +PASS lighting reports version, backend and phase +PASS lighting reports nonempty artifact paths +PASS lighting artifact exists: Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/LightingData.asset +PASS lighting artifact exists: Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_light.exr +PASS lighting artifact exists: Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_dir.png +execute_menu_item {"executed": true, "executionTime": 565, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Validate Lighting", "message": "Menu item executed successfully", "success": true} +PASS Validate Lighting +PASS lighting persisted reload validation: {'target': 'Lighting', 'unityVersion': '6000.4.4f1', 'passed': True, 'error': '', 'lightmapCount': 1, 'pathCorners': 0, 'persistedAsset': 'Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/LightingData.asset'} +PASS fresh validation evidence belongs to lighting +EVIDENCE {"target": "Lighting", "unityVersion": "6000.4.4f1", "passed": true, "error": "", "lightmapCount": 1, "pathCorners": 0, "persistedAsset": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/LightingData.asset"} +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/LightingData.asset", "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_light.exr", "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting/Lightmap-0_comp_dir.png"], "backend": "lighting", "code": "BAKE_SUCCEEDED", "jobId": "3749cee9acaf46a1a1eba2fc20402ae1", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": null, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS lighting terminal result remains queryable after scene reload +execute_menu_item {"executed": true, "executionTime": 346, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Prepare Legacy", "message": "Menu item executed successfully", "success": true} +PASS Prepare Legacy +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with SCENE_MISMATCH: {"command":"raw start_scene_bake","data":{"code":"SCENE_MISMATCH","error":"scenePath must identify the saved active scene under Assets/.","reason":"scenePath must identify the saved active scene under Assets/.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"SCENE_MISMATCH","message":"scenePath must identify the saved active scene under Assets/. (code: SCENE_MISMATCH)"}],"success":false,"warnings":[]} + +start_scene_bake {"artifacts": [], "backend": "navmesh-legacy", "code": "BAKE_STARTED", "jobId": "1ff5ce13e5d249b3bff5a0b1a7750164", "phase": "queued", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS navmesh-legacy starts tracked asynchronous job +get_scene_bake_status {"artifacts": [], "backend": "navmesh-legacy", "code": "BAKE_STARTED", "jobId": "1ff5ce13e5d249b3bff5a0b1a7750164", "phase": "baking", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy/NavMesh.asset"], "backend": "navmesh-legacy", "code": "BAKE_SUCCEEDED", "jobId": "1ff5ce13e5d249b3bff5a0b1a7750164", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": true, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS stable job identity +PASS navmesh-legacy genuine success: {'artifacts': ['Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy/NavMesh.asset'], 'backend': 'navmesh-legacy', 'code': 'BAKE_SUCCEEDED', 'jobId': '1ff5ce13e5d249b3bff5a0b1a7750164', 'phase': 'complete', 'reason': 'Bake artifacts and saved scene references verified.', 'scenePath': 'Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy.unity', 'status': 'succeeded', 'unityVersion': '6000.4.4f1', 'verification': {'generatedThisRun': True, 'navigationQuery': True, 'passed': True, 'persisted': True, 'sceneReferenced': True}} +PASS navmesh-legacy reports version, backend and phase +PASS navmesh-legacy reports nonempty artifact paths +PASS navmesh-legacy artifact exists: Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy/NavMesh.asset +execute_menu_item {"executed": true, "executionTime": 579, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Validate Legacy", "message": "Menu item executed successfully", "success": true} +PASS Validate Legacy +PASS navmesh-legacy persisted reload validation: {'target': 'Legacy', 'unityVersion': '6000.4.4f1', 'passed': True, 'error': '', 'lightmapCount': 0, 'pathCorners': 2, 'persistedAsset': 'Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy/NavMesh.asset'} +PASS fresh validation evidence belongs to navmesh-legacy +EVIDENCE {"target": "Legacy", "unityVersion": "6000.4.4f1", "passed": true, "error": "", "lightmapCount": 0, "pathCorners": 2, "persistedAsset": "Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy/NavMesh.asset"} +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy/NavMesh.asset"], "backend": "navmesh-legacy", "code": "BAKE_SUCCEEDED", "jobId": "1ff5ce13e5d249b3bff5a0b1a7750164", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": true, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS navmesh-legacy terminal result remains queryable after scene reload +execute_menu_item {"executed": true, "executionTime": 325, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Prepare Surface", "message": "Menu item executed successfully", "success": true} +PASS Prepare Surface +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with surfacePath: {"command":"raw start_scene_bake","data":null,"errors":[{"code":"INVALID_ARGUMENT","message":"INVALID_ARGUMENT: Invalid parameters for tool `start_scene_bake`: $ must satisfy exactly one schema variant (matched 0); details: $.surfacePath is required"}],"success":false,"warnings":[]} + +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with SURFACE_NOT_FOUND: {"command":"raw start_scene_bake","data":{"code":"SURFACE_NOT_FOUND","error":"surfacePath must identify exactly one NavMeshSurface in the target scene.","reason":"surfacePath must identify exactly one NavMeshSurface in the target scene.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"SURFACE_NOT_FOUND","message":"surfacePath must identify exactly one NavMeshSurface in the target scene. (code: SURFACE_NOT_FOUND)"}],"success":false,"warnings":[]} + +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with SCENE_MISMATCH: {"command":"raw start_scene_bake","data":{"code":"SCENE_MISMATCH","error":"scenePath must identify the saved active scene under Assets/.","reason":"scenePath must identify the saved active scene under Assets/.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"SCENE_MISMATCH","message":"scenePath must identify the saved active scene under Assets/. (code: SCENE_MISMATCH)"}],"success":false,"warnings":[]} + +start_scene_bake {"artifacts": [], "backend": "navmesh-surface", "code": "BAKE_STARTED", "jobId": "1460193e843a4c22b9df488c8680ff44", "phase": "queued", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS navmesh-surface starts tracked asynchronous job +get_scene_bake_status {"artifacts": [], "backend": "navmesh-surface", "code": "BAKE_STARTED", "jobId": "1460193e843a4c22b9df488c8680ff44", "phase": "finalizing", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-1460193e843a4c22b9df488c8680ff44.asset"], "backend": "navmesh-surface", "code": "BAKE_SUCCEEDED", "jobId": "1460193e843a4c22b9df488c8680ff44", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": true, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS stable job identity +PASS navmesh-surface genuine success: {'artifacts': ['Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-1460193e843a4c22b9df488c8680ff44.asset'], 'backend': 'navmesh-surface', 'code': 'BAKE_SUCCEEDED', 'jobId': '1460193e843a4c22b9df488c8680ff44', 'phase': 'complete', 'reason': 'Bake artifacts and saved scene references verified.', 'scenePath': 'Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity', 'status': 'succeeded', 'unityVersion': '6000.4.4f1', 'verification': {'generatedThisRun': True, 'navigationQuery': True, 'passed': True, 'persisted': True, 'sceneReferenced': True}} +PASS navmesh-surface reports version, backend and phase +PASS navmesh-surface reports nonempty artifact paths +PASS navmesh-surface artifact exists: Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-1460193e843a4c22b9df488c8680ff44.asset +execute_menu_item {"executed": true, "executionTime": 622, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Validate Surface", "message": "Menu item executed successfully", "success": true} +PASS Validate Surface +PASS navmesh-surface persisted reload validation: {'target': 'Surface', 'unityVersion': '6000.4.4f1', 'passed': True, 'error': '', 'lightmapCount': 0, 'pathCorners': 2, 'persistedAsset': 'Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-1460193e843a4c22b9df488c8680ff44.asset'} +PASS fresh validation evidence belongs to navmesh-surface +EVIDENCE {"target": "Surface", "unityVersion": "6000.4.4f1", "passed": true, "error": "", "lightmapCount": 0, "pathCorners": 2, "persistedAsset": "Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-1460193e843a4c22b9df488c8680ff44.asset"} +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-1460193e843a4c22b9df488c8680ff44.asset"], "backend": "navmesh-surface", "code": "BAKE_SUCCEEDED", "jobId": "1460193e843a4c22b9df488c8680ff44", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": true, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS navmesh-surface terminal result remains queryable after scene reload +start_scene_bake {"artifacts": [], "backend": "navmesh-surface", "code": "BAKE_STARTED", "jobId": "e93b59e165ad4e07a7d2c53838f25092", "phase": "queued", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS rebake has an independent job identity +get_scene_bake_status {"artifacts": [], "backend": "navmesh-surface", "code": "BAKE_STARTED", "jobId": "e93b59e165ad4e07a7d2c53838f25092", "phase": "finalizing", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Surface/NavMesh-e93b59e165ad4e07a7d2c53838f25092.asset"], "backend": "navmesh-surface", "code": "BAKE_SUCCEEDED", "jobId": "e93b59e165ad4e07a7d2c53838f25092", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": true, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS stable job identity +PASS same-scene rebake succeeds +PASS rebake writes fresh artifacts +execute_menu_item {"executed": true, "executionTime": 527, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Validate Surface", "message": "Menu item executed successfully", "success": true} +PASS Validate Surface +PASS rebake persists usable NavMesh +execute_menu_item {"executed": true, "executionTime": 143, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Exclude Surface Geometry", "message": "Menu item executed successfully", "success": true} +PASS Exclude Surface Geometry +start_scene_bake {"artifacts": [], "backend": "navmesh-surface", "code": "BAKE_STARTED", "jobId": "633a415774ed4665b614afb8f1f76942", "phase": "queued", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +get_scene_bake_status {"artifacts": [], "backend": "navmesh-surface", "code": "BAKE_STARTED", "jobId": "633a415774ed4665b614afb8f1f76942", "phase": "finalizing", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "navmesh-surface", "code": "ARTIFACT_VERIFICATION_FAILED", "jobId": "633a415774ed4665b614afb8f1f76942", "phase": "failed", "reason": "Generated NavMesh cannot answer a complete path query.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", "status": "failed", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +PASS empty rebake cannot reuse old NavMesh as success +execute_menu_item {"executed": true, "executionTime": 545, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Validate Surface", "message": "Menu item executed successfully", "success": true} +PASS Validate Surface +PASS failed rebake preserves prior usable Surface data and scene assignment +execute_menu_item {"executed": true, "executionTime": 364, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Prepare Occlusion", "message": "Menu item executed successfully", "success": true} +PASS Prepare Occlusion +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with SCENE_MISMATCH: {"command":"raw start_scene_bake","data":{"code":"SCENE_MISMATCH","error":"scenePath must identify the saved active scene under Assets/.","reason":"scenePath must identify the saved active scene under Assets/.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"SCENE_MISMATCH","message":"scenePath must identify the saved active scene under Assets/. (code: SCENE_MISMATCH)"}],"success":false,"warnings":[]} + +start_scene_bake {"artifacts": [], "backend": "occlusion", "code": "BAKE_STARTED", "jobId": "5803ae1102d54f75a7bfaed2fcd834a3", "phase": "queued", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS occlusion starts tracked asynchronous job +get_scene_bake_status {"artifacts": [], "backend": "occlusion", "code": "BAKE_STARTED", "jobId": "5803ae1102d54f75a7bfaed2fcd834a3", "phase": "finalizing", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion/OcclusionCullingData.asset"], "backend": "occlusion", "code": "BAKE_SUCCEEDED", "jobId": "5803ae1102d54f75a7bfaed2fcd834a3", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": null, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS stable job identity +PASS occlusion genuine success: {'artifacts': ['Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion/OcclusionCullingData.asset'], 'backend': 'occlusion', 'code': 'BAKE_SUCCEEDED', 'jobId': '5803ae1102d54f75a7bfaed2fcd834a3', 'phase': 'complete', 'reason': 'Bake artifacts and saved scene references verified.', 'scenePath': 'Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion.unity', 'status': 'succeeded', 'unityVersion': '6000.4.4f1', 'verification': {'generatedThisRun': True, 'navigationQuery': None, 'passed': True, 'persisted': True, 'sceneReferenced': True}} +PASS occlusion reports version, backend and phase +PASS occlusion reports nonempty artifact paths +PASS occlusion artifact exists: Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion/OcclusionCullingData.asset +execute_menu_item {"executed": true, "executionTime": 600, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Validate Occlusion", "message": "Menu item executed successfully", "success": true} +PASS Validate Occlusion +PASS occlusion persisted reload validation: {'target': 'Occlusion', 'unityVersion': '6000.4.4f1', 'passed': True, 'error': '', 'lightmapCount': 0, 'pathCorners': 0, 'persistedAsset': 'Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion/OcclusionCullingData.asset'} +PASS fresh validation evidence belongs to occlusion +EVIDENCE {"target": "Occlusion", "unityVersion": "6000.4.4f1", "passed": true, "error": "", "lightmapCount": 0, "pathCorners": 0, "persistedAsset": "Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion/OcclusionCullingData.asset"} +get_scene_bake_status {"artifacts": ["Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion/OcclusionCullingData.asset"], "backend": "occlusion", "code": "BAKE_SUCCEEDED", "jobId": "5803ae1102d54f75a7bfaed2fcd834a3", "phase": "complete", "reason": "Bake artifacts and saved scene references verified.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion.unity", "status": "succeeded", "unityVersion": "6000.4.4f1", "verification": {"generatedThisRun": true, "navigationQuery": null, "passed": true, "persisted": true, "sceneReferenced": true}} +PASS occlusion terminal result remains queryable after scene reload +execute_menu_item {"executed": true, "executionTime": 433, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Prepare NoOutput", "message": "Menu item executed successfully", "success": true} +PASS Prepare NoOutput +start_scene_bake {"artifacts": [], "backend": "navmesh-surface", "code": "BAKE_STARTED", "jobId": "b3bc45b27e8b470ebbc5a39cc517ff2e", "phase": "queued", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/NoOutput/NoOutput.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +get_scene_bake_status {"artifacts": [], "backend": "navmesh-surface", "code": "BAKE_STARTED", "jobId": "b3bc45b27e8b470ebbc5a39cc517ff2e", "phase": "finalizing", "reason": "Bake accepted; poll get_scene_bake_status for verified completion.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/NoOutput/NoOutput.unity", "status": "running", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +get_scene_bake_status {"artifacts": [], "backend": "navmesh-surface", "code": "ARTIFACT_VERIFICATION_FAILED", "jobId": "b3bc45b27e8b470ebbc5a39cc517ff2e", "phase": "failed", "reason": "Generated NavMesh cannot answer a complete path query.", "scenePath": "Assets/Scenes/Generated/E2E/Baking/NoOutput/NoOutput.unity", "status": "failed", "unityVersion": "6000.4.4f1", "verification": {"passed": false}} +PASS stable job identity +PASS backend completion without navigable output is a failed job +PASS no-output job reports diagnostic code and reason +PASS failed no-output job does not report successful artifacts +PASS no-output job does not persist unusable NavMeshData +execute_menu_item {"executed": true, "executionTime": 330, "menuExists": true, "menuPath": "Tools/Unity CLI/Baking/Prepare Empty", "message": "Menu item executed successfully", "success": true} +PASS Prepare Empty +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with NO_GEOMETRY: {"command":"raw start_scene_bake","data":{"code":"NO_GEOMETRY","error":"The target scene contains no active geometry to bake.","reason":"The target scene contains no active geometry to bake.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"NO_GEOMETRY","message":"The target scene contains no active geometry to bake. (code: NO_GEOMETRY)"}],"success":false,"warnings":[]} + +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with NO_GEOMETRY: {"command":"raw start_scene_bake","data":{"code":"NO_GEOMETRY","error":"The target scene contains no active geometry to bake.","reason":"The target scene contains no active geometry to bake.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"NO_GEOMETRY","message":"The target scene contains no active geometry to bake. (code: NO_GEOMETRY)"}],"success":false,"warnings":[]} + +PASS start_scene_bake returns a genuine error +PASS start_scene_bake rejects with NO_GEOMETRY: {"command":"raw start_scene_bake","data":{"code":"NO_GEOMETRY","error":"The target scene contains no active geometry to bake.","reason":"The target scene contains no active geometry to bake.","status":"error","unityVersion":"6000.4.4f1"},"errors":[{"code":"NO_GEOMETRY","message":"The target scene contains no active geometry to bake. (code: NO_GEOMETRY)"}],"success":false,"warnings":[]} + +PASS empty scene rejection creates no bake artifacts +Baking E2E: passed=101 failed=0 diff --git a/docs/verification/issue-386/resume/bake-headed-result.json b/docs/verification/issue-386/resume/bake-headed-result.json new file mode 100644 index 00000000..741c706c --- /dev/null +++ b/docs/verification/issue-386/resume/bake-headed-result.json @@ -0,0 +1,47 @@ +{ + "argv": [ + "py", + "-3", + "-X", + "utf8", + "-B", + "scripts/e2e-bake.py", + "--unity-cli", + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "--project-root", + "\\.cache\\issue-386\\staff-project" + ], + "started_at": "2026-10-03T22:12:57.649158+00:00", + "editor_pid": 53380, + "owned_dialog_actions": [ + { + "scene": "Assets/Scenes/Generated/E2E/Baking/Lighting/Lighting.unity", + "action": "Ignore external reload, keep live bake scene", + "at": "2026-10-03T22:13:17.017866+00:00" + }, + { + "scene": "Assets/Scenes/Generated/E2E/Baking/Legacy/Legacy.unity", + "action": "Ignore external reload, keep live bake scene", + "at": "2026-10-03T22:13:23.035841+00:00" + }, + { + "scene": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", + "action": "Ignore external reload, keep live bake scene", + "at": "2026-10-03T22:13:30.057345+00:00" + }, + { + "scene": "Assets/Scenes/Generated/E2E/Baking/Surface/Surface.unity", + "action": "Ignore external reload, keep live bake scene", + "at": "2026-10-03T22:13:34.069832+00:00" + }, + { + "scene": "Assets/Scenes/Generated/E2E/Baking/Occlusion/Occlusion.unity", + "action": "Ignore external reload, keep live bake scene", + "at": "2026-10-03T22:13:42.095729+00:00" + } + ], + "exit_code": 0, + "finished_at": "2026-10-03T22:13:51.120050+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/bake-preview-green.xml b/docs/verification/issue-386/resume/bake-preview-green.xml new file mode 100644 index 00000000..6278f95e --- /dev/null +++ b/docs/verification/issue-386/resume/bake-preview-green.xml @@ -0,0 +1,3 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.PreviewSceneDoesNotBlockSavedScene + diff --git a/docs/verification/issue-386/resume/bake-preview-red.xml b/docs/verification/issue-386/resume/bake-preview-red.xml new file mode 100644 index 00000000..6e99be17 --- /dev/null +++ b/docs/verification/issue-386/resume/bake-preview-red.xml @@ -0,0 +1,25 @@ + + { + "status": "error", + "code": "MULTIPLE_SCENES", + "reason": "Load only the target scene before baking.", + "error": "Load only the target scene before baking.", + "unityVersion": "6000.4.4f1" +} + Expected string length 7 but was 5. Strings differ at index 0. + Expected: "running" + But was: "error" + -----------^ +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.BakeHandlerTests.PreviewSceneDoesNotBlockSavedScene + diff --git a/docs/verification/issue-386/resume/batch-message-green.txt b/docs/verification/issue-386/resume/batch-message-green.txt new file mode 100644 index 00000000..dd6119a6 --- /dev/null +++ b/docs/verification/issue-386/resume/batch-message-green.txt @@ -0,0 +1,8 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 20.68s + Running unittests src\main.rs (target\debug\deps\unity_cli-6f9d4071c936636c.exe) + +running 1 test +test core::failure::tests::failed_batch_preserves_first_failure_message_and_all_results ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 556 filtered out; finished in 0.00s diff --git a/docs/verification/issue-386/resume/batch-message-red.txt b/docs/verification/issue-386/resume/batch-message-red.txt new file mode 100644 index 00000000..dc7775fe --- /dev/null +++ b/docs/verification/issue-386/resume/batch-message-red.txt @@ -0,0 +1,22 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 10.43s + Running unittests src\main.rs (target\debug\deps\unity_cli-6f9d4071c936636c.exe) + +running 1 test +test core::failure::tests::failed_batch_preserves_first_failure_message_and_all_results ... FAILED + +failures: + +---- core::failure::tests::failed_batch_preserves_first_failure_message_and_all_results stdout ---- + +thread 'core::failure::tests::failed_batch_preserves_first_failure_message_and_all_results' (52600) panicked at src\core\failure.rs:166:9: +assertion failed: format!("{error:#}").contains("Failed to connect to Unity at 127.0.0.1:9") +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + +failures: + core::failure::tests::failed_batch_preserves_first_failure_message_and_all_results + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 556 filtered out; finished in 0.00s + +error: test failed, to rerun pass `--bin unity-cli` diff --git a/docs/verification/issue-386/resume/canonical-verify-second.txt b/docs/verification/issue-386/resume/canonical-verify-second.txt new file mode 100644 index 00000000..bd31da56 --- /dev/null +++ b/docs/verification/issue-386/resume/canonical-verify-second.txt @@ -0,0 +1,2 @@ +{"error":"unexpected server response: verify: deferred — host busy for 1500s (budget 1500s): verification lease held by verification 99a8660247f5bc49--verification--4d3836567f81bbf5 (pid 52908 alive, job running, nice unknown, spawn-host inherit, 2692s left, 4 batches ≈ 4102s); holder progressing: held 103m52s, its 10 working processes gained 6607ms of CPU over the last 2.8s (240.3% of one core), and its process set turned over; next_turn_reserved: yes; queue_position: 1; rerun `verify.run` in about 4102s (timing hint only; a progressing holder renews its TTL) — a deferral is not a failure and there is no attempt cap: your turn stays reserved, so keep rerunning `verify.run` while the holder makes progress","exit_code":1,"ok":false,"operation":"verify.run"} +gwtd verify.run: unexpected server response: verify: deferred — host busy for 1500s (budget 1500s): verification lease held by verification 99a8660247f5bc49--verification--4d3836567f81bbf5 (pid 52908 alive, job running, nice unknown, spawn-host inherit, 2692s left, 4 batches ≈ 4102s); holder progressing: held 103m52s, its 10 working processes gained 6607ms of CPU over the last 2.8s (240.3% of one core), and its process set turned over; next_turn_reserved: yes; queue_position: 1; rerun `verify.run` in about 4102s (timing hint only; a progressing holder renews its TTL) — a deferral is not a failure and there is no attempt cap: your turn stays reserved, so keep rerunning `verify.run` while the holder makes progress diff --git a/docs/verification/issue-386/resume/canonical-verify.txt b/docs/verification/issue-386/resume/canonical-verify.txt new file mode 100644 index 00000000..24bb87fc --- /dev/null +++ b/docs/verification/issue-386/resume/canonical-verify.txt @@ -0,0 +1,8 @@ +{ + "error": "unexpected server response: verify: deferred — host busy for 1500s (budget 1500s): verification lease held by verification 99a8660247f5bc49--verification--4d3836567f81bbf5 (pid 52908 alive, job running, nice unknown, spawn-host inherit, 2699s left, 7 batches ≈ 597s); holder progressing: held 68m20s, its 7 working processes gained 515ms of CPU over the last 5.0s (10.3% of one core), and its process set turned over; next_turn_reserved: yes; queue_position: 1; rerun `verify.run` in about 597s (timing hint only; a progressing holder renews its TTL) — a deferral is not a failure and there is no attempt cap: your turn stays reserved, so keep rerunning `verify.run` while the holder makes progress", + "exit_code": 1, + "ok": false, + "operation": "verify.run", + "output": "" +} +gwtd verify.run: unexpected server response: verify: deferred — host busy for 1500s (budget 1500s): verification lease held by verification 99a8660247f5bc49--verification--4d3836567f81bbf5 (pid 52908 alive, job running, nice unknown, spawn-host inherit, 2699s left, 7 batches ≈ 597s); holder progressing: held 68m20s, its 7 working processes gained 515ms of CPU over the last 5.0s (10.3% of one core), and its process set turned over; next_turn_reserved: yes; queue_position: 1; rerun `verify.run` in about 597s (timing hint only; a progressing holder renews its TTL) — a deferral is not a failure and there is no attempt cap: your turn stays reserved, so keep rerunning `verify.run` while the holder makes progress diff --git a/docs/verification/issue-386/resume/cargo-all-final.txt b/docs/verification/issue-386/resume/cargo-all-final.txt new file mode 100644 index 00000000..e7b019fe --- /dev/null +++ b/docs/verification/issue-386/resume/cargo-all-final.txt @@ -0,0 +1,706 @@ + Finished `test` profile [unoptimized + debuginfo] target(s) in 1.03s + Running unittests src\main.rs (target\debug\deps\unity_cli-6f9d4071c936636c.exe) + +running 558 tests +test app::editor::tests::editor_launch_uses_paths_supported_by_unity ... ok +test app::runner::tests::ambiguous_editor_fails_before_contacting_any_editor ... ok +test app::runner::tests::animation_curve_edits_accept_operations_and_tangent_modes ... ok +test app::runner::tests::animation_curve_edits_reject_missing_identifiers_and_invalid_nested_fields ... ok +test app::runner::tests::animation_curve_queries_validate_complete_binding_filters ... ok +test app::runner::tests::audio_mixer_arguments_are_action_specific ... ok +test app::runner::tests::augment_command_stats_inserts_cli_snapshot ... ok +test app::runner::tests::baking_invalid_target_missing_scene_and_missing_job_are_rejected ... ok +test app::runner::tests::baking_surface_requires_path_before_contacting_editor ... ok +test app::runner::tests::baking_valid_targets_and_polling_are_accepted ... ok +test app::runner::tests::bridge_commands_resolve_explicit_project_path ... ok +test app::runner::tests::build_reference_call_clean_defaults ... ok +test app::runner::tests::build_reference_call_clean_with_version ... ok +test app::runner::tests::build_reference_call_diff_path_mode_with_limit ... ok +test app::runner::tests::build_reference_call_diff_symbol_mode ... ok +test app::runner::tests::build_reference_call_embed_build_includes_version ... ok +test app::runner::tests::build_reference_call_embed_build_omits_optional_version ... ok +test app::runner::tests::build_reference_call_embed_search_omits_optional_top_k ... ok +test app::runner::tests::build_reference_call_embed_search_with_top_k ... ok +test app::runner::tests::build_reference_call_fetch_carries_all_flags ... ok +test app::runner::tests::build_reference_call_fetch_defaults_without_overrides ... ok +test app::runner::tests::build_reference_call_find_symbol_minimal ... ok +test app::runner::tests::build_reference_call_find_symbol_with_filters ... ok +test app::runner::tests::build_reference_call_grep_defaults_context_to_zero ... ok +test app::runner::tests::build_reference_call_grep_with_file_glob_and_context ... ok +test app::runner::tests::build_reference_call_resolve_symbol_at_minimal ... ok +test app::runner::tests::build_reference_call_resolve_symbol_at_with_version ... ok +test app::runner::tests::build_reference_call_search_minimal_pattern ... ok +test app::runner::tests::build_reference_call_search_with_all_options ... ok +test app::runner::tests::build_reference_call_status_includes_explicit_version ... ok +test app::runner::tests::build_reference_call_status_omits_optional_version ... ok +test app::runner::tests::build_reference_call_view_omits_optional_lines ... ok +test app::runner::tests::build_reference_call_view_with_range ... ok +test app::runner::tests::capture_screenshot_timeout_respects_os_fallback_flag ... ok +test app::runner::tests::env_var_guard_restores_previous_value ... ok +test app::runner::tests::eval_cli_accepts_code_and_rejects_invalid_mode ... ok +test app::runner::tests::eval_dry_run_does_not_execute_arbitrary_code ... ok +test app::runner::tests::eval_schemas_require_code_and_status_id ... ok +test app::runner::tests::eval_transport_error_keeps_generated_request_id ... ok +test app::runner::tests::execute_tool_skips_mutating_tool_in_dry_run_mode ... ok +test app::runner::tests::hot_reload_requires_revision_and_explicit_action ... ok +test app::runner::tests::init_tracing_accepts_verbose_levels ... ok +test app::runner::tests::instances_list_defaults_host_to_ipv4_loopback ... ok +test app::runner::tests::load_params_defaults_to_empty_object ... ok +test app::runner::tests::load_params_reads_inline_json ... ok +test app::runner::tests::load_params_reads_json_from_file ... ok +test app::runner::tests::load_params_rejects_when_json_and_params_file_are_both_set ... ok +test app::runner::tests::parse_external_tool_command_accepts_json_flag ... ok +test app::runner::tests::parse_external_tool_command_rejects_unknown_flag ... ok +test app::runner::tests::parse_external_tool_command_requires_tool_name ... ok +test app::runner::tests::parse_external_tool_command_requires_values_for_flags ... ok +test app::runner::tests::parse_external_tool_command_supports_equals_forms ... ok +test app::runner::tests::parse_json_object_accepts_object ... ok +test app::runner::tests::parse_json_object_rejects_non_object ... ok +test app::runner::tests::parse_ports_deduplicates_values ... ok +test app::runner::tests::parse_ports_rejects_invalid_values ... ok +test app::runner::tests::parse_ports_returns_empty_for_none ... ok +test app::runner::tests::parse_ports_with_diagnostics_reports_duplicate_values ... ok +test app::runner::tests::ping_version_check_reports_mismatch_and_unknown ... ok +test app::runner::tests::prefab_override_validation_requires_explicit_scope_and_apply_target ... ok +test app::runner::tests::print_value_text_handles_string_and_object ... ok +test app::runner::tests::project_path_flag_is_global_and_feeds_runtime_overrides ... ok +test app::runner::tests::run_with_cli_batch_marks_skipped_items_in_dry_run_mode ... ok +test app::runner::tests::run_with_cli_exercises_remote_command_error_paths ... ok +test app::runner::tests::run_with_cli_handles_instances_and_daemon_commands_without_server ... ok +test app::runner::tests::run_with_cli_handles_local_tool_and_batch_paths ... ok +test app::runner::tests::run_with_cli_rejects_unknown_external_tool ... ok +test app::runner::tests::run_with_cli_requires_batch_input_source ... ok +test app::runner::tests::run_with_cli_set_active_text_output_when_reachable ... ok +test app::runner::tests::run_with_cli_supports_tool_schema_command ... ok +test app::runner::tests::runtime_overrides_are_derived_from_cli_at_app_boundary ... ok +test app::runner::tests::setup_and_bridge_cli_arguments_parse ... ok +test app::runner::tests::timeline_manage_is_skipped_in_dry_run ... ok +test app::runner::tests::timeline_validation_requires_target_and_valid_action ... ok +test app::runner::tests::validate_tool_params_accepts_add_component_payload ... ok +test app::runner::tests::validate_tool_params_accepts_addressables_manage_add_entry ... ok +test app::runner::tests::validate_tool_params_accepts_analyze_asset_dependencies_get_dependencies ... ok +test app::runner::tests::validate_tool_params_accepts_build_index_output_path ... ok +test app::runner::tests::validate_tool_params_accepts_create_animation_clip_payload ... ok +test app::runner::tests::validate_tool_params_accepts_create_animator_controller_payload ... ok +test app::runner::tests::validate_tool_params_accepts_create_gameobject_with_vector_fields ... ok +test app::runner::tests::validate_tool_params_accepts_create_sprite_atlas_payload ... ok +test app::runner::tests::validate_tool_params_accepts_delete_gameobject_with_path_and_paths ... ok +test app::runner::tests::validate_tool_params_accepts_execute_menu_item_get_available_menus ... ok +test app::runner::tests::validate_tool_params_accepts_execute_menu_item_without_action ... ok +test app::runner::tests::validate_tool_params_accepts_get_input_actions_state_with_asset_path ... ok +test app::runner::tests::validate_tool_params_accepts_input_keyboard_batch_actions ... ok +test app::runner::tests::validate_tool_params_accepts_load_scene_by_name ... ok +test app::runner::tests::validate_tool_params_accepts_lsp_write_payload_with_path_alias ... ok +test app::runner::tests::validate_tool_params_accepts_manage_layers_get_by_index ... ok +test app::runner::tests::validate_tool_params_accepts_package_manager_list_action ... ok +test app::runner::tests::validate_tool_params_accepts_profiler_start_payload ... ok +test app::runner::tests::validate_tool_params_accepts_valid_payload ... ok +test app::runner::tests::validate_tool_params_accepts_write_csharp_file_payload ... ok +test app::runner::tests::validate_tool_params_rejects_addressables_analyze_dependencies_without_asset_path ... ok +test app::runner::tests::validate_tool_params_rejects_addressables_manage_move_entry_without_target_group ... ok +test app::runner::tests::validate_tool_params_rejects_analyze_asset_dependencies_get_dependencies_without_asset_path ... ok +test app::runner::tests::validate_tool_params_rejects_analyze_asset_dependencies_invalid_action ... ok +test app::runner::tests::validate_tool_params_rejects_analyze_screenshot_without_source ... ok +test app::runner::tests::validate_tool_params_rejects_create_animation_clip_without_sprite_paths ... ok +test app::runner::tests::validate_tool_params_rejects_create_package_setting_without_value ... ok +test app::runner::tests::validate_tool_params_rejects_delete_gameobject_without_target ... ok +test app::runner::tests::validate_tool_params_rejects_execute_menu_item_without_action_or_menu_path ... ok +test app::runner::tests::validate_tool_params_rejects_execute_menu_item_without_menu_path ... ok +test app::runner::tests::validate_tool_params_rejects_invalid_animator_condition_mode ... ok +test app::runner::tests::validate_tool_params_rejects_invalid_sprite_atlas_filter_mode ... ok +test app::runner::tests::validate_tool_params_rejects_load_scene_with_both_identifiers ... ok +test app::runner::tests::validate_tool_params_rejects_manage_asset_database_move_without_to_path ... ok +test app::runner::tests::validate_tool_params_rejects_manage_layers_add_without_layer_name ... ok +test app::runner::tests::validate_tool_params_rejects_manage_layers_invalid_action ... ok +test app::runner::tests::validate_tool_params_rejects_manage_selection_set_without_object_paths ... ok +test app::runner::tests::validate_tool_params_rejects_manage_tools_activate_without_tool_name ... ok +test app::runner::tests::validate_tool_params_rejects_manage_windows_focus_without_window_type ... ok +test app::runner::tests::validate_tool_params_rejects_missing_required_property ... ok +test app::runner::tests::validate_tool_params_rejects_package_manager_search_without_keyword ... ok +test app::runner::tests::validate_tool_params_rejects_registry_config_add_scope_without_scope ... ok +test app::runner::tests::validate_tool_params_rejects_remove_input_binding_without_selector ... ok +test app::runner::tests::validate_tool_params_rejects_set_component_field_missing_required ... ok +test app::runner::tests::validate_tool_params_rejects_unknown_field_for_clear_logs ... ok +test app::runner::tests::validate_tool_params_rejects_unknown_property_when_schema_is_strict ... ok +test app::runner::tests::validate_tool_params_rejects_unknown_run_tests_property ... ok +test app::setup::tests::hub_paths_for_windows_and_linux_do_not_depend_on_test_host ... ok +test app::setup::tests::launch_editor_skips_when_project_is_locked_and_errors_without_editor ... ok +test app::setup::tests::project_unity_version_and_hub_path ... ok +test app::setup::tests::setup_dry_run_leaves_editor_unchecked_and_skips_writes ... ok +test app::setup::tests::setup_flags_editor_serving_another_project ... ok +test app::setup::tests::setup_installs_bridge_and_confirms_matching_editor ... ok +test app::setup::tests::setup_reports_version_mismatch_as_json ... ok +test app::setup::tests::setup_without_dry_run_reports_unreachable_editor ... ok +test app::test_report::tests::github_annotations_extract_unity_location_and_escape_injection ... ok +test app::test_report::tests::junit_preserves_failed_skipped_and_escaped_details ... ok +test app::test_report::tests::junit_time_is_millisecond_precision_for_xunit_schema ... ok +test app::test_report::tests::nunit_nests_test_cases_in_a_suite_and_preserves_details ... ok +test app::test_report::tests::parent_suite_rollups_do_not_duplicate_leaf_failures ... ok +test app::test_report::tests::suite_failure_is_reported_even_without_failed_leaves ... ok +test cli::test_command_tests::test_command_accepts_report_output_without_changing_global_output ... ok +test core::bridge::tests::dry_run_reports_change_without_writing ... ok +test core::bridge::tests::embedded_package_is_reported_and_not_duplicated ... ok +test core::bridge::tests::input_backends_untouched_when_setting_absent_or_already_enabled ... ok +test core::bridge::tests::install_adds_openupm_registry_and_cli_version ... ok +test core::bridge::tests::install_adds_scope_to_existing_openupm_registry ... ok +test core::bridge::tests::install_enables_input_system_backends_while_editor_is_closed ... ok +test core::bridge::tests::install_is_noop_when_already_configured_by_hand ... ok +test core::bridge::tests::install_keeps_other_version_and_upgrade_pins_cli_version ... ok +test core::bridge::tests::install_leaves_input_backends_when_editor_is_open_or_dry_run ... ok +test core::bridge::tests::install_twice_leaves_manifest_byte_identical ... ok +test core::bridge::tests::rejects_malformed_manifest ... ok +test core::bridge::tests::resolve_project_root_walks_up_and_validates_explicit_path ... ok +test core::bridge::tests::status_prefers_lock_resolution_and_reports_missing ... ok +test core::bridge::tests::upgrade_leaves_custom_sources_alone ... ok +test core::bridge::tests::version_check_classifies_versions ... ok +test core::command_stats::tests::snapshot_groups_calls_by_tool_and_route ... ok +test core::config::tests::default_host_returns_ipv4_loopback_without_env ... ok +test core::config::tests::default_port_returns_6400_without_env ... ok +test core::config::tests::default_timeout_returns_30000_without_env ... ok +test core::config::tests::empty_value_is_ignored ... ok +test core::config::tests::execution_context_uses_defaults ... ok +test core::config::tests::fails_when_legacy_alias_is_set ... ok +test core::config::tests::fails_when_removed_unityd_env_is_set ... ok +test core::config::tests::returns_none_when_no_keys_set ... ok +test core::config::tests::u16_env_parses_correctly ... ok +test core::config::tests::u16_env_rejects_zero ... ok +test core::config::tests::u64_env_parses_correctly ... ok +test core::config::tests::u64_env_rejects_zero ... ok +test core::doctor::tests::classification_priority ... ok +test core::doctor::tests::editor_import_workers_are_not_reusable_editors ... ok +test core::doctor::tests::parses_safe_mode_and_latest_compile_errors ... ok +test core::doctor::tests::reads_bridge_version_from_local_file_dependency ... ok +test core::doctor::tests::reads_project_bridge_port ... ok +test core::doctor::tests::recognizes_editor_command_lines_only ... ok +test core::doctor::tests::reports_editor_not_running ... ok +test core::doctor::tests::reports_port_in_use_with_owner_pid ... ok +test core::doctor::tests::safe_mode_exit_clears_flag ... ok +test core::editor_discovery::tests::ambiguous_error_json_lists_candidates ... ok +test core::editor_discovery::tests::dead_pid_marks_lockfile_stale ... ok +test core::editor_discovery::tests::discover_reads_lockfiles_and_skips_garbage ... ok +test core::editor_discovery::tests::expired_heartbeat_marks_lockfile_stale ... ok +test core::editor_discovery::tests::pid_zero_is_never_alive ... ok +test core::editor_discovery::tests::select_for_path_ignores_stale_editors_and_sibling_prefixes ... ok +test core::editor_discovery::tests::select_for_path_prefers_deepest_live_project ... ok +test core::endpoint::tests::active_instance_keeps_priority_over_lockfile_discovery ... ok +test core::endpoint::tests::cli_override_wins_over_active_instance ... ok +test core::endpoint::tests::cwd_inside_project_selects_that_editor ... ok +test core::endpoint::tests::cwd_outside_projects_with_two_editors_is_ambiguous ... ok +test core::endpoint::tests::env_port_wins_when_no_cli_override ... ok +test core::endpoint::tests::explicit_port_wins_over_project_path_and_lockfiles ... ok +test core::endpoint::tests::no_lockfiles_keeps_legacy_default ... ok +test core::endpoint::tests::project_command_targets_its_own_editor_among_several ... ok +test core::endpoint::tests::project_command_without_its_editor_uses_default_endpoint ... ok +test core::endpoint::tests::project_path_selects_matching_editor ... ok +test core::endpoint::tests::project_path_without_running_editor_is_not_found ... ok +test core::endpoint::tests::project_root_env_falls_back_to_default_without_any_lockfile ... ok +test core::endpoint::tests::single_running_editor_is_used_from_anywhere ... ok +test core::endpoint::tests::stale_editors_do_not_cause_ambiguity ... ok +test core::endpoint::tests::unity_project_root_env_acts_as_project_path ... ok +test core::failure::tests::failed_batch_preserves_first_failure_message_and_all_results ... ok +test core::instances::tests::authenticated_health_checks_support_listing_and_selection ... ok +test core::instances::tests::list_instances_adds_default_port_when_no_entries_exist ... ok +test core::instances::tests::list_instances_enumerates_lockfiles_without_ports ... ok +test core::instances::tests::list_instances_keeps_explicit_ports_next_to_lockfiles ... ok +test core::instances::tests::list_instances_reports_down_for_tcp_listener_that_is_not_unity_bridge ... ok +test core::instances::tests::list_instances_reports_up_for_reachable_port ... ok +test core::instances::tests::load_registry_reconstructs_missing_ids ... ok +test core::instances::tests::parse_id_validates_shape ... ok +test core::instances::tests::registry_path_uses_env_and_creates_parent_directory ... ok +test core::instances::tests::registry_round_trip_serialization_shape_is_supported ... ok +test core::instances::tests::set_active_fails_for_unreachable_instance ... ok +test core::instances::tests::set_active_succeeds_for_reachable_instance_and_tracks_previous ... ok +test core::managed_binaries::tests::cache_root_falls_back_to_home_unity_cache ... ok +test core::managed_binaries::tests::cache_root_prefers_unity_cli_cache_root_env ... ok +test core::managed_binaries::tests::detect_rid_returns_known_target_triple ... ok +test core::managed_binaries::tests::download_latest_binary_applies_matching_checksum ... ok +test core::managed_binaries::tests::download_latest_binary_rejects_checksum_mismatch_and_keeps_existing_install ... ok +test core::managed_binaries::tests::ensure_latest_for_can_skip_remote_checks_in_tests ... ok +test core::managed_binaries::tests::ensure_local_uses_existing_binary_without_download ... ok +test core::managed_binaries::tests::get_json_fails_with_status_and_body ... ok +test core::managed_binaries::tests::get_json_parses_http_body ... ok +test core::managed_binaries::tests::get_json_retries_transient_server_error ... ok +test core::managed_binaries::tests::get_optional_text_returns_body_for_success ... ok +test core::managed_binaries::tests::get_optional_text_returns_none_for_not_found ... ok +test core::managed_binaries::tests::get_response_includes_authorization_header ... ok +test core::managed_binaries::tests::get_response_reports_http_status_errors ... ok +test core::managed_binaries::tests::parse_sha256sums_reads_text_and_binary_mode_entries ... ok +test core::managed_binaries::tests::read_local_version_returns_none_for_missing_or_blank_file ... ok +test core::managed_binaries::tests::replace_file_atomic_overwrites_destination ... ok +test core::managed_binaries::tests::sha256_file_matches_known_hash ... ok +test core::managed_binaries::tests::tools_root_falls_back_to_home_unity_tools_when_env_unset ... ok +test core::managed_binaries::tests::tools_root_prefers_unity_cli_tools_root_env ... ok +test core::managed_binaries::tests::unity_cli_status_uses_managed_install_layout ... ok +test core::managed_binaries::tests::verify_manifest_against_checksums_requires_matching_entry ... ok +test core::managed_binaries::tests::write_and_read_local_version_round_trip ... ok +test core::runtime_paths::tests::daemon_dir_is_under_run_root ... ok +test core::self_update::tests::is_recent_returns_false_for_missing_path ... ok +test core::self_update::tests::is_recent_returns_true_for_freshly_touched_file ... ok +test core::self_update::tests::last_check_path_uses_unity_cli_tools_root_env ... ok +test core::self_update::tests::maybe_self_update_skipped_when_opt_out_env_set ... ok +test core::self_update::tests::maybe_self_update_skips_when_recent_check_exists ... ok +test core::self_update::tests::touch_creates_parent_and_writes_marker ... ok +test core::self_update::tests::warn_cargo_conflict_runs_without_panic ... ok +test daemon::runtime::tests::runtime_module_builds_without_warnings_when_unix_code_is_disabled ... ok +test daemon::spawn::tests::spawn_detached_starts_the_command ... ok +test daemon::spawn::tests::spawn_module_builds_for_windows_without_warnings ... ok +test daemon::spawn::tests::spawned_child_does_not_hold_the_callers_stdout_pipe ... ok +test daemon::unityd::tests::daemon_call_error_classification ... ok +test daemon::unityd::tests::daemon_request_batch_round_trip ... ok +test daemon::unityd::tests::daemon_request_ping_round_trip ... ok +test daemon::unityd::tests::daemon_request_status_round_trip ... ok +test daemon::unityd::tests::daemon_request_stop_round_trip ... ok +test daemon::unityd::tests::daemon_request_tool_round_trip ... ok +test daemon::unityd::tests::daemon_response_error_round_trip ... ok +test daemon::unityd::tests::daemon_response_round_trip ... ok +test daemon::unityd::tests::daemon_response_round_trip_preserves_timing ... ok +test daemon::unityd::tests::idle_timeout_default ... ok +test daemon::unityd::tests::pid_file_path_is_under_tools_dir ... ok +test daemon::unityd::tests::pooled_connection_closed_by_editor_restart_is_reconnected_before_sending ... ok +test daemon::unityd::tests::pooled_connection_uses_each_requests_timeout ... ok +test daemon::unityd::tests::request_lost_after_sending_is_reported_and_not_resent ... ok +test daemon::unityd::tests::startup_lock_times_out_and_is_reusable_after_release ... ok +test daemon::unityd::tests::tools_dir_creates_directory ... ok +test lsp::client::tests::collect_document_symbols_flattens_nested_symbols ... ok +test lsp::client::tests::get_apply_defaults_to_false ... ok +test lsp::client::tests::id_matches_accepts_number_and_string_id ... ok +test lsp::client::tests::kind_from_lsp_maps_known_values ... ok +test lsp::client::tests::normalize_lsp_write_result_adds_contract_fields ... ok +test lsp::client::tests::normalize_rel_path_accepts_assets_packages_and_library ... ok +test lsp::client::tests::normalize_rel_path_extracts_supported_prefix_from_absolute_like_input ... ok +test lsp::client::tests::normalize_rel_path_rejects_parent_traversal ... ok +test lsp::client::tests::path_matches_scope_filters_paths ... ok +test lsp::client::tests::remove_symbol_request_includes_fail_on_references_when_set ... ok +test lsp::client::tests::remove_symbol_request_omits_fail_on_references_when_unset ... ok +test lsp::client::tests::require_helpers_validate_expected_fields ... ok +test lsp::client::tests::retryable_session_error_detects_transport_failures ... ok +test lsp::client::tests::retryable_session_error_ignores_argument_errors ... ok +test lsp::client::tests::to_project_relative_or_raw_returns_relative_for_absolute_under_root ... ok +test lsp::client::tests::uri_and_ref_path_helpers_resolve_project_relative_paths ... ok +test lsp::client::tests::uri_to_rel_path_rejects_non_file_uris ... ok +test lsp::daemon::tests::daemon_idle_timeout_uses_env_override ... ok +test lsp::daemon::tests::handle_request_handles_ping_status_and_stop ... ok +test lsp::daemon::tests::is_would_block_checks_error_kind ... ok +test lsp::daemon::tests::write_all_with_retry_handles_would_block_and_partial_writes ... ok +test lsp::daemon::tests::write_all_with_retry_rejects_zero_byte_progress ... ok +test lsp::daemon::tests::write_pid_file_and_cleanup_manage_files_under_tools_root ... ok +test mcp::configure::tests::custom_root_may_have_missing_ancestors_without_creating_them ... ok +test mcp::configure::tests::invalid_config_is_never_overwritten_and_preview_creates_nothing ... ok +test mcp::configure::tests::malformed_shapes_and_http_name_collisions_are_rejected ... ok +test mcp::configure::tests::merges_inline_toml_without_losing_other_servers_or_options ... ok +test mcp::configure::tests::windows_and_local_paths ... ok +test mcp::tests::projects_owned_custom_descriptor_without_an_mcp_specific_schema ... ok +test reference::cache::tests::gc_empty_root_returns_empty ... ok +test reference::cache::tests::gc_keep_zero_removes_all_versions ... ok +test reference::cache::tests::gc_keeps_n_newest_and_returns_removed ... ok +test reference::cache::tests::gc_skips_non_directory_entries ... ok +test reference::cache::tests::list_versions_empty_when_root_missing ... ok +test reference::cache::tests::list_versions_returns_existing_dirs ... ok +test reference::cache::tests::list_versions_skips_files_in_root ... ok +test reference::cache::tests::meta_roundtrip ... ok +test reference::cache::tests::read_meta_returns_error_for_invalid_json ... ok +test reference::cache::tests::read_meta_returns_error_when_missing ... ok +test reference::cache::tests::version_dir_rejects_empty ... ok +test reference::cache::tests::version_dir_rejects_paths_outside_single_cache_entry ... ok +test reference::cache::tests::version_dir_under_cache_root ... ok +test reference::diff::tests::compute_line_diff_empty_for_identical_lines ... ok +test reference::diff::tests::compute_line_diff_for_deletes_only_returns_removal_hunk ... ok +test reference::diff::tests::compute_line_diff_for_inserts_only_returns_addition_hunk ... ok +test reference::diff::tests::compute_line_diff_for_separate_changes_produces_multiple_hunks ... ok +test reference::diff::tests::compute_line_diff_replacement_isolates_changed_lines ... ok +test reference::diff::tests::compute_path_diff_can_be_truncated ... ok +test reference::diff::tests::compute_path_diff_categorises_runtime_export ... ok +test reference::diff::tests::compute_symbol_diff_detects_changed_animator ... ok +test reference::diff::tests::compute_symbol_diff_returns_diff_when_only_one_side_has_symbol ... ok +test reference::diff::tests::compute_symbol_diff_returns_none_for_missing_in_both ... ok +test reference::diff::tests::ensure_cache_dir_errors_on_missing ... ok +test reference::diff::tests::split_fqn_separates_namespace_and_name ... ok +test reference::embed::tests::build_embedding_index_handles_empty_symbol_index ... ok +test reference::embed::tests::build_embedding_index_with_mock_embedder ... ok +test reference::embed::tests::cosine_similarity_handles_zero_vectors ... ok +test reference::embed::tests::embedding_roundtrip_via_bincode ... ok +test reference::embed::tests::resolve_onnxruntime_dylib_explains_how_to_install_when_missing ... ok +test reference::embed::tests::resolve_onnxruntime_dylib_falls_back_to_first_existing_candidate ... ok +test reference::embed::tests::resolve_onnxruntime_dylib_prefers_existing_env_path ... ok +test reference::embed::tests::resolve_onnxruntime_dylib_rejects_missing_env_path ... ok +test reference::embed::tests::search_ranks_by_cosine_similarity ... ok +test reference::embed::tests::search_returns_empty_for_empty_index ... ok +test reference::embed::tests::search_returns_empty_for_empty_query ... ok +test reference::embed::tests::symbol_to_text_includes_namespace_and_kind ... ok +test reference::embed::tests::symbol_to_text_without_namespace_omits_dot ... ok +test reference::fetcher::tests::api_discovery_paginates_branches_and_includes_tags ... ok +test reference::fetcher::tests::api_discovery_surfaces_http_errors ... ok +test reference::fetcher::tests::archive_url_uses_unity_cs_reference_org ... ok +test reference::fetcher::tests::build_clone_args_emits_shallow_single_branch ... ok +test reference::fetcher::tests::ensure_git_available_succeeds_in_test_env ... ok +test reference::fetcher::tests::extract_zip_to_rejects_entries_with_parent_segments ... ok +test reference::fetcher::tests::extract_zip_to_strips_top_level_prefix_and_writes_files ... ok +test reference::fetcher::tests::fetch_selected_checks_out_long_windows_paths_without_global_configuration ... ok +test reference::fetcher::tests::fetch_selected_pins_commit_after_branch_advances ... ok +test reference::fetcher::tests::fetch_selected_rejects_invalid_commit_before_creating_destination ... ok +test reference::fetcher::tests::github_token_returns_none_when_env_unset ... ok +test reference::fetcher::tests::github_token_skips_empty_and_picks_first_non_empty ... ok +test reference::fetcher::tests::license_ok_when_env_set ... ok +test reference::fetcher::tests::license_ok_when_flag_true ... ok +test reference::fetcher::tests::license_rejects_zero_value ... ok +test reference::fetcher::tests::license_required_when_flag_false_and_env_unset ... ok +test reference::fetcher::tests::list_public_refs_discovers_branches_and_tags ... ok +test reference::fetcher::tests::list_public_refs_preserves_transport_error ... ok +test reference::fetcher::tests::public_refs_use_basic_authentication_for_git_http ... ok +test reference::fetcher::tests::run_clone_rejects_when_license_not_accepted ... ok +test reference::index::tests::build_or_update_index_handles_existing_fixture ... ok +test reference::index::tests::build_or_update_index_persists_signature ... ok +test reference::index::tests::build_or_update_index_skips_already_indexed_files_until_change ... ok +test reference::index::tests::extract_symbols_from_text_captures_namespace ... ok +test reference::index::tests::extract_symbols_from_text_does_not_double_capture_class_name ... ok +test reference::index::tests::extract_symbols_from_text_finds_class ... ok +test reference::index::tests::extract_symbols_from_text_finds_methods ... ok +test reference::index::tests::extract_symbols_from_text_finds_property ... ok +test reference::index::tests::extract_symbols_from_text_finds_struct_and_interface ... ok +test reference::index::tests::file_signature_changes_when_content_changes ... ok +test reference::index::tests::find_symbol_filters_by_kind_and_namespace ... ok +test reference::index::tests::validate_kind_accepts_known_and_rejects_unknown ... ok +test reference::search::tests::grep_filters_by_filename_glob ... ok +test reference::search::tests::grep_finds_class_animator_with_line_numbers ... ok +test reference::search::tests::grep_returns_context_lines ... ok +test reference::search::tests::view_rejects_parent_traversal ... ok +test reference::search::tests::view_returns_requested_line_range ... ok +test reference::tests::cached_fetch_and_status_report_stored_provenance ... ok +test reference::tests::cached_unknown_version_can_be_used_without_branch_resolution ... ok +test reference::tests::dir_size_empty_returns_zero ... ok +test reference::tests::dir_size_sums_file_lengths ... ok +test reference::tests::execute_clean_dry_run_false_actually_removes ... ok +test reference::tests::execute_clean_dry_run_on_empty_cache_returns_empty_removed ... ok +test reference::tests::execute_diff_errors_when_cache_missing ... ok +test reference::tests::execute_diff_path_mode_returns_added_removed_changed ... ok +test reference::tests::execute_diff_requires_from_and_to ... ok +test reference::tests::execute_diff_requires_symbol_or_path ... ok +test reference::tests::execute_diff_symbol_mode_returns_diffs ... ok +test reference::tests::execute_embed_build_errors_when_cache_missing ... ok +test reference::tests::execute_embed_search_errors_when_index_missing ... ok +test reference::tests::execute_embed_search_requires_query ... ok +test reference::tests::execute_fetch_force_preserves_existing_on_transport_failure ... ok +test reference::tests::execute_fetch_skips_when_destination_exists_without_force ... ok +test reference::tests::execute_find_symbol_empty_hits_for_unknown_name ... ok +test reference::tests::execute_find_symbol_filters_namespace ... ok +test reference::tests::execute_find_symbol_rejects_unknown_kind ... ok +test reference::tests::execute_find_symbol_requires_name ... ok +test reference::tests::execute_find_symbol_returns_error_when_cache_missing ... ok +test reference::tests::execute_find_symbol_returns_hits_from_fixture ... ok +test reference::tests::execute_grep_invalid_regex_returns_error ... ok +test reference::tests::execute_grep_requires_pattern ... ok +test reference::tests::execute_grep_supports_file_glob_filter ... ok +test reference::tests::execute_grep_via_dispatcher_returns_hits ... ok +test reference::tests::execute_resolve_symbol_at_empty_token_for_blank_position ... ok +test reference::tests::execute_resolve_symbol_at_finds_token_via_fixture ... ok +test reference::tests::execute_resolve_symbol_at_requires_path_line_column ... ok +test reference::tests::execute_resolve_symbol_at_requires_project_prefix ... ok +test reference::tests::execute_search_requires_pattern ... ok +test reference::tests::execute_search_via_dispatcher_truncates_max_results ... ok +test reference::tests::execute_search_without_max_results_returns_all_hits ... ok +test reference::tests::execute_status_includes_size_bytes ... ok +test reference::tests::execute_status_returns_versions_list ... ok +test reference::tests::execute_view_rejects_parent_traversal_via_dispatcher ... ok +test reference::tests::execute_view_requires_path_param ... ok +test reference::tests::execute_view_via_dispatcher_returns_lines ... ok +test reference::tests::extract_token_at_cursor_handles_edge_cases ... ok +test reference::tests::extract_token_at_cursor_handles_escaped_quote_in_string ... ok +test reference::tests::extract_token_at_cursor_returns_ident_after_closed_string ... ok +test reference::tests::extract_token_at_cursor_skips_line_comment ... ok +test reference::tests::extract_token_at_cursor_skips_string_literal ... ok +test reference::tests::fetch_resolves_project_and_explicit_refs_and_records_actual_commit ... ok +test reference::tests::legacy_metadata_keeps_unknown_match_instead_of_claiming_exact ... ok +test reference::tests::maybe_execute_returns_none_for_unknown_tool ... ok +test reference::tests::now_unix_seconds_string_is_decimal ... ok +test reference::tests::resolve_version_falls_back_to_project_detection ... ok +test reference::tests::resolve_version_uses_explicit_param ... ok +test reference::version::tests::ambiguous_auto_candidates_and_unknown_versions_return_candidates ... ok +test reference::version::tests::detect_returns_error_when_editor_version_line_absent ... ok +test reference::version::tests::detect_returns_error_when_editor_version_value_empty ... ok +test reference::version::tests::detect_returns_error_when_project_version_missing ... ok +test reference::version::tests::exact_tag_precedes_minor_but_version_named_head_is_not_exact ... ok +test reference::version::tests::explicit_ref_has_priority_and_ambiguous_short_names_require_full_ref ... ok +test reference::version::tests::minor_version_key_rejects_invalid_inputs ... ok +test reference::version::tests::parse_editor_version_returns_value_directly ... ok +test reference::version::tests::parses_remote_refs_with_peeled_tag_commits_in_any_order ... ok +test reference::version::tests::public_resolver_handles_previously_supported_minors ... ok +test reference::version::tests::reads_known_project_version ... ok +test reference::version::tests::reads_unknown_minor_without_static_mapping ... ok +test reference::version::tests::selects_new_and_existing_minor_branches_without_claiming_exact_match ... ok +test skills::loader::tests::load_skills_handles_missing_root_and_skips_non_skill_entries ... ok +test skills::loader::tests::load_skills_supports_single_skill_root_and_dir_name_fallback ... ok +test skills::loader::tests::parse_frontmatter_and_collect_references_cover_optional_branches ... ok +test skills::loader::tests::parse_frontmatter_extracts_metadata ... ok +test skills::loader::tests::split_frontmatter_and_parse_frontmatter_cover_edge_cases ... ok +test skills::loader::tests::split_frontmatter_handles_basic_skill ... ok +test skills::tests::good_skill_passes_all_rules ... ok +test skills::tests::model_helpers_cover_skill_accessors_and_tool_sets ... ok +test skills::tests::r01_missing_description_fires ... ok +test skills::tests::r01_missing_multiple_required_fields_fire ... ok +test skills::tests::r02_name_mismatch_fires ... ok +test skills::tests::r03_disallowed_tool_fires ... ok +test skills::tests::r03_legacy_bare_bash_fires ... ok +test skills::tests::r04_unknown_category_fires ... ok +test skills::tests::r05_empty_and_duplicate_triggers_fire ... ok +test skills::tests::r05_uppercase_trigger_fires ... ok +test skills::tests::r06_unknown_sibling_fires ... ok +test skills::tests::r07_too_long_description_fires ... ok +test skills::tests::r08_missing_front_trigger_fires ... ok +test skills::tests::r09_first_person_fires ... ok +test skills::tests::r10_missing_use_when_fires ... ok +test skills::tests::r11_missing_sibling_mention_fires ... ok +test skills::tests::r12_unidirectional_sibling_fires ... ok +test skills::tests::r13_too_long_body_fires ... ok +test skills::tests::r14_missing_heading_fires ... ok +test skills::tests::r15_references_without_link_fires ... ok +test skills::tests::r16_time_sensitive_phrase_fires ... ok +test skills::tests::r17_missing_runtime_checklist_fires ... ok +test skills::tests::r18_long_reference_without_toc_fires ... ok +test skills::tests::r19_reference_link_to_reference_fires ... ok +test skills::tests::r20_and_r21_validate_windows_git_symlink_placeholders ... ok +test skills::tests::r22_collision_without_cross_listing_fires ... ok +test skills::tests::report_and_runner_cover_text_json_discovery_and_error_paths ... ok +test test_env::isolated_runtime_restores_inherited_environment_after_unwind ... ok +test tooling::discovery::tests::bridge_reserved_names_match_the_cli_catalog_including_local_tools ... ok +test tooling::discovery::tests::builtin_descriptors_keep_schemas_and_mark_their_source ... ok +test tooling::discovery::tests::custom_descriptor_roundtrips_owned_names_and_schema ... ok +test tooling::discovery::tests::list_tools_is_a_read_only_remote_builtin ... ok +test tooling::local_tools::tests::build_index_and_find_symbol_roundtrip ... ok +test tooling::local_tools::tests::collect_cs_files_and_index_helpers_cover_readiness_branches ... ok +test tooling::local_tools::tests::create_class_generates_simple_class ... ok +test tooling::local_tools::tests::create_class_rejects_existing_file ... ok +test tooling::local_tools::tests::create_class_rejects_invalid_name ... ok +test tooling::local_tools::tests::create_class_with_namespace_and_inherits ... ok +test tooling::local_tools::tests::default_runtime_config_falls_back_to_ipv4_loopback ... ok +test tooling::local_tools::tests::extract_symbols_from_text_covers_major_symbol_kinds ... ok +test tooling::local_tools::tests::find_refs_supports_cursor_paging ... ok +test tooling::local_tools::tests::find_symbol_returns_index_not_ready_before_build ... ok +test tooling::local_tools::tests::get_symbols_extracts_class_and_method ... ok +test tooling::local_tools::tests::helper_comment_and_snippet_processing_works ... ok +test tooling::local_tools::tests::helper_path_normalization_and_resolution_cover_edge_cases ... ok +test tooling::local_tools::tests::helper_symbol_and_scope_predicates_work ... ok +test tooling::local_tools::tests::list_packages_lists_package_dirs ... ok +test tooling::local_tools::tests::lsp_write_tools_require_lsp_mode ... ok +test tooling::local_tools::tests::post_write_refresh_failure_preserves_applied_files_without_runtime_panic ... ok +test tooling::local_tools::tests::read_returns_file_slice ... ok +test tooling::local_tools::tests::requires_unityengine_using_only_for_monobehaviour ... ok +test tooling::local_tools::tests::search_finds_matching_lines ... ok +test tooling::local_tools::tests::update_index_refreshes_symbol_names ... ok +test tooling::os_capture::tests::capture_fails_when_no_candidate_exists ... ok +test tooling::os_capture::tests::detects_daemon_stringified_timeouts ... ok +test tooling::os_capture::tests::disabled_fallback_returns_the_timeout_error ... ok +test tooling::os_capture::tests::failed_os_capture_keeps_both_errors ... ok +test tooling::os_capture::tests::fallback_flag_defaults_on_and_is_stripped ... ok +test tooling::os_capture::tests::non_timeout_errors_are_not_recovered ... ok +test tooling::os_capture::tests::output_path_follows_bridge_capture_directory ... ok +test tooling::os_capture::tests::timeout_is_recovered_with_os_fallback_marker ... ok +test tooling::os_capture::tests::verbatim_prefix_is_dropped_before_the_path_reaches_os_tools ... ok +test tooling::tool_catalog::tests::action_enum_schemas_use_composite_variants ... ok +test tooling::tool_catalog::tests::addressables_analyze_schema_uses_action_specific_variants ... ok +test tooling::tool_catalog::tests::addressables_manage_schema_has_manage_actions ... ok +test tooling::tool_catalog::tests::all_tools_e2e_covers_catalog_or_documents_exclusion ... ok +test tooling::tool_catalog::tests::analyze_asset_dependencies_schema_has_expected_actions ... ok +test tooling::tool_catalog::tests::animation_curve_tools_advertise_strict_unity_contracts ... ok +test tooling::tool_catalog::tests::baking_tools_have_explicit_target_and_polling_contracts ... ok +test tooling::tool_catalog::tests::build_index_schema_allows_output_path ... ok +test tooling::tool_catalog::tests::build_player_schema_requires_explicit_safe_build_inputs ... ok +test tooling::tool_catalog::tests::capture_video_start_schema_restricts_mode_and_format ... ok +test tooling::tool_catalog::tests::clear_logs_schema_is_strict_empty_object ... ok +test tooling::tool_catalog::tests::create_animation_clip_schema_requires_clip_and_sprite_paths ... ok +test tooling::tool_catalog::tests::create_animator_controller_schema_is_strict_and_nested ... ok +test tooling::tool_catalog::tests::create_prefab_schema_allows_template_mode_without_source_object ... ok +test tooling::tool_catalog::tests::create_sprite_atlas_schema_is_strict_and_nested ... ok +test tooling::tool_catalog::tests::csharp_file_write_schemas_are_local_and_strict ... ok +test tooling::tool_catalog::tests::delete_gameobject_schema_uses_any_of_targets ... ok +test tooling::tool_catalog::tests::execute_menu_item_schema_supports_default_and_action_variants ... ok +test tooling::tool_catalog::tests::get_build_status_is_read_only_and_requires_build_id ... ok +test tooling::tool_catalog::tests::get_gameobject_details_schema_uses_any_of_identifiers ... ok +test tooling::tool_catalog::tests::get_index_status_schema_is_strict_empty_object ... ok +test tooling::tool_catalog::tests::hot_reload_tools_expose_explicit_preview_and_recovery_contract ... ok +test tooling::tool_catalog::tests::input_keyboard_schema_uses_any_of_for_action_or_actions ... ok +test tooling::tool_catalog::tests::known_tool_lookup_works ... ok +test tooling::tool_catalog::tests::load_scene_schema_uses_one_of_identifier_variants ... ok +test tooling::tool_catalog::tests::local_executor_tools_are_marked ... ok +test tooling::tool_catalog::tests::manage_asset_database_schema_uses_action_specific_variants ... ok +test tooling::tool_catalog::tests::manage_layers_schema_requires_action_enum ... ok +test tooling::tool_catalog::tests::modify_gameobject_schema_requires_path ... ok +test tooling::tool_catalog::tests::package_manager_schema_has_required_action ... ok +test tooling::tool_catalog::tests::ping_schema_is_strict_object ... ok +test tooling::tool_catalog::tests::prefab_override_tools_have_strict_discoverable_schemas ... ok +test tooling::tool_catalog::tests::quit_editor_exposes_optional_scene_protection_parameter ... ok +test tooling::tool_catalog::tests::remote_tools_have_unity_bridge_dispatch_cases ... ok +test tooling::tool_catalog::tests::rename_symbol_schema_is_strict_and_requires_name_path ... ok +test tooling::tool_catalog::tests::run_tests_schema_allows_test_mode_enum ... ok +test tooling::tool_catalog::tests::set_component_field_schema_requires_component_and_field ... ok +test tooling::tool_catalog::tests::timeline_schema_exposes_actions_and_stale_clip_guard ... ok +test tooling::tool_catalog::tests::timeline_tools_are_discoverable_with_correct_mutation_flags ... ok +test tooling::tool_catalog::tests::tool_catalog_avoids_default_params_schema_for_known_tools ... ok +test tooling::tool_catalog::tests::tool_catalog_keeps_manifest_parity_count ... ok +test tooling::tool_catalog::tests::tool_specs_cover_catalog ... ok +test tooling::tool_catalog::tests::tools_doc_matches_registered_catalog ... ok +test tooling::tool_catalog::tests::vfx_apply_is_mutating_and_requires_op ... ok +test tooling::tool_catalog::tests::vfx_describe_graph_is_read_only_and_requires_asset_path ... ok +test tooling::tool_catalog::tests::vfx_runtime_is_mutating_and_requires_op_and_game_object ... ok +test tooling::tool_catalog::tests::vfx_settings_is_mutating_and_requires_op ... ok +test tooling::tool_index::tests::category_accepts_heading_or_slug ... ok +test tooling::tool_index::tests::every_tool_has_exactly_one_index_entry_with_a_short_summary ... ok +test tooling::tool_index::tests::query_matches_name_or_summary_case_insensitively ... ok +test tooling::tool_index::tests::tool_index_matches_docs_headings ... ok +test tooling::tool_index::tests::unknown_category_lists_valid_slugs ... ok +test unity::auth::tests::credentials_are_endpoint_scoped_and_absent_from_discovery_output ... ok +test unity::auth::tests::explicit_mounted_lockfile_and_invalid_file_errors_do_not_expose_token ... ok +test unity::auth::tests::only_exact_one_enables_legacy_opt_out ... ok +test unity::transport::tests::call_tool_returns_error_on_failure_response ... ok +test unity::transport::tests::call_tool_returns_result_on_success ... ok +test unity::transport::tests::call_tool_with_timing_reports_non_negative_durations ... ok +test unity::transport::tests::every_request_carries_token_from_private_lockfile ... ok +test unity::transport::tests::normalize_failure_preserves_complete_error_envelope ... ok +test unity::transport::tests::normalize_response_handles_success_and_error_shapes ... ok +test unity::transport::tests::parse_embedded_json_keeps_plain_strings ... ok +test unity::transport::tests::parse_json_accepts_trimmed_json ... ok +test unity::transport::tests::parse_json_rejects_empty_and_non_utf8_payload ... ok +test unity::transport::tests::ping_backfills_bridge_version_from_editor_state_envelope ... ok + +test result: ok. 558 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 69.01s + + Running tests\auth_warning.rs (target\debug\deps\auth_warning-c35c20bac6c142a9.exe) + +running 1 test +test legacy_opt_out_warns_on_stderr_only_for_exact_one ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.83s + + Running tests\bridge_package_dependencies.rs (target\debug\deps\bridge_package_dependencies-c22ae8298886d006.exe) + +running 1 test +test bridge_declares_ugui_when_sources_use_it ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s + + Running tests\build_failure_output.rs (target\debug\deps\build_failure_output-1ea8e89b85e8d186.exe) + +running 1 test +test failed_build_status_keeps_json_report_and_nonzero_exit ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.51s + + Running tests\ci_tests.rs (target\debug\deps\ci_tests-0a59ca143bc1adb3.exe) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests\csharp_post_write.rs (target\debug\deps\csharp_post_write-132f286b429372c3.exe) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests\custom_tools.rs (target\debug\deps\custom_tools-f6cf3b643480b090.exe) + +running 10 tests +test batch_validates_all_custom_arguments_before_any_side_effect ... ok +test custom_method_is_not_retried_after_lost_response ... ok +test custom_numeric_ranges_and_nullable_defaults_are_validated_before_execution ... ok +test discovery_merges_schemas_and_sources_and_filters_custom_tools ... ok +test discovery_rejects_conflicting_or_malformed_editor_catalogs ... ok +test dry_run_and_unknown_tools_never_invoke_a_custom_method ... ok +test invalid_custom_arguments_never_reach_the_method ... ok +test names_only_and_compact_preserve_small_list_shapes ... ok +test old_bridges_keep_the_builtin_catalog_but_auth_errors_are_visible ... ok +test schema_and_all_call_spellings_support_custom_names ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.85s + + Running tests\editor_lifecycle.rs (target\debug\deps\editor_lifecycle-84c3f58d5f45f2e9.exe) + +running 4 tests +test close_requires_bridge_scene_protection_before_sending_quit ... ok +test editor_lifecycle_commands_are_available ... ok +test missing_editor_explains_official_install_and_returns_precondition ... ok +test status_reports_compilation_from_the_selected_project ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.72s + + Running tests\install_script.rs (target\debug\deps\install_script-a3d362ab68edd4d9.exe) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests\json_envelope.rs (target\debug\deps\json_envelope-6eaad9084b5bdd8a.exe) + +running 15 tests +test batch_with_failed_operation_does_not_exit_zero ... ok +test bridge_errors_preserve_codes_and_authentication_exit ... ok +test bridge_warnings_reach_the_public_envelope ... ok +test clap_usage_error_has_json_envelope ... ok +test direct_authentication_and_bridge_failures_match_daemon ... ok +test invalid_batch_is_usage_error ... ok +test invalid_json_is_usage_error ... ok +test invalid_port_list_is_usage_error ... ok +test invalid_tool_routes_are_usage_errors ... ok +test local_success_uses_single_envelope ... ok +test nested_bridge_failure_is_not_reported_as_success ... ok +test response_timeout_is_retryable_operation_failure ... ok +test skills_show_and_lint_use_envelopes ... ok +test test_completion_distinguishes_failed_and_passed ... ok +test unreachable_editor_is_exit_seven ... ok + +test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 21.77s + + Running tests\mcp.rs (target\debug\deps\mcp-9035db26334793d1.exe) + +running 3 tests +test configure_all_clients_preserves_other_servers_and_dry_run ... ok +test malformed_requests_do_not_end_session_or_execute_tools_before_initialization ... ok +test stdio_catalog_and_failure_contract_without_editor ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 18.04s + + Running tests\mcp_dynamic.rs (target\debug\deps\mcp_dynamic-5e938b67940e38e9.exe) + +running 1 test +test custom_catalog_calls_and_live_removal_share_cli_discovery_and_validation ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.11s + + Running tests\setup_dry_run.rs (target\debug\deps\setup_dry_run-7097af0dc1444163.exe) + +running 2 tests +test setup_dry_run_prints_plan_without_connections_writes_or_launches ... ok +test setup_launch_returns_output_while_editor_is_still_running ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.14s + + Running tests\skills_install.rs (target\debug\deps\skills_install-7ac81df839f43c4f.exe) + +running 7 tests +test all_clients_install_embedded_references_and_show_works_outside_repository ... ok +test dry_run_prints_only_paths_without_creating_files ... ok +test global_dry_run_flag_also_prevents_installation ... ok +test install_protects_unowned_directory_and_force_keeps_unrelated_files ... ok +test invalid_ledger_paths_are_rejected_even_with_force ... ok +test refresh_does_not_install_clients_without_a_ledger ... ok +test refresh_syncs_an_older_owned_version_and_protects_local_edits ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.75s + + Running tests\tool_list_filters.rs (target\debug\deps\tool_list_filters-6faf0e078f88be27.exe) + +running 7 tests +test category_returns_only_that_docs_section ... ok +test compact_is_name_and_description_only_and_at_most_half_of_full_catalog ... ok +test limit_and_offset_page_the_filtered_list ... ok +test offline_default_list_has_schemas_and_names_only_is_compatible ... ok +test query_returns_only_matching_tools ... ok +test unknown_category_is_rejected ... ok +test unopened_project_still_exposes_the_offline_builtin_catalog ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 15.26s + + Running tests\unityd_autostart.rs (target\debug\deps\unityd_autostart-6dcacab8badb9285.exe) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/docs/verification/issue-386/resume/cargo-test-inventory.json b/docs/verification/issue-386/resume/cargo-test-inventory.json new file mode 100644 index 00000000..bc920d2e --- /dev/null +++ b/docs/verification/issue-386/resume/cargo-test-inventory.json @@ -0,0 +1,3057 @@ +{ + "total": 610, + "passed": 610, + "failed": 0, + "tests": [ + { + "suite": "unittests src\\main.rs", + "name": "app::editor::tests::editor_launch_uses_paths_supported_by_unity", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::ambiguous_editor_fails_before_contacting_any_editor", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::animation_curve_edits_accept_operations_and_tangent_modes", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::animation_curve_edits_reject_missing_identifiers_and_invalid_nested_fields", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::animation_curve_queries_validate_complete_binding_filters", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::audio_mixer_arguments_are_action_specific", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::augment_command_stats_inserts_cli_snapshot", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::baking_invalid_target_missing_scene_and_missing_job_are_rejected", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::baking_surface_requires_path_before_contacting_editor", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::baking_valid_targets_and_polling_are_accepted", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::bridge_commands_resolve_explicit_project_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_clean_defaults", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_clean_with_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_diff_path_mode_with_limit", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_diff_symbol_mode", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_embed_build_includes_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_embed_build_omits_optional_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_embed_search_omits_optional_top_k", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_embed_search_with_top_k", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_fetch_carries_all_flags", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_fetch_defaults_without_overrides", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_find_symbol_minimal", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_find_symbol_with_filters", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_grep_defaults_context_to_zero", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_grep_with_file_glob_and_context", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_resolve_symbol_at_minimal", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_resolve_symbol_at_with_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_search_minimal_pattern", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_search_with_all_options", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_status_includes_explicit_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_status_omits_optional_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_view_omits_optional_lines", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::build_reference_call_view_with_range", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::capture_screenshot_timeout_respects_os_fallback_flag", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::env_var_guard_restores_previous_value", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::eval_cli_accepts_code_and_rejects_invalid_mode", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::eval_dry_run_does_not_execute_arbitrary_code", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::eval_schemas_require_code_and_status_id", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::eval_transport_error_keeps_generated_request_id", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::execute_tool_skips_mutating_tool_in_dry_run_mode", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::hot_reload_requires_revision_and_explicit_action", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::init_tracing_accepts_verbose_levels", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::instances_list_defaults_host_to_ipv4_loopback", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::load_params_defaults_to_empty_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::load_params_reads_inline_json", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::load_params_reads_json_from_file", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::load_params_rejects_when_json_and_params_file_are_both_set", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_external_tool_command_accepts_json_flag", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_external_tool_command_rejects_unknown_flag", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_external_tool_command_requires_tool_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_external_tool_command_requires_values_for_flags", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_external_tool_command_supports_equals_forms", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_json_object_accepts_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_json_object_rejects_non_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_ports_deduplicates_values", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_ports_rejects_invalid_values", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_ports_returns_empty_for_none", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::parse_ports_with_diagnostics_reports_duplicate_values", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::ping_version_check_reports_mismatch_and_unknown", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::prefab_override_validation_requires_explicit_scope_and_apply_target", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::print_value_text_handles_string_and_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::project_path_flag_is_global_and_feeds_runtime_overrides", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::run_with_cli_batch_marks_skipped_items_in_dry_run_mode", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::run_with_cli_exercises_remote_command_error_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::run_with_cli_handles_instances_and_daemon_commands_without_server", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::run_with_cli_handles_local_tool_and_batch_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::run_with_cli_rejects_unknown_external_tool", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::run_with_cli_requires_batch_input_source", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::run_with_cli_set_active_text_output_when_reachable", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::run_with_cli_supports_tool_schema_command", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::runtime_overrides_are_derived_from_cli_at_app_boundary", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::setup_and_bridge_cli_arguments_parse", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::timeline_manage_is_skipped_in_dry_run", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::timeline_validation_requires_target_and_valid_action", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_add_component_payload", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_addressables_manage_add_entry", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_analyze_asset_dependencies_get_dependencies", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_build_index_output_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_create_animation_clip_payload", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_create_animator_controller_payload", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_create_gameobject_with_vector_fields", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_create_sprite_atlas_payload", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_delete_gameobject_with_path_and_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_execute_menu_item_get_available_menus", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_execute_menu_item_without_action", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_get_input_actions_state_with_asset_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_input_keyboard_batch_actions", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_load_scene_by_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_lsp_write_payload_with_path_alias", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_manage_layers_get_by_index", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_package_manager_list_action", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_profiler_start_payload", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_valid_payload", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_accepts_write_csharp_file_payload", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_addressables_analyze_dependencies_without_asset_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_addressables_manage_move_entry_without_target_group", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_analyze_asset_dependencies_get_dependencies_without_asset_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_analyze_asset_dependencies_invalid_action", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_analyze_screenshot_without_source", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_create_animation_clip_without_sprite_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_create_package_setting_without_value", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_delete_gameobject_without_target", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_execute_menu_item_without_action_or_menu_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_execute_menu_item_without_menu_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_invalid_animator_condition_mode", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_invalid_sprite_atlas_filter_mode", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_load_scene_with_both_identifiers", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_manage_asset_database_move_without_to_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_manage_layers_add_without_layer_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_manage_layers_invalid_action", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_manage_selection_set_without_object_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_manage_tools_activate_without_tool_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_manage_windows_focus_without_window_type", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_missing_required_property", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_package_manager_search_without_keyword", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_registry_config_add_scope_without_scope", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_remove_input_binding_without_selector", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_set_component_field_missing_required", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_unknown_field_for_clear_logs", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_unknown_property_when_schema_is_strict", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::runner::tests::validate_tool_params_rejects_unknown_run_tests_property", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::setup::tests::hub_paths_for_windows_and_linux_do_not_depend_on_test_host", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::setup::tests::launch_editor_skips_when_project_is_locked_and_errors_without_editor", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::setup::tests::project_unity_version_and_hub_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::setup::tests::setup_dry_run_leaves_editor_unchecked_and_skips_writes", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::setup::tests::setup_flags_editor_serving_another_project", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::setup::tests::setup_installs_bridge_and_confirms_matching_editor", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::setup::tests::setup_reports_version_mismatch_as_json", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::setup::tests::setup_without_dry_run_reports_unreachable_editor", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::test_report::tests::github_annotations_extract_unity_location_and_escape_injection", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::test_report::tests::junit_preserves_failed_skipped_and_escaped_details", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::test_report::tests::junit_time_is_millisecond_precision_for_xunit_schema", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::test_report::tests::nunit_nests_test_cases_in_a_suite_and_preserves_details", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::test_report::tests::parent_suite_rollups_do_not_duplicate_leaf_failures", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "app::test_report::tests::suite_failure_is_reported_even_without_failed_leaves", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "cli::test_command_tests::test_command_accepts_report_output_without_changing_global_output", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::dry_run_reports_change_without_writing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::embedded_package_is_reported_and_not_duplicated", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::input_backends_untouched_when_setting_absent_or_already_enabled", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::install_adds_openupm_registry_and_cli_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::install_adds_scope_to_existing_openupm_registry", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::install_enables_input_system_backends_while_editor_is_closed", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::install_is_noop_when_already_configured_by_hand", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::install_keeps_other_version_and_upgrade_pins_cli_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::install_leaves_input_backends_when_editor_is_open_or_dry_run", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::install_twice_leaves_manifest_byte_identical", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::rejects_malformed_manifest", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::resolve_project_root_walks_up_and_validates_explicit_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::status_prefers_lock_resolution_and_reports_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::upgrade_leaves_custom_sources_alone", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::bridge::tests::version_check_classifies_versions", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::command_stats::tests::snapshot_groups_calls_by_tool_and_route", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::default_host_returns_ipv4_loopback_without_env", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::default_port_returns_6400_without_env", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::default_timeout_returns_30000_without_env", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::empty_value_is_ignored", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::execution_context_uses_defaults", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::fails_when_legacy_alias_is_set", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::fails_when_removed_unityd_env_is_set", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::returns_none_when_no_keys_set", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::u16_env_parses_correctly", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::u16_env_rejects_zero", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::u64_env_parses_correctly", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::config::tests::u64_env_rejects_zero", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::classification_priority", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::editor_import_workers_are_not_reusable_editors", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::parses_safe_mode_and_latest_compile_errors", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::reads_bridge_version_from_local_file_dependency", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::reads_project_bridge_port", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::recognizes_editor_command_lines_only", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::reports_editor_not_running", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::reports_port_in_use_with_owner_pid", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::doctor::tests::safe_mode_exit_clears_flag", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::editor_discovery::tests::ambiguous_error_json_lists_candidates", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::editor_discovery::tests::dead_pid_marks_lockfile_stale", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::editor_discovery::tests::discover_reads_lockfiles_and_skips_garbage", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::editor_discovery::tests::expired_heartbeat_marks_lockfile_stale", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::editor_discovery::tests::pid_zero_is_never_alive", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::editor_discovery::tests::select_for_path_ignores_stale_editors_and_sibling_prefixes", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::editor_discovery::tests::select_for_path_prefers_deepest_live_project", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::active_instance_keeps_priority_over_lockfile_discovery", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::cli_override_wins_over_active_instance", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::cwd_inside_project_selects_that_editor", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::cwd_outside_projects_with_two_editors_is_ambiguous", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::env_port_wins_when_no_cli_override", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::explicit_port_wins_over_project_path_and_lockfiles", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::no_lockfiles_keeps_legacy_default", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::project_command_targets_its_own_editor_among_several", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::project_command_without_its_editor_uses_default_endpoint", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::project_path_selects_matching_editor", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::project_path_without_running_editor_is_not_found", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::project_root_env_falls_back_to_default_without_any_lockfile", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::single_running_editor_is_used_from_anywhere", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::stale_editors_do_not_cause_ambiguity", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::endpoint::tests::unity_project_root_env_acts_as_project_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::failure::tests::failed_batch_preserves_first_failure_message_and_all_results", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::authenticated_health_checks_support_listing_and_selection", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::list_instances_adds_default_port_when_no_entries_exist", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::list_instances_enumerates_lockfiles_without_ports", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::list_instances_keeps_explicit_ports_next_to_lockfiles", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::list_instances_reports_down_for_tcp_listener_that_is_not_unity_bridge", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::list_instances_reports_up_for_reachable_port", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::load_registry_reconstructs_missing_ids", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::parse_id_validates_shape", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::registry_path_uses_env_and_creates_parent_directory", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::registry_round_trip_serialization_shape_is_supported", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::set_active_fails_for_unreachable_instance", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::instances::tests::set_active_succeeds_for_reachable_instance_and_tracks_previous", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::cache_root_falls_back_to_home_unity_cache", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::cache_root_prefers_unity_cli_cache_root_env", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::detect_rid_returns_known_target_triple", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::download_latest_binary_applies_matching_checksum", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::download_latest_binary_rejects_checksum_mismatch_and_keeps_existing_install", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::ensure_latest_for_can_skip_remote_checks_in_tests", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::ensure_local_uses_existing_binary_without_download", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::get_json_fails_with_status_and_body", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::get_json_parses_http_body", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::get_json_retries_transient_server_error", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::get_optional_text_returns_body_for_success", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::get_optional_text_returns_none_for_not_found", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::get_response_includes_authorization_header", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::get_response_reports_http_status_errors", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::parse_sha256sums_reads_text_and_binary_mode_entries", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::read_local_version_returns_none_for_missing_or_blank_file", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::replace_file_atomic_overwrites_destination", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::sha256_file_matches_known_hash", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::tools_root_falls_back_to_home_unity_tools_when_env_unset", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::tools_root_prefers_unity_cli_tools_root_env", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::unity_cli_status_uses_managed_install_layout", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::verify_manifest_against_checksums_requires_matching_entry", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::managed_binaries::tests::write_and_read_local_version_round_trip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::runtime_paths::tests::daemon_dir_is_under_run_root", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::self_update::tests::is_recent_returns_false_for_missing_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::self_update::tests::is_recent_returns_true_for_freshly_touched_file", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::self_update::tests::last_check_path_uses_unity_cli_tools_root_env", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::self_update::tests::maybe_self_update_skipped_when_opt_out_env_set", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::self_update::tests::maybe_self_update_skips_when_recent_check_exists", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::self_update::tests::touch_creates_parent_and_writes_marker", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "core::self_update::tests::warn_cargo_conflict_runs_without_panic", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::runtime::tests::runtime_module_builds_without_warnings_when_unix_code_is_disabled", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::spawn::tests::spawn_detached_starts_the_command", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::spawn::tests::spawn_module_builds_for_windows_without_warnings", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::spawn::tests::spawned_child_does_not_hold_the_callers_stdout_pipe", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_call_error_classification", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_request_batch_round_trip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_request_ping_round_trip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_request_status_round_trip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_request_stop_round_trip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_request_tool_round_trip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_response_error_round_trip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_response_round_trip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::daemon_response_round_trip_preserves_timing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::idle_timeout_default", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::pid_file_path_is_under_tools_dir", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::pooled_connection_closed_by_editor_restart_is_reconnected_before_sending", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::pooled_connection_uses_each_requests_timeout", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::request_lost_after_sending_is_reported_and_not_resent", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::startup_lock_times_out_and_is_reusable_after_release", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "daemon::unityd::tests::tools_dir_creates_directory", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::collect_document_symbols_flattens_nested_symbols", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::get_apply_defaults_to_false", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::id_matches_accepts_number_and_string_id", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::kind_from_lsp_maps_known_values", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::normalize_lsp_write_result_adds_contract_fields", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::normalize_rel_path_accepts_assets_packages_and_library", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::normalize_rel_path_extracts_supported_prefix_from_absolute_like_input", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::normalize_rel_path_rejects_parent_traversal", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::path_matches_scope_filters_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::remove_symbol_request_includes_fail_on_references_when_set", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::remove_symbol_request_omits_fail_on_references_when_unset", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::require_helpers_validate_expected_fields", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::retryable_session_error_detects_transport_failures", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::retryable_session_error_ignores_argument_errors", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::to_project_relative_or_raw_returns_relative_for_absolute_under_root", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::uri_and_ref_path_helpers_resolve_project_relative_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::client::tests::uri_to_rel_path_rejects_non_file_uris", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::daemon::tests::daemon_idle_timeout_uses_env_override", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::daemon::tests::handle_request_handles_ping_status_and_stop", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::daemon::tests::is_would_block_checks_error_kind", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::daemon::tests::write_all_with_retry_handles_would_block_and_partial_writes", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::daemon::tests::write_all_with_retry_rejects_zero_byte_progress", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "lsp::daemon::tests::write_pid_file_and_cleanup_manage_files_under_tools_root", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "mcp::configure::tests::custom_root_may_have_missing_ancestors_without_creating_them", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "mcp::configure::tests::invalid_config_is_never_overwritten_and_preview_creates_nothing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "mcp::configure::tests::malformed_shapes_and_http_name_collisions_are_rejected", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "mcp::configure::tests::merges_inline_toml_without_losing_other_servers_or_options", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "mcp::configure::tests::windows_and_local_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "mcp::tests::projects_owned_custom_descriptor_without_an_mcp_specific_schema", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::gc_empty_root_returns_empty", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::gc_keep_zero_removes_all_versions", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::gc_keeps_n_newest_and_returns_removed", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::gc_skips_non_directory_entries", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::list_versions_empty_when_root_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::list_versions_returns_existing_dirs", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::list_versions_skips_files_in_root", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::meta_roundtrip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::read_meta_returns_error_for_invalid_json", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::read_meta_returns_error_when_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::version_dir_rejects_empty", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::version_dir_rejects_paths_outside_single_cache_entry", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::cache::tests::version_dir_under_cache_root", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_line_diff_empty_for_identical_lines", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_line_diff_for_deletes_only_returns_removal_hunk", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_line_diff_for_inserts_only_returns_addition_hunk", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_line_diff_for_separate_changes_produces_multiple_hunks", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_line_diff_replacement_isolates_changed_lines", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_path_diff_can_be_truncated", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_path_diff_categorises_runtime_export", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_symbol_diff_detects_changed_animator", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_symbol_diff_returns_diff_when_only_one_side_has_symbol", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::compute_symbol_diff_returns_none_for_missing_in_both", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::ensure_cache_dir_errors_on_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::diff::tests::split_fqn_separates_namespace_and_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::build_embedding_index_handles_empty_symbol_index", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::build_embedding_index_with_mock_embedder", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::cosine_similarity_handles_zero_vectors", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::embedding_roundtrip_via_bincode", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::resolve_onnxruntime_dylib_explains_how_to_install_when_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::resolve_onnxruntime_dylib_falls_back_to_first_existing_candidate", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::resolve_onnxruntime_dylib_prefers_existing_env_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::resolve_onnxruntime_dylib_rejects_missing_env_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::search_ranks_by_cosine_similarity", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::search_returns_empty_for_empty_index", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::search_returns_empty_for_empty_query", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::symbol_to_text_includes_namespace_and_kind", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::embed::tests::symbol_to_text_without_namespace_omits_dot", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::api_discovery_paginates_branches_and_includes_tags", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::api_discovery_surfaces_http_errors", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::archive_url_uses_unity_cs_reference_org", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::build_clone_args_emits_shallow_single_branch", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::ensure_git_available_succeeds_in_test_env", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::extract_zip_to_rejects_entries_with_parent_segments", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::extract_zip_to_strips_top_level_prefix_and_writes_files", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::fetch_selected_checks_out_long_windows_paths_without_global_configuration", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::fetch_selected_pins_commit_after_branch_advances", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::fetch_selected_rejects_invalid_commit_before_creating_destination", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::github_token_returns_none_when_env_unset", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::github_token_skips_empty_and_picks_first_non_empty", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::license_ok_when_env_set", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::license_ok_when_flag_true", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::license_rejects_zero_value", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::license_required_when_flag_false_and_env_unset", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::list_public_refs_discovers_branches_and_tags", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::list_public_refs_preserves_transport_error", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::public_refs_use_basic_authentication_for_git_http", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::fetcher::tests::run_clone_rejects_when_license_not_accepted", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::build_or_update_index_handles_existing_fixture", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::build_or_update_index_persists_signature", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::build_or_update_index_skips_already_indexed_files_until_change", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::extract_symbols_from_text_captures_namespace", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::extract_symbols_from_text_does_not_double_capture_class_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::extract_symbols_from_text_finds_class", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::extract_symbols_from_text_finds_methods", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::extract_symbols_from_text_finds_property", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::extract_symbols_from_text_finds_struct_and_interface", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::file_signature_changes_when_content_changes", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::find_symbol_filters_by_kind_and_namespace", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::index::tests::validate_kind_accepts_known_and_rejects_unknown", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::search::tests::grep_filters_by_filename_glob", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::search::tests::grep_finds_class_animator_with_line_numbers", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::search::tests::grep_returns_context_lines", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::search::tests::view_rejects_parent_traversal", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::search::tests::view_returns_requested_line_range", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::cached_fetch_and_status_report_stored_provenance", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::cached_unknown_version_can_be_used_without_branch_resolution", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::dir_size_empty_returns_zero", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::dir_size_sums_file_lengths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_clean_dry_run_false_actually_removes", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_clean_dry_run_on_empty_cache_returns_empty_removed", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_diff_errors_when_cache_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_diff_path_mode_returns_added_removed_changed", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_diff_requires_from_and_to", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_diff_requires_symbol_or_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_diff_symbol_mode_returns_diffs", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_embed_build_errors_when_cache_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_embed_search_errors_when_index_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_embed_search_requires_query", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_fetch_force_preserves_existing_on_transport_failure", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_fetch_skips_when_destination_exists_without_force", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_find_symbol_empty_hits_for_unknown_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_find_symbol_filters_namespace", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_find_symbol_rejects_unknown_kind", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_find_symbol_requires_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_find_symbol_returns_error_when_cache_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_find_symbol_returns_hits_from_fixture", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_grep_invalid_regex_returns_error", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_grep_requires_pattern", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_grep_supports_file_glob_filter", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_grep_via_dispatcher_returns_hits", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_resolve_symbol_at_empty_token_for_blank_position", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_resolve_symbol_at_finds_token_via_fixture", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_resolve_symbol_at_requires_path_line_column", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_resolve_symbol_at_requires_project_prefix", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_search_requires_pattern", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_search_via_dispatcher_truncates_max_results", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_search_without_max_results_returns_all_hits", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_status_includes_size_bytes", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_status_returns_versions_list", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_view_rejects_parent_traversal_via_dispatcher", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_view_requires_path_param", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::execute_view_via_dispatcher_returns_lines", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::extract_token_at_cursor_handles_edge_cases", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::extract_token_at_cursor_handles_escaped_quote_in_string", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::extract_token_at_cursor_returns_ident_after_closed_string", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::extract_token_at_cursor_skips_line_comment", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::extract_token_at_cursor_skips_string_literal", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::fetch_resolves_project_and_explicit_refs_and_records_actual_commit", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::legacy_metadata_keeps_unknown_match_instead_of_claiming_exact", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::maybe_execute_returns_none_for_unknown_tool", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::now_unix_seconds_string_is_decimal", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::resolve_version_falls_back_to_project_detection", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::tests::resolve_version_uses_explicit_param", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::ambiguous_auto_candidates_and_unknown_versions_return_candidates", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::detect_returns_error_when_editor_version_line_absent", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::detect_returns_error_when_editor_version_value_empty", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::detect_returns_error_when_project_version_missing", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::exact_tag_precedes_minor_but_version_named_head_is_not_exact", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::explicit_ref_has_priority_and_ambiguous_short_names_require_full_ref", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::minor_version_key_rejects_invalid_inputs", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::parse_editor_version_returns_value_directly", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::parses_remote_refs_with_peeled_tag_commits_in_any_order", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::public_resolver_handles_previously_supported_minors", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::reads_known_project_version", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::reads_unknown_minor_without_static_mapping", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "reference::version::tests::selects_new_and_existing_minor_branches_without_claiming_exact_match", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::loader::tests::load_skills_handles_missing_root_and_skips_non_skill_entries", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::loader::tests::load_skills_supports_single_skill_root_and_dir_name_fallback", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::loader::tests::parse_frontmatter_and_collect_references_cover_optional_branches", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::loader::tests::parse_frontmatter_extracts_metadata", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::loader::tests::split_frontmatter_and_parse_frontmatter_cover_edge_cases", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::loader::tests::split_frontmatter_handles_basic_skill", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::good_skill_passes_all_rules", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::model_helpers_cover_skill_accessors_and_tool_sets", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r01_missing_description_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r01_missing_multiple_required_fields_fire", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r02_name_mismatch_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r03_disallowed_tool_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r03_legacy_bare_bash_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r04_unknown_category_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r05_empty_and_duplicate_triggers_fire", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r05_uppercase_trigger_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r06_unknown_sibling_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r07_too_long_description_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r08_missing_front_trigger_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r09_first_person_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r10_missing_use_when_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r11_missing_sibling_mention_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r12_unidirectional_sibling_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r13_too_long_body_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r14_missing_heading_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r15_references_without_link_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r16_time_sensitive_phrase_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r17_missing_runtime_checklist_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r18_long_reference_without_toc_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r19_reference_link_to_reference_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r20_and_r21_validate_windows_git_symlink_placeholders", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::r22_collision_without_cross_listing_fires", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "skills::tests::report_and_runner_cover_text_json_discovery_and_error_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "test_env::isolated_runtime_restores_inherited_environment_after_unwind", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::discovery::tests::bridge_reserved_names_match_the_cli_catalog_including_local_tools", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::discovery::tests::builtin_descriptors_keep_schemas_and_mark_their_source", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::discovery::tests::custom_descriptor_roundtrips_owned_names_and_schema", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::discovery::tests::list_tools_is_a_read_only_remote_builtin", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::build_index_and_find_symbol_roundtrip", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::collect_cs_files_and_index_helpers_cover_readiness_branches", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::create_class_generates_simple_class", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::create_class_rejects_existing_file", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::create_class_rejects_invalid_name", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::create_class_with_namespace_and_inherits", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::default_runtime_config_falls_back_to_ipv4_loopback", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::extract_symbols_from_text_covers_major_symbol_kinds", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::find_refs_supports_cursor_paging", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::find_symbol_returns_index_not_ready_before_build", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::get_symbols_extracts_class_and_method", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::helper_comment_and_snippet_processing_works", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::helper_path_normalization_and_resolution_cover_edge_cases", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::helper_symbol_and_scope_predicates_work", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::list_packages_lists_package_dirs", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::lsp_write_tools_require_lsp_mode", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::post_write_refresh_failure_preserves_applied_files_without_runtime_panic", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::read_returns_file_slice", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::requires_unityengine_using_only_for_monobehaviour", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::search_finds_matching_lines", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::local_tools::tests::update_index_refreshes_symbol_names", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::capture_fails_when_no_candidate_exists", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::detects_daemon_stringified_timeouts", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::disabled_fallback_returns_the_timeout_error", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::failed_os_capture_keeps_both_errors", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::fallback_flag_defaults_on_and_is_stripped", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::non_timeout_errors_are_not_recovered", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::output_path_follows_bridge_capture_directory", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::timeout_is_recovered_with_os_fallback_marker", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::os_capture::tests::verbatim_prefix_is_dropped_before_the_path_reaches_os_tools", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::action_enum_schemas_use_composite_variants", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::addressables_analyze_schema_uses_action_specific_variants", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::addressables_manage_schema_has_manage_actions", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::all_tools_e2e_covers_catalog_or_documents_exclusion", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::analyze_asset_dependencies_schema_has_expected_actions", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::animation_curve_tools_advertise_strict_unity_contracts", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::baking_tools_have_explicit_target_and_polling_contracts", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::build_index_schema_allows_output_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::build_player_schema_requires_explicit_safe_build_inputs", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::capture_video_start_schema_restricts_mode_and_format", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::clear_logs_schema_is_strict_empty_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::create_animation_clip_schema_requires_clip_and_sprite_paths", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::create_animator_controller_schema_is_strict_and_nested", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::create_prefab_schema_allows_template_mode_without_source_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::create_sprite_atlas_schema_is_strict_and_nested", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::csharp_file_write_schemas_are_local_and_strict", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::delete_gameobject_schema_uses_any_of_targets", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::execute_menu_item_schema_supports_default_and_action_variants", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::get_build_status_is_read_only_and_requires_build_id", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::get_gameobject_details_schema_uses_any_of_identifiers", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::get_index_status_schema_is_strict_empty_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::hot_reload_tools_expose_explicit_preview_and_recovery_contract", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::input_keyboard_schema_uses_any_of_for_action_or_actions", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::known_tool_lookup_works", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::load_scene_schema_uses_one_of_identifier_variants", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::local_executor_tools_are_marked", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::manage_asset_database_schema_uses_action_specific_variants", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::manage_layers_schema_requires_action_enum", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::modify_gameobject_schema_requires_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::package_manager_schema_has_required_action", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::ping_schema_is_strict_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::prefab_override_tools_have_strict_discoverable_schemas", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::quit_editor_exposes_optional_scene_protection_parameter", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::remote_tools_have_unity_bridge_dispatch_cases", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::rename_symbol_schema_is_strict_and_requires_name_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::run_tests_schema_allows_test_mode_enum", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::set_component_field_schema_requires_component_and_field", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::timeline_schema_exposes_actions_and_stale_clip_guard", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::timeline_tools_are_discoverable_with_correct_mutation_flags", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::tool_catalog_avoids_default_params_schema_for_known_tools", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::tool_catalog_keeps_manifest_parity_count", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::tool_specs_cover_catalog", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::tools_doc_matches_registered_catalog", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::vfx_apply_is_mutating_and_requires_op", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::vfx_describe_graph_is_read_only_and_requires_asset_path", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::vfx_runtime_is_mutating_and_requires_op_and_game_object", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_catalog::tests::vfx_settings_is_mutating_and_requires_op", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_index::tests::category_accepts_heading_or_slug", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_index::tests::every_tool_has_exactly_one_index_entry_with_a_short_summary", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_index::tests::query_matches_name_or_summary_case_insensitively", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_index::tests::tool_index_matches_docs_headings", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "tooling::tool_index::tests::unknown_category_lists_valid_slugs", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::auth::tests::credentials_are_endpoint_scoped_and_absent_from_discovery_output", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::auth::tests::explicit_mounted_lockfile_and_invalid_file_errors_do_not_expose_token", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::auth::tests::only_exact_one_enables_legacy_opt_out", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::call_tool_returns_error_on_failure_response", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::call_tool_returns_result_on_success", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::call_tool_with_timing_reports_non_negative_durations", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::every_request_carries_token_from_private_lockfile", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::normalize_failure_preserves_complete_error_envelope", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::normalize_response_handles_success_and_error_shapes", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::parse_embedded_json_keeps_plain_strings", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::parse_json_accepts_trimmed_json", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::parse_json_rejects_empty_and_non_utf8_payload", + "result": "ok" + }, + { + "suite": "unittests src\\main.rs", + "name": "unity::transport::tests::ping_backfills_bridge_version_from_editor_state_envelope", + "result": "ok" + }, + { + "suite": "tests\\auth_warning.rs", + "name": "legacy_opt_out_warns_on_stderr_only_for_exact_one", + "result": "ok" + }, + { + "suite": "tests\\bridge_package_dependencies.rs", + "name": "bridge_declares_ugui_when_sources_use_it", + "result": "ok" + }, + { + "suite": "tests\\build_failure_output.rs", + "name": "failed_build_status_keeps_json_report_and_nonzero_exit", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "batch_validates_all_custom_arguments_before_any_side_effect", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "custom_method_is_not_retried_after_lost_response", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "custom_numeric_ranges_and_nullable_defaults_are_validated_before_execution", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "discovery_merges_schemas_and_sources_and_filters_custom_tools", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "discovery_rejects_conflicting_or_malformed_editor_catalogs", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "dry_run_and_unknown_tools_never_invoke_a_custom_method", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "invalid_custom_arguments_never_reach_the_method", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "names_only_and_compact_preserve_small_list_shapes", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "old_bridges_keep_the_builtin_catalog_but_auth_errors_are_visible", + "result": "ok" + }, + { + "suite": "tests\\custom_tools.rs", + "name": "schema_and_all_call_spellings_support_custom_names", + "result": "ok" + }, + { + "suite": "tests\\editor_lifecycle.rs", + "name": "close_requires_bridge_scene_protection_before_sending_quit", + "result": "ok" + }, + { + "suite": "tests\\editor_lifecycle.rs", + "name": "editor_lifecycle_commands_are_available", + "result": "ok" + }, + { + "suite": "tests\\editor_lifecycle.rs", + "name": "missing_editor_explains_official_install_and_returns_precondition", + "result": "ok" + }, + { + "suite": "tests\\editor_lifecycle.rs", + "name": "status_reports_compilation_from_the_selected_project", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "batch_with_failed_operation_does_not_exit_zero", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "bridge_errors_preserve_codes_and_authentication_exit", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "bridge_warnings_reach_the_public_envelope", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "clap_usage_error_has_json_envelope", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "direct_authentication_and_bridge_failures_match_daemon", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "invalid_batch_is_usage_error", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "invalid_json_is_usage_error", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "invalid_port_list_is_usage_error", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "invalid_tool_routes_are_usage_errors", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "local_success_uses_single_envelope", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "nested_bridge_failure_is_not_reported_as_success", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "response_timeout_is_retryable_operation_failure", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "skills_show_and_lint_use_envelopes", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "test_completion_distinguishes_failed_and_passed", + "result": "ok" + }, + { + "suite": "tests\\json_envelope.rs", + "name": "unreachable_editor_is_exit_seven", + "result": "ok" + }, + { + "suite": "tests\\mcp.rs", + "name": "configure_all_clients_preserves_other_servers_and_dry_run", + "result": "ok" + }, + { + "suite": "tests\\mcp.rs", + "name": "malformed_requests_do_not_end_session_or_execute_tools_before_initialization", + "result": "ok" + }, + { + "suite": "tests\\mcp.rs", + "name": "stdio_catalog_and_failure_contract_without_editor", + "result": "ok" + }, + { + "suite": "tests\\mcp_dynamic.rs", + "name": "custom_catalog_calls_and_live_removal_share_cli_discovery_and_validation", + "result": "ok" + }, + { + "suite": "tests\\setup_dry_run.rs", + "name": "setup_dry_run_prints_plan_without_connections_writes_or_launches", + "result": "ok" + }, + { + "suite": "tests\\setup_dry_run.rs", + "name": "setup_launch_returns_output_while_editor_is_still_running", + "result": "ok" + }, + { + "suite": "tests\\skills_install.rs", + "name": "all_clients_install_embedded_references_and_show_works_outside_repository", + "result": "ok" + }, + { + "suite": "tests\\skills_install.rs", + "name": "dry_run_prints_only_paths_without_creating_files", + "result": "ok" + }, + { + "suite": "tests\\skills_install.rs", + "name": "global_dry_run_flag_also_prevents_installation", + "result": "ok" + }, + { + "suite": "tests\\skills_install.rs", + "name": "install_protects_unowned_directory_and_force_keeps_unrelated_files", + "result": "ok" + }, + { + "suite": "tests\\skills_install.rs", + "name": "invalid_ledger_paths_are_rejected_even_with_force", + "result": "ok" + }, + { + "suite": "tests\\skills_install.rs", + "name": "refresh_does_not_install_clients_without_a_ledger", + "result": "ok" + }, + { + "suite": "tests\\skills_install.rs", + "name": "refresh_syncs_an_older_owned_version_and_protects_local_edits", + "result": "ok" + }, + { + "suite": "tests\\tool_list_filters.rs", + "name": "category_returns_only_that_docs_section", + "result": "ok" + }, + { + "suite": "tests\\tool_list_filters.rs", + "name": "compact_is_name_and_description_only_and_at_most_half_of_full_catalog", + "result": "ok" + }, + { + "suite": "tests\\tool_list_filters.rs", + "name": "limit_and_offset_page_the_filtered_list", + "result": "ok" + }, + { + "suite": "tests\\tool_list_filters.rs", + "name": "offline_default_list_has_schemas_and_names_only_is_compatible", + "result": "ok" + }, + { + "suite": "tests\\tool_list_filters.rs", + "name": "query_returns_only_matching_tools", + "result": "ok" + }, + { + "suite": "tests\\tool_list_filters.rs", + "name": "unknown_category_is_rejected", + "result": "ok" + }, + { + "suite": "tests\\tool_list_filters.rs", + "name": "unopened_project_still_exposes_the_offline_builtin_catalog", + "result": "ok" + } + ] +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/clippy-all-features-final.txt b/docs/verification/issue-386/resume/clippy-all-features-final.txt new file mode 100644 index 00000000..cecc522b --- /dev/null +++ b/docs/verification/issue-386/resume/clippy-all-features-final.txt @@ -0,0 +1 @@ + Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.77s diff --git a/docs/verification/issue-386/resume/clippy.txt b/docs/verification/issue-386/resume/clippy.txt new file mode 100644 index 00000000..40132944 --- /dev/null +++ b/docs/verification/issue-386/resume/clippy.txt @@ -0,0 +1,2 @@ + Checking unity-cli v0.18.1 () + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.80s diff --git a/docs/verification/issue-386/resume/comparison-unit-linux.txt b/docs/verification/issue-386/resume/comparison-unit-linux.txt new file mode 100644 index 00000000..ccfad5af --- /dev/null +++ b/docs/verification/issue-386/resume/comparison-unit-linux.txt @@ -0,0 +1,20 @@ +test_benchmark_does_not_reuse_another_projects_daemon_or_host (test_compare_official.CompareTests.test_benchmark_does_not_reuse_another_projects_daemon_or_host) ... ok +test_coexistence_rejects_a_different_editor_version (test_compare_official.CompareTests.test_coexistence_rejects_a_different_editor_version) ... ok +test_coexistence_rejects_a_different_project (test_compare_official.CompareTests.test_coexistence_rejects_a_different_project) ... ok +test_empty_read_and_unapplied_material_are_not_success (test_compare_official.CompareTests.test_empty_read_and_unapplied_material_are_not_success) ... ok +test_eval_must_report_completed (test_compare_official.CompareTests.test_eval_must_report_completed) ... ok +test_failed_create_is_not_a_measurement (test_compare_official.CompareTests.test_failed_create_is_not_a_measurement) ... ok +test_official_nested_failure_is_rejected (test_compare_official.CompareTests.test_official_nested_failure_is_rejected) ... ok +test_process_checks_accept_the_shared_cli_envelope (test_compare_official.CompareTests.test_process_checks_accept_the_shared_cli_envelope) ... ok +test_read_uses_same_asset_within_official_authoring_root (test_compare_official.CompareTests.test_read_uses_same_asset_within_official_authoring_root) ... ok +test_resident_operations_match_all_23_staff_operations (test_compare_official.CompareTests.test_resident_operations_match_all_23_staff_operations) ... ok +test_shell_rejects_in_band_failure (test_compare_official.CompareTests.test_shell_rejects_in_band_failure) ... ok +test_shell_rejects_mismatched_id (test_compare_official.CompareTests.test_shell_rejects_mismatched_id) ... ok +test_shell_reuses_process_and_correlates_responses (test_compare_official.CompareTests.test_shell_reuses_process_and_correlates_responses) ... ok +test_shell_timeout_is_bounded (test_compare_official.CompareTests.test_shell_timeout_is_bounded) ... ok +test_transition_waits_for_completed_state (test_compare_official.CompareTests.test_transition_waits_for_completed_state) ... ok + +---------------------------------------------------------------------- +Ran 15 tests in 0.948s + +OK diff --git a/docs/verification/issue-386/resume/derived-lib-error.txt b/docs/verification/issue-386/resume/derived-lib-error.txt new file mode 100644 index 00000000..7a9388c1 --- /dev/null +++ b/docs/verification/issue-386/resume/derived-lib-error.txt @@ -0,0 +1 @@ +error: no library targets found in package `unity-cli` diff --git a/docs/verification/issue-386/resume/domain-reload.json b/docs/verification/issue-386/resume/domain-reload.json new file mode 100644 index 00000000..21d54f7e --- /dev/null +++ b/docs/verification/issue-386/resume/domain-reload.json @@ -0,0 +1,347 @@ +{ + "cases": [ + { + "domainReloadEnabled": true, + "settings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "None", + "enterPlayModeOptionsEnabled": false, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "runId": "85eea27b-fe0d-40b6-ae10-d2c7b829cdeb", + "status": "pass", + "passed": 2, + "failed": 0, + "result": { + "failedTests": 0, + "failures": [], + "inconclusiveTests": 0, + "latestResult": { + "fileContent": "{\r\n \"generatedAt\": \"2026-10-03T21:25:37.6564561Z\",\r\n \"runStartedAt\": \"2026-10-03T21:25:37.4176270Z\",\r\n \"durationSeconds\": 0.1734297,\r\n \"testMode\": \"PlayMode\",\r\n \"totalTests\": 2,\r\n \"passed\": 2,\r\n \"failed\": 0,\r\n \"skipped\": 0,\r\n \"inconclusive\": 0,\r\n \"status\": \"passed\",\r\n \"failures\": [],\r\n \"tests\": [\r\n {\r\n \"name\": \"FrameAdvances\",\r\n \"fullName\": \"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\",\r\n \"status\": \"Passed\",\r\n \"duration\": 0.0218017,\r\n \"message\": null,\r\n \"stackTrace\": null,\r\n \"output\": \"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\r\\n\"\r\n },\r\n {\r\n \"name\": \"RigidbodyFalls\",\r\n \"fullName\": \"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\",\r\n \"status\": \"Passed\",\r\n \"duration\": 0.1025816,\r\n \"message\": null,\r\n \"stackTrace\": null,\r\n \"output\": \"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\r\\n\"\r\n }\r\n ]\r\n}", + "generatedAt": "2026-10-03T21:25:37.6671220Z", + "path": "\\.cache\\issue-386\\staff-project\\.unity\\test-results\\TestResults_PlayMode_20261003_212530.json", + "status": "available", + "summary": { + "durationSeconds": 0.1734297, + "failed": 0, + "failures": [], + "generatedAt": "2026-10-03T21:25:37.6564561Z", + "inconclusive": 0, + "passed": 2, + "runStartedAt": "2026-10-03T21:25:37.4176270Z", + "skipped": 0, + "status": "passed", + "testMode": "PlayMode", + "tests": [ + { + "duration": 0.0218017, + "fullName": "UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances", + "message": null, + "name": "FrameAdvances", + "output": "[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\r\n", + "stackTrace": null, + "status": "Passed" + }, + { + "duration": 0.1025816, + "fullName": "UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls", + "message": null, + "name": "RigidbodyFalls", + "output": "[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\r\n", + "stackTrace": null, + "status": "Passed" + } + ], + "totalTests": 2 + } + }, + "passedTests": 2, + "runId": "85eea27b-fe0d-40b6-ae10-d2c7b829cdeb", + "skippedTests": 0, + "status": "completed", + "success": true, + "testMode": "PlayMode", + "tests": [ + { + "duration": 0.0218017, + "fullName": "UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances", + "message": null, + "name": "FrameAdvances", + "output": "[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\r\n", + "status": "Passed" + }, + { + "duration": 0.1025816, + "fullName": "UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls", + "message": null, + "name": "RigidbodyFalls", + "output": "[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\r\n", + "status": "Passed" + } + ], + "totalTests": 2 + } + }, + { + "domainReloadEnabled": false, + "settings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeOptionsEnabled": true, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "runId": "707b27fd-ae6a-4eb0-8e9f-f41b8430ce07", + "status": "pass", + "passed": 2, + "failed": 0, + "result": { + "failedTests": 0, + "failures": [], + "inconclusiveTests": 0, + "latestResult": { + "fileContent": "{\r\n \"generatedAt\": \"2026-10-03T21:25:41.7656478Z\",\r\n \"runStartedAt\": \"2026-10-03T21:25:41.6407521Z\",\r\n \"durationSeconds\": 0.1093431,\r\n \"testMode\": \"PlayMode\",\r\n \"totalTests\": 2,\r\n \"passed\": 2,\r\n \"failed\": 0,\r\n \"skipped\": 0,\r\n \"inconclusive\": 0,\r\n \"status\": \"passed\",\r\n \"failures\": [],\r\n \"tests\": [\r\n {\r\n \"name\": \"FrameAdvances\",\r\n \"fullName\": \"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\",\r\n \"status\": \"Passed\",\r\n \"duration\": 0.0044743,\r\n \"message\": null,\r\n \"stackTrace\": null,\r\n \"output\": \"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\r\\n\"\r\n },\r\n {\r\n \"name\": \"RigidbodyFalls\",\r\n \"fullName\": \"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\",\r\n \"status\": \"Passed\",\r\n \"duration\": 0.08695,\r\n \"message\": null,\r\n \"stackTrace\": null,\r\n \"output\": \"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\r\\n\"\r\n }\r\n ]\r\n}", + "generatedAt": "2026-10-03T21:25:41.7661521Z", + "path": "\\.cache\\issue-386\\staff-project\\.unity\\test-results\\TestResults_PlayMode_20261003_212540.json", + "status": "available", + "summary": { + "durationSeconds": 0.1093431, + "failed": 0, + "failures": [], + "generatedAt": "2026-10-03T21:25:41.7656478Z", + "inconclusive": 0, + "passed": 2, + "runStartedAt": "2026-10-03T21:25:41.6407521Z", + "skipped": 0, + "status": "passed", + "testMode": "PlayMode", + "tests": [ + { + "duration": 0.0044743, + "fullName": "UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances", + "message": null, + "name": "FrameAdvances", + "output": "[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\r\n", + "stackTrace": null, + "status": "Passed" + }, + { + "duration": 0.08695, + "fullName": "UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls", + "message": null, + "name": "RigidbodyFalls", + "output": "[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\r\n", + "stackTrace": null, + "status": "Passed" + } + ], + "totalTests": 2 + } + }, + "passedTests": 2, + "runId": "707b27fd-ae6a-4eb0-8e9f-f41b8430ce07", + "skippedTests": 0, + "status": "completed", + "success": true, + "testMode": "PlayMode", + "tests": [ + { + "duration": 0.0044743, + "fullName": "UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances", + "message": null, + "name": "FrameAdvances", + "output": "[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\r\n", + "status": "Passed" + }, + { + "duration": 0.08695, + "fullName": "UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls", + "message": null, + "name": "RigidbodyFalls", + "output": "[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\r\n", + "status": "Passed" + } + ], + "totalTests": 2 + } + } + ], + "calls": [ + { + "tool": "ping", + "parameters": {}, + "returncode": 0, + "stdout": "{\"command\":\"raw ping\",\"data\":{\"bridgeVersion\":\"0.18.1\",\"echo\":null,\"message\":\"pong\",\"projectPath\":\"E:\\\\unity-cli\\\\work\\\\issue-386\\\\.cache\\\\issue-386\\\\staff-project\",\"supportsSafeClose\":true,\"timestamp\":\"2026-10-03T21:25:30.1959524Z\"},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_project_settings", + "parameters": { + "includePlayer": false, + "includeEditor": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw get_project_settings\",\"data\":{\"editor\":{\"assetNamingUsesSpace\":true,\"defaultBehaviorMode\":\"Mode3D\",\"enterPlayModeOptions\":\"DisableDomainReload\",\"enterPlayModeOptionsEnabled\":true,\"prefabModeRegularEnvironment\":\"None\",\"prefabModeUIEnvironment\":\"None\",\"serializationMode\":\"ForceText\",\"unityRemote\":\"\",\"unityRemoteCompression\":\"\",\"unityRemoteResolution\":\"\"}},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "execute_menu_item", + "parameters": { + "action": "execute", + "menuPath": "Tools/Unity CLI/Test Runner E2E/Enable Domain Reload" + }, + "returncode": 0, + "stdout": "{\"command\":\"raw execute_menu_item\",\"data\":{\"executed\":true,\"executionTime\":1,\"menuExists\":true,\"menuPath\":\"Tools/Unity CLI/Test Runner E2E/Enable Domain Reload\",\"message\":\"Menu item executed successfully\",\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_project_settings", + "parameters": { + "includePlayer": false, + "includeEditor": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw get_project_settings\",\"data\":{\"editor\":{\"assetNamingUsesSpace\":true,\"defaultBehaviorMode\":\"Mode3D\",\"enterPlayModeOptions\":\"None\",\"enterPlayModeOptionsEnabled\":false,\"prefabModeRegularEnvironment\":\"None\",\"prefabModeUIEnvironment\":\"None\",\"serializationMode\":\"ForceText\",\"unityRemote\":\"\",\"unityRemoteCompression\":\"\",\"unityRemoteResolution\":\"\"}},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "run_tests", + "parameters": { + "testMode": "PlayMode", + "filter": "DomainReloadResultTests", + "includeDetails": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw run_tests\",\"data\":{\"message\":\"Test execution started. Use get_test_status to check progress.\",\"runId\":\"85eea27b-fe0d-40b6-ae10-d2c7b829cdeb\",\"status\":\"running\"},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_test_status", + "parameters": { + "includeTestResults": true, + "includeFileContent": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw get_test_status\",\"data\":{\"elapsedSeconds\":6.8131452999999995,\"message\":\"Test execution in progress\",\"runId\":\"85eea27b-fe0d-40b6-ae10-d2c7b829cdeb\",\"source\":\"run_tests\",\"status\":\"running\",\"testMode\":\"PlayMode\"},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_test_status", + "parameters": { + "includeTestResults": true, + "includeFileContent": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw get_test_status\",\"data\":{\"failedTests\":0,\"failures\":[],\"inconclusiveTests\":0,\"latestResult\":{\"fileContent\":\"{\\r\\n \\\"generatedAt\\\": \\\"2026-10-03T21:25:37.6564561Z\\\",\\r\\n \\\"runStartedAt\\\": \\\"2026-10-03T21:25:37.4176270Z\\\",\\r\\n \\\"durationSeconds\\\": 0.1734297,\\r\\n \\\"testMode\\\": \\\"PlayMode\\\",\\r\\n \\\"totalTests\\\": 2,\\r\\n \\\"passed\\\": 2,\\r\\n \\\"failed\\\": 0,\\r\\n \\\"skipped\\\": 0,\\r\\n \\\"inconclusive\\\": 0,\\r\\n \\\"status\\\": \\\"passed\\\",\\r\\n \\\"failures\\\": [],\\r\\n \\\"tests\\\": [\\r\\n {\\r\\n \\\"name\\\": \\\"FrameAdvances\\\",\\r\\n \\\"fullName\\\": \\\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\\",\\r\\n \\\"status\\\": \\\"Passed\\\",\\r\\n \\\"duration\\\": 0.0218017,\\r\\n \\\"message\\\": null,\\r\\n \\\"stackTrace\\\": null,\\r\\n \\\"output\\\": \\\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\\\r\\\\n\\\"\\r\\n },\\r\\n {\\r\\n \\\"name\\\": \\\"RigidbodyFalls\\\",\\r\\n \\\"fullName\\\": \\\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\\",\\r\\n \\\"status\\\": \\\"Passed\\\",\\r\\n \\\"duration\\\": 0.1025816,\\r\\n \\\"message\\\": null,\\r\\n \\\"stackTrace\\\": null,\\r\\n \\\"output\\\": \\\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\\\r\\\\n\\\"\\r\\n }\\r\\n ]\\r\\n}\",\"generatedAt\":\"2026-10-03T21:25:37.6671220Z\",\"path\":\"E:\\\\unity-cli\\\\work\\\\issue-386\\\\.cache\\\\issue-386\\\\staff-project\\\\.unity\\\\test-results\\\\TestResults_PlayMode_20261003_212530.json\",\"status\":\"available\",\"summary\":{\"durationSeconds\":0.1734297,\"failed\":0,\"failures\":[],\"generatedAt\":\"2026-10-03T21:25:37.6564561Z\",\"inconclusive\":0,\"passed\":2,\"runStartedAt\":\"2026-10-03T21:25:37.4176270Z\",\"skipped\":0,\"status\":\"passed\",\"testMode\":\"PlayMode\",\"tests\":[{\"duration\":0.0218017,\"fullName\":\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\",\"message\":null,\"name\":\"FrameAdvances\",\"output\":\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\r\\n\",\"stackTrace\":null,\"status\":\"Passed\"},{\"duration\":0.1025816,\"fullName\":\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\",\"message\":null,\"name\":\"RigidbodyFalls\",\"output\":\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\r\\n\",\"stackTrace\":null,\"status\":\"Passed\"}],\"totalTests\":2}},\"passedTests\":2,\"runId\":\"85eea27b-fe0d-40b6-ae10-d2c7b829cdeb\",\"skippedTests\":0,\"status\":\"completed\",\"success\":true,\"testMode\":\"PlayMode\",\"tests\":[{\"duration\":0.0218017,\"fullName\":\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\",\"message\":null,\"name\":\"FrameAdvances\",\"output\":\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\r\\n\",\"status\":\"Passed\"},{\"duration\":0.1025816,\"fullName\":\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\",\"message\":null,\"name\":\"RigidbodyFalls\",\"output\":\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\r\\n\",\"status\":\"Passed\"}],\"totalTests\":2},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_editor_state", + "parameters": {}, + "returncode": 0, + "stdout": "{\"command\":\"raw get_editor_state\",\"data\":{\"state\":{\"applicationContentsPath\":\"C:/Program Files/Unity/Hub/Editor/6000.4.4f1/Editor/Data\",\"applicationPath\":\"C:/Program Files/Unity/Hub/Editor/6000.4.4f1/Editor/Unity.exe\",\"isCompiling\":false,\"isPaused\":false,\"isPlaying\":false,\"isUpdating\":false,\"playability\":{\"compilation\":null,\"lastPlayRequestTime\":null,\"playRequested\":false,\"reason\":\"ready\"},\"timeSinceStartup\":1278.6441159},\"status\":\"success\"},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "execute_menu_item", + "parameters": { + "action": "execute", + "menuPath": "Tools/Unity CLI/Test Runner E2E/Disable Domain Reload" + }, + "returncode": 0, + "stdout": "{\"command\":\"raw execute_menu_item\",\"data\":{\"executed\":true,\"executionTime\":43,\"menuExists\":true,\"menuPath\":\"Tools/Unity CLI/Test Runner E2E/Disable Domain Reload\",\"message\":\"Menu item executed successfully\",\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_project_settings", + "parameters": { + "includePlayer": false, + "includeEditor": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw get_project_settings\",\"data\":{\"editor\":{\"assetNamingUsesSpace\":true,\"defaultBehaviorMode\":\"Mode3D\",\"enterPlayModeOptions\":\"DisableDomainReload\",\"enterPlayModeOptionsEnabled\":true,\"prefabModeRegularEnvironment\":\"None\",\"prefabModeUIEnvironment\":\"None\",\"serializationMode\":\"ForceText\",\"unityRemote\":\"\",\"unityRemoteCompression\":\"\",\"unityRemoteResolution\":\"\"}},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "run_tests", + "parameters": { + "testMode": "PlayMode", + "filter": "DomainReloadResultTests", + "includeDetails": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw run_tests\",\"data\":{\"message\":\"Test execution started. Use get_test_status to check progress.\",\"runId\":\"707b27fd-ae6a-4eb0-8e9f-f41b8430ce07\",\"status\":\"running\"},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_test_status", + "parameters": { + "includeTestResults": true, + "includeFileContent": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw get_test_status\",\"data\":{\"failedTests\":0,\"failures\":[],\"inconclusiveTests\":0,\"latestResult\":{\"fileContent\":\"{\\r\\n \\\"generatedAt\\\": \\\"2026-10-03T21:25:41.7656478Z\\\",\\r\\n \\\"runStartedAt\\\": \\\"2026-10-03T21:25:41.6407521Z\\\",\\r\\n \\\"durationSeconds\\\": 0.1093431,\\r\\n \\\"testMode\\\": \\\"PlayMode\\\",\\r\\n \\\"totalTests\\\": 2,\\r\\n \\\"passed\\\": 2,\\r\\n \\\"failed\\\": 0,\\r\\n \\\"skipped\\\": 0,\\r\\n \\\"inconclusive\\\": 0,\\r\\n \\\"status\\\": \\\"passed\\\",\\r\\n \\\"failures\\\": [],\\r\\n \\\"tests\\\": [\\r\\n {\\r\\n \\\"name\\\": \\\"FrameAdvances\\\",\\r\\n \\\"fullName\\\": \\\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\\",\\r\\n \\\"status\\\": \\\"Passed\\\",\\r\\n \\\"duration\\\": 0.0044743,\\r\\n \\\"message\\\": null,\\r\\n \\\"stackTrace\\\": null,\\r\\n \\\"output\\\": \\\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\\\r\\\\n\\\"\\r\\n },\\r\\n {\\r\\n \\\"name\\\": \\\"RigidbodyFalls\\\",\\r\\n \\\"fullName\\\": \\\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\\",\\r\\n \\\"status\\\": \\\"Passed\\\",\\r\\n \\\"duration\\\": 0.08695,\\r\\n \\\"message\\\": null,\\r\\n \\\"stackTrace\\\": null,\\r\\n \\\"output\\\": \\\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\\\r\\\\n\\\"\\r\\n }\\r\\n ]\\r\\n}\",\"generatedAt\":\"2026-10-03T21:25:41.7661521Z\",\"path\":\"E:\\\\unity-cli\\\\work\\\\issue-386\\\\.cache\\\\issue-386\\\\staff-project\\\\.unity\\\\test-results\\\\TestResults_PlayMode_20261003_212540.json\",\"status\":\"available\",\"summary\":{\"durationSeconds\":0.1093431,\"failed\":0,\"failures\":[],\"generatedAt\":\"2026-10-03T21:25:41.7656478Z\",\"inconclusive\":0,\"passed\":2,\"runStartedAt\":\"2026-10-03T21:25:41.6407521Z\",\"skipped\":0,\"status\":\"passed\",\"testMode\":\"PlayMode\",\"tests\":[{\"duration\":0.0044743,\"fullName\":\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\",\"message\":null,\"name\":\"FrameAdvances\",\"output\":\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\r\\n\",\"stackTrace\":null,\"status\":\"Passed\"},{\"duration\":0.08695,\"fullName\":\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\",\"message\":null,\"name\":\"RigidbodyFalls\",\"output\":\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\r\\n\",\"stackTrace\":null,\"status\":\"Passed\"}],\"totalTests\":2}},\"passedTests\":2,\"runId\":\"707b27fd-ae6a-4eb0-8e9f-f41b8430ce07\",\"skippedTests\":0,\"status\":\"completed\",\"success\":true,\"testMode\":\"PlayMode\",\"tests\":[{\"duration\":0.0044743,\"fullName\":\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\",\"message\":null,\"name\":\"FrameAdvances\",\"output\":\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.FrameAdvances\\r\\n\",\"status\":\"Passed\"},{\"duration\":0.08695,\"fullName\":\"UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\",\"message\":null,\"name\":\"RigidbodyFalls\",\"output\":\"[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.DomainReloadResultTests.RigidbodyFalls\\r\\n\",\"status\":\"Passed\"}],\"totalTests\":2},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_editor_state", + "parameters": {}, + "returncode": 0, + "stdout": "{\"command\":\"raw get_editor_state\",\"data\":{\"state\":{\"applicationContentsPath\":\"C:/Program Files/Unity/Hub/Editor/6000.4.4f1/Editor/Data\",\"applicationPath\":\"C:/Program Files/Unity/Hub/Editor/6000.4.4f1/Editor/Unity.exe\",\"isCompiling\":false,\"isPaused\":false,\"isPlaying\":false,\"isUpdating\":false,\"playability\":{\"compilation\":null,\"lastPlayRequestTime\":null,\"playRequested\":false,\"reason\":\"ready\"},\"timeSinceStartup\":1282.8478036},\"status\":\"success\"},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "execute_menu_item", + "parameters": { + "action": "execute", + "menuPath": "Tools/Unity CLI/Test Runner E2E/Restore Settings" + }, + "returncode": 0, + "stdout": "{\"command\":\"raw execute_menu_item\",\"data\":{\"executed\":true,\"executionTime\":0,\"menuExists\":true,\"menuPath\":\"Tools/Unity CLI/Test Runner E2E/Restore Settings\",\"message\":\"Menu item executed successfully\",\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + }, + { + "tool": "get_project_settings", + "parameters": { + "includePlayer": false, + "includeEditor": true + }, + "returncode": 0, + "stdout": "{\"command\":\"raw get_project_settings\",\"data\":{\"editor\":{\"assetNamingUsesSpace\":true,\"defaultBehaviorMode\":\"Mode3D\",\"enterPlayModeOptions\":\"DisableDomainReload\",\"enterPlayModeOptionsEnabled\":true,\"prefabModeRegularEnvironment\":\"None\",\"prefabModeUIEnvironment\":\"None\",\"serializationMode\":\"ForceText\",\"unityRemote\":\"\",\"unityRemoteCompression\":\"\",\"unityRemoteResolution\":\"\"}},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "" + } + ], + "ping": { + "bridgeVersion": "0.18.1", + "echo": null, + "message": "pong", + "projectPath": "\\.cache\\issue-386\\staff-project", + "supportsSafeClose": true, + "timestamp": "2026-10-03T21:25:30.1959524Z" + }, + "originalSettings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeOptionsEnabled": true, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "settingsRestored": true, + "status": "pass" +} diff --git a/docs/verification/issue-386/resume/domain-reload.txt b/docs/verification/issue-386/resume/domain-reload.txt new file mode 100644 index 00000000..c6c82a25 --- /dev/null +++ b/docs/verification/issue-386/resume/domain-reload.txt @@ -0,0 +1,3 @@ +PASS domainReloadEnabled=True: 2 passed, 0 failed +PASS domainReloadEnabled=False: 2 passed, 0 failed +Evidence: \.cache\issue-386\resume\domain-reload.json; pass diff --git a/docs/verification/issue-386/resume/eval.txt b/docs/verification/issue-386/resume/eval.txt new file mode 100644 index 00000000..f4ff1399 --- /dev/null +++ b/docs/verification/issue-386/resume/eval.txt @@ -0,0 +1,21 @@ +{"assetsPath": "/.cache/issue-386/staff-project/Assets", "codeIndexRoot": "/.cache/issue-386/staff-project/.unity/cache/code-index", "packagesPath": "/.cache/issue-386/staff-project/Packages", "projectRoot": "/.cache/issue-386/staff-project", "unity": {"platform": "WindowsEditor", "productName": "staff-project", "unityVersion": "6000.4.4f1"}} +PASS AC-1 numeric expression +PASS AC-3 create +PASS AC-2 read scene object +PASS Unity Object descriptor +PASS AC-3 modify +PASS requestId deduplication and status +PASS AC-4 compile diagnostics +PASS AC-4 runtime exception +PASS captured logs +PASS JSON array +PASS statements without return +PASS unknown status +PASS #391 identical source reuses its compilation +PASS #391 AC-3 newly loaded assembly resolves +PASS #391 AC-3 types resolve across Domain Reload +soak {"iterations": 1000, "evaluations": 1000, "emittedAssemblies": 4, "loadedAssemblies": 4, "managedMemoryGrowthBytes": 2658304, "storedResults": 256} +PASS #391 AC-4 1000 consecutive evaluations stay within bounds +PASS AC-5 no persistent C# files +PASS Play Mode expression +Eval E2E: 18 passed, 0 failed diff --git a/docs/verification/issue-386/resume/final-checks.json b/docs/verification/issue-386/resume/final-checks.json new file mode 100644 index 00000000..d3feb0a8 --- /dev/null +++ b/docs/verification/issue-386/resume/final-checks.json @@ -0,0 +1,58 @@ +[ + { + "argv": [ + "cargo", + "fmt", + "--all", + "--", + "--check" + ], + "started_at": "2026-10-03T22:03:49.943444+00:00", + "finished_at": "2026-10-03T22:03:50.756622+00:00", + "exit_code": 0, + "log": "fmt.log" + }, + { + "argv": [ + "cargo", + "clippy", + "--all-targets", + "--", + "-D", + "warnings" + ], + "started_at": "2026-10-03T22:03:50.757030+00:00", + "finished_at": "2026-10-03T22:03:52.010330+00:00", + "exit_code": 0, + "log": "clippy.log" + }, + { + "argv": [ + "cargo", + "test", + "--all-targets", + "--no-fail-fast", + "--", + "--test-threads=1" + ], + "started_at": "2026-10-03T22:03:52.010738+00:00", + "finished_at": "2026-10-03T22:06:31.762136+00:00", + "exit_code": 0, + "log": "cargo-all-final.log" + }, + { + "argv": [ + "cargo", + "run", + "--", + "skills", + "lint", + "--severity", + "error" + ], + "started_at": "2026-10-03T22:06:32.769563+00:00", + "finished_at": "2026-10-03T22:06:46.527203+00:00", + "exit_code": 0, + "log": "skills-lint-final.log" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/final-doc-checks.json b/docs/verification/issue-386/resume/final-doc-checks.json new file mode 100644 index 00000000..11178def --- /dev/null +++ b/docs/verification/issue-386/resume/final-doc-checks.json @@ -0,0 +1,45 @@ +[ + { + "argv": [ + "cargo", + "clippy", + "--workspace", + "--all-targets", + "--all-features", + "--", + "-D", + "warnings" + ], + "started_at": "2026-10-03T22:56:01.133701+00:00", + "log": "clippy-all-features-final.txt", + "exit_code": 0, + "finished_at": "2026-10-03T22:56:06.120231+00:00" + }, + { + "argv": [ + "cargo", + "doc", + "--workspace", + "--no-deps", + "--document-private-items" + ], + "started_at": "2026-10-03T22:56:06.120677+00:00", + "log": "rustdoc-final.txt", + "exit_code": 0, + "finished_at": "2026-10-03T22:56:15.763277+00:00" + }, + { + "argv": [ + "bunx", + "markdownlint-cli2", + "docs/comparison.md", + "docs/verification/issue-386/README.md", + "docs/verification/issue-386/resume/README.md", + "packaging/winget/README.md" + ], + "started_at": "2026-10-03T22:56:15.763736+00:00", + "log": "markdownlint-final.txt", + "exit_code": 0, + "finished_at": "2026-10-03T22:56:18.391255+00:00" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/final-markdown-check.json b/docs/verification/issue-386/resume/final-markdown-check.json new file mode 100644 index 00000000..4f6ac307 --- /dev/null +++ b/docs/verification/issue-386/resume/final-markdown-check.json @@ -0,0 +1,16 @@ +{ + "argv": [ + "bunx", + "markdownlint-cli2", + "docs/comparison.md", + "docs/hot-reload.md", + "docs/verification/issue-386/README.md", + "docs/verification/issue-386/resume/*.md", + "packaging/winget/README.md", + "tasks/lessons.md" + ], + "started_at": "2026-10-04T00:07:27.072912+00:00", + "exit_code": 0, + "finished_at": "2026-10-04T00:07:28.544136+00:00", + "log": "markdownlint-final.txt" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/fmt.txt b/docs/verification/issue-386/resume/fmt.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/docs/verification/issue-386/resume/fmt.txt @@ -0,0 +1 @@ + diff --git a/docs/verification/issue-386/resume/fresh-play-results.json b/docs/verification/issue-386/resume/fresh-play-results.json new file mode 100644 index 00000000..ed730f1a --- /dev/null +++ b/docs/verification/issue-386/resume/fresh-play-results.json @@ -0,0 +1,56 @@ +[ + { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "playmode", + "--filter", + "TouchGesturePlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\TouchGesturePlayModeTests-fresh.xml" + ], + "name": "TouchGesturePlayModeTests", + "started_at": "2026-10-03T22:56:41.476870+00:00", + "exit_code": 0, + "tests": 15, + "failed": 0, + "finished_at": "2026-10-03T22:57:03.993174+00:00" + }, + { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "playmode", + "--filter", + "InputSimulationAutomationPlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\InputSimulationAutomationPlayModeTests-fresh.xml" + ], + "name": "InputSimulationAutomationPlayModeTests", + "started_at": "2026-10-03T22:57:03.993573+00:00", + "exit_code": 8, + "tests": 7, + "failed": 2, + "finished_at": "2026-10-03T22:57:18.660143+00:00" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/fsr-package.json b/docs/verification/issue-386/resume/fsr-package.json new file mode 100644 index 00000000..f73b66cd --- /dev/null +++ b/docs/verification/issue-386/resume/fsr-package.json @@ -0,0 +1,9 @@ +{ + "url": "https://codeload.github.com/handzlikchris/FastScriptReload/zip/51140b71d9e5df1de231b33ec20ee089b18bebec", + "commit": "51140b71d9e5df1de231b33ec20ee089b18bebec", + "version": "1.8.0", + "package": "com.handzlikchris.fastscriptreload", + "archive_bytes": 14083364, + "archive_sha256": "5f04d854dd63bf7e6c285476e2d725cba0694b284cc2d82390b345d88b1f4435", + "assets": "\\.cache\\issue-386\\fsr-pinned\\FastScriptReload-51140b71d9e5df1de231b33ec20ee089b18bebec\\Assets" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/hot-reload-results.txt b/docs/verification/issue-386/resume/hot-reload-results.txt new file mode 100644 index 00000000..863dc582 --- /dev/null +++ b/docs/verification/issue-386/resume/hot-reload-results.txt @@ -0,0 +1,28 @@ +Unity: 6000.4.4f1 architecture: X64 mode: supported +PASS Editor process architecture is X64 +Backend: {"applied": [], "appliedRevision": null, "available": true, "backend": "FastScriptReload", "baselineRevision": null, "code": null, "failed": [], "limitation": null, "path": null, "platformSupported": true, "recovery": null, "recoveryRequired": false, "requestedRevision": null, "state": "idle", "supported": true, "transaction": null, "unverified": []} +PASS baseline calculation runs in real Play Mode +PASS Editor update observer records runtime and backend status without a queued request +PASS backend supports this actual Editor +PASS recovery stops Play without restarting +PASS recovery records compiled source checksum for next session +PASS recovery checksum matches actual compiled assembly +PASS new Play session executes original disk baseline after recovery +PASS hot_reload rejects: STALE / +PASS hot_reload rejects: SYNTAX / +PASS hot_reload rejects: UNSUPPORTED / +PASS preflight failures preserve verified revision +PASS Play continues with expected calculation +PASS scene/object identity, position, HP, score, static and nonserialized state preserved +PASS new revision follows verified natural execution +PASS Play continues with expected calculation +PASS scene/object identity, position, HP, score, static and nonserialized state preserved +PASS successful preview leaves disk source unchanged +PASS partially executing preview clears whole-version claim while verification is pending +PASS hot_reload rejects: HOT_RELOAD_VERIFICATION_FAILED / +PASS unverified partial transaction clears whole-version claim and requires recovery +PASS recovery stops Play without restarting +PASS recovery records compiled source checksum for next session +PASS recovery checksum matches actual compiled assembly +PASS new Play session executes original disk baseline after recovery +RESULT pass=25 fail=0 diff --git a/docs/verification/issue-386/resume/hot-reload-summary.json b/docs/verification/issue-386/resume/hot-reload-summary.json new file mode 100644 index 00000000..b39c00de --- /dev/null +++ b/docs/verification/issue-386/resume/hot-reload-summary.json @@ -0,0 +1,49 @@ +{ + "editor": "6000.4.4f1 Windows x64", + "port": "6492", + "project": "\\.cache\\issue-386\\resume\\hot-reload-windows\\Project", + "command": [ + "C:/Program Files/Unity/Hub/Editor/6000.4.4f1/Editor/Unity.exe", + "-batchmode", + "-nographics", + "-projectPath", + "\\.cache\\issue-386\\resume\\hot-reload-windows\\Project", + "-executeMethod", + "UnityCliBridge.TestScenes.UnityCliInputBatchHost.Run", + "-logFile", + "\\.cache\\issue-386\\resume\\hot-reload-windows\\editor.log" + ], + "fsr": { + "url": "https://codeload.github.com/handzlikchris/FastScriptReload/zip/51140b71d9e5df1de231b33ec20ee089b18bebec", + "commit": "51140b71d9e5df1de231b33ec20ee089b18bebec", + "version": "1.8.0", + "package": "com.handzlikchris.fastscriptreload", + "archive_bytes": 14083364, + "archive_sha256": "5f04d854dd63bf7e6c285476e2d725cba0694b284cc2d82390b345d88b1f4435", + "assets": "\\.cache\\issue-386\\fsr-pinned\\FastScriptReload-51140b71d9e5df1de231b33ec20ee089b18bebec\\Assets" + }, + "started_at": "2026-10-03T23:03:53.394825+00:00", + "cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", + "pid": 5188, + "test_command": [ + "py", + "-3", + "-X", + "utf8", + "-B", + "\\scripts\\e2e-hot-reload.py", + "--project", + "\\.cache\\issue-386\\resume\\hot-reload-windows\\Project", + "--port", + "6492", + "--unity-cli", + "\\target\\debug\\unity-cli.exe", + "--expect", + "supported", + "--require-arch", + "X64" + ], + "exit_code": 0, + "editor_exit_code": 4294967295, + "finished_at": "2026-10-03T23:08:21.043376+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/input-actions-persistence.txt b/docs/verification/issue-386/resume/input-actions-persistence.txt new file mode 100644 index 00000000..a395091c --- /dev/null +++ b/docs/verification/issue-386/resume/input-actions-persistence.txt @@ -0,0 +1,54 @@ +Unity 6000.4.4f1; port 6489; artifacts \AppData\Local\Temp\input-actions-persistence-oyi524qv +Unity host 1 ready: \AppData\Local\Temp\input-actions-persistence-oyi524qv\unity-1.log +PASS create_action_map: source map/action/binding contents and IDs match memory +PASS create_action_map: source control schemes match memory +PASS create_action_map: reimport preserves structure and IDs +PASS add_input_action: source map/action/binding contents and IDs match memory +PASS add_input_action: source control schemes match memory +PASS add_input_action: reimport preserves structure and IDs +PASS add_input_binding: source map/action/binding contents and IDs match memory +PASS add_input_binding: source control schemes match memory +PASS add_input_binding: reimport preserves structure and IDs +PASS remove_input_binding: source map/action/binding contents and IDs match memory +PASS remove_input_binding: source control schemes match memory +PASS remove_input_binding: reimport preserves structure and IDs +PASS create_composite_binding: source map/action/binding contents and IDs match memory +PASS create_composite_binding: source control schemes match memory +PASS create_composite_binding: reimport preserves structure and IDs +PASS remove_all_bindings: source map/action/binding contents and IDs match memory +PASS remove_all_bindings: source control schemes match memory +PASS remove_all_bindings: reimport preserves structure and IDs +PASS add_input_binding: source map/action/binding contents and IDs match memory +PASS add_input_binding: source control schemes match memory +PASS add_input_binding: reimport preserves structure and IDs +PASS remove_input_action: source map/action/binding contents and IDs match memory +PASS remove_input_action: source control schemes match memory +PASS remove_input_action: reimport preserves structure and IDs +PASS create_action_map: source map/action/binding contents and IDs match memory +PASS create_action_map: source control schemes match memory +PASS create_action_map: reimport preserves structure and IDs +PASS remove_action_map: source map/action/binding contents and IDs match memory +PASS remove_action_map: source control schemes match memory +PASS remove_action_map: reimport preserves structure and IDs +PASS manage_control_schemes: source map/action/binding contents and IDs match memory +PASS manage_control_schemes: source control schemes match memory +PASS manage_control_schemes: reimport preserves structure and IDs +PASS manage_control_schemes: source map/action/binding contents and IDs match memory +PASS manage_control_schemes: source control schemes match memory +PASS manage_control_schemes: reimport preserves structure and IDs +PASS manage_control_schemes: source map/action/binding contents and IDs match memory +PASS manage_control_schemes: source control schemes match memory +PASS manage_control_schemes: reimport preserves structure and IDs +PASS add_input_binding: source map/action/binding contents and IDs match memory +PASS add_input_binding: source control schemes match memory +PASS add_input_binding: reimport preserves structure and IDs +Unity host 2 ready: \AppData\Local\Temp\input-actions-persistence-oyi524qv\unity-2.log +PASS Editor restart preserves maps/actions/bindings/schemes and IDs +PASS Editor restart preserves source JSON +PASS remove_action_map: source map/action/binding contents and IDs match memory +PASS remove_action_map: source control schemes match memory +PASS remove_action_map: reimport preserves structure and IDs +PASS manage_control_schemes: source map/action/binding contents and IDs match memory +PASS manage_control_schemes: source control schemes match memory +PASS manage_control_schemes: reimport preserves structure and IDs +{"unity_version": "6000.4.4f1", "passed": 50, "failed": 0, "editor_starts": 2, "artifacts": "\\AppData\\Local\\Temp\\input-actions-persistence-oyi524qv"} diff --git a/docs/verification/issue-386/resume/input-counter-green.json b/docs/verification/issue-386/resume/input-counter-green.json new file mode 100644 index 00000000..a3253c8d --- /dev/null +++ b/docs/verification/issue-386/resume/input-counter-green.json @@ -0,0 +1,25 @@ +{ + "command": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6493", + "test", + "--project-path", + "\\.cache\\issue-386\\resume\\hot-reload-windows\\Project", + "--mode", + "playmode", + "--filter", + "InputSimulationAutomationPlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\InputSimulationAutomationPlayModeTests-counter-green.xml" + ], + "mode": "native Windows headless / isolated minimal fixture", + "exit_code": 0, + "tests": 11, + "failed": 0 +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/input-counter-green.txt b/docs/verification/issue-386/resume/input-counter-green.txt new file mode 100644 index 00000000..c9467322 --- /dev/null +++ b/docs/verification/issue-386/resume/input-counter-green.txt @@ -0,0 +1,2 @@ +Started headless Editor (pid 34888) +11 tests, 0 failed; report: \.cache\issue-386\resume\InputSimulationAutomationPlayModeTests-counter-green.xml diff --git a/docs/verification/issue-386/resume/input-counter-red.json b/docs/verification/issue-386/resume/input-counter-red.json new file mode 100644 index 00000000..007910e5 --- /dev/null +++ b/docs/verification/issue-386/resume/input-counter-red.json @@ -0,0 +1,25 @@ +{ + "command": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6493", + "test", + "--project-path", + "\\.cache\\issue-386\\resume\\hot-reload-windows\\Project", + "--mode", + "playmode", + "--filter", + "InputSimulationAutomationPlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\InputSimulationAutomationPlayModeTests-counter-red.xml" + ], + "mode": "native Windows headless / isolated minimal fixture", + "exit_code": 8, + "tests": 11, + "failed": 3 +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/input-counter-red.txt b/docs/verification/issue-386/resume/input-counter-red.txt new file mode 100644 index 00000000..21dd5bd1 --- /dev/null +++ b/docs/verification/issue-386/resume/input-counter-red.txt @@ -0,0 +1,3 @@ +Started headless Editor (pid 26584) +11 tests, 3 failed; report: \.cache\issue-386\resume\InputSimulationAutomationPlayModeTests-counter-red.xml +TEST_FAILED: Unity command failed (code: UNKNOWN_ERROR) diff --git a/docs/verification/issue-386/resume/linux-gnome-fallback-result.json b/docs/verification/issue-386/resume/linux-gnome-fallback-result.json new file mode 100644 index 00000000..4f2d12d2 --- /dev/null +++ b/docs/verification/issue-386/resume/linux-gnome-fallback-result.json @@ -0,0 +1,34 @@ +{ + "started_at": "2026-10-03T20:40:53.902978+00:00", + "real_editor": false, + "compositor": "GNOME Shell 46 nested Wayland", + "shell_pid": 1506028, + "exit_code": 0, + "stdout": { + "command": "raw capture_screenshot", + "data": { + "captureMode": "game", + "fallback": "os", + "fallbackTool": "gnome-screenshot", + "fileSize": 16225, + "height": 600, + "message": "Desktop screenshot captured by the OS (Unity Editor did not respond)", + "note": "Unity Editor did not respond (OPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)); captured the whole desktop with an OS screenshot instead. The Editor main thread may be blocked by a modal dialog. Pass \"osFallback\": false to get the timeout error instead.", + "path": "/tmp/issue386-gnome-ssj55wmm/CaptureProject/.unity/capture/image_os_1791060058291.png", + "width": 800 + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stderr": "\u001b[2m2026-10-03T20:40:58.289725Z\u001b[0m \u001b[33m WARN\u001b[0m Unity did not respond; falling back to OS screenshot \u001b[3merror\u001b[0m\u001b[2m=\u001b[0mOPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)\n", + "png": { + "size": [ + 800, + 600 + ], + "sha256": "bb8d1f1f9236430fc6567fa822e63e04ef5cd0d9747ad66c346d20d9e1766f26" + }, + "passed": true, + "finished_at": "2026-10-03T20:41:01.353274+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/linux-license.json b/docs/verification/issue-386/resume/linux-license.json new file mode 100644 index 00000000..0803b857 --- /dev/null +++ b/docs/verification/issue-386/resume/linux-license.json @@ -0,0 +1,7 @@ +{ + "editor": "6000.4.4f1 Linux x64", + "exit_code": 198, + "result": "No valid Unity Editor license found. Please activate your license.", + "hub": "3.22.2 official package installed and sign-in window started", + "real_editor_verified": false +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/linux-wayland-extra-results.json b/docs/verification/issue-386/resume/linux-wayland-extra-results.json new file mode 100644 index 00000000..b422fae7 --- /dev/null +++ b/docs/verification/issue-386/resume/linux-wayland-extra-results.json @@ -0,0 +1,35 @@ +[ + { + "tool": "spectacle", + "started_at": "2026-10-03T20:55:11.313451+00:00", + "real_editor": false, + "exit_code": 0, + "stdout": { + "command": "raw capture_screenshot", + "data": { + "captureMode": "game", + "fallback": "os", + "fallbackTool": "spectacle", + "fileSize": 5327, + "height": 720, + "message": "Desktop screenshot captured by the OS (Unity Editor did not respond)", + "note": "Unity Editor did not respond (OPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)); captured the whole desktop with an OS screenshot instead. The Editor main thread may be blocked by a modal dialog. Pass \"osFallback\": false to get the timeout error instead.", + "path": "/tmp/issue386-spectacle-9wpjr84r/CaptureProject/.unity/capture/image_os_1791060914678.png", + "width": 1280 + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stderr": "\u001b[2m2026-10-03T20:55:14.676790Z\u001b[0m \u001b[33m WARN\u001b[0m Unity did not respond; falling back to OS screenshot \u001b[3merror\u001b[0m\u001b[2m=\u001b[0mOPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)\n", + "png": { + "size": [ + 1280, + 720 + ], + "sha256": "8dc98e7f34604d19f8d0c2e0654c36e47ebd63193de9da301fe395df74969b26" + }, + "passed": true, + "finished_at": "2026-10-03T20:55:15.796264+00:00" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/linux-wayland-first-results.json b/docs/verification/issue-386/resume/linux-wayland-first-results.json new file mode 100644 index 00000000..577acb16 --- /dev/null +++ b/docs/verification/issue-386/resume/linux-wayland-first-results.json @@ -0,0 +1,60 @@ +[ + { + "tool": "grim", + "started_at": "2026-10-03T20:53:36.396523+00:00", + "real_editor": false, + "exit_code": 0, + "stdout": { + "command": "raw capture_screenshot", + "data": { + "captureMode": "game", + "fallback": "os", + "fallbackTool": "grim", + "fileSize": 4319, + "height": 720, + "message": "Desktop screenshot captured by the OS (Unity Editor did not respond)", + "note": "Unity Editor did not respond (OPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)); captured the whole desktop with an OS screenshot instead. The Editor main thread may be blocked by a modal dialog. Pass \"osFallback\": false to get the timeout error instead.", + "path": "/tmp/issue386-grim-hycf6y8w/CaptureProject/.unity/capture/image_os_1791060819733.png", + "width": 1280 + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stderr": "\u001b[2m2026-10-03T20:53:39.731779Z\u001b[0m \u001b[33m WARN\u001b[0m Unity did not respond; falling back to OS screenshot \u001b[3merror\u001b[0m\u001b[2m=\u001b[0mOPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)\n", + "png": { + "size": [ + 1280, + 720 + ], + "sha256": "b4d1a3754933377521fe5c694fb1f6275e229cba8fa5db7b4ea4f9fb51e5e9e4" + }, + "passed": true, + "finished_at": "2026-10-03T20:53:39.789517+00:00" + }, + { + "tool": "spectacle", + "started_at": "2026-10-03T20:53:39.793108+00:00", + "real_editor": false, + "exit_code": 6, + "stdout": { + "command": "raw capture_screenshot", + "data": { + "code": "TIMEOUT", + "error": "OPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed", + "status": "error" + }, + "errors": [ + { + "code": "TIMEOUT", + "message": "OS screenshot fallback also failed: No OS screenshot tool succeeded (grim: No such file or directory (os error 2); gnome-screenshot: No such file or directory (os error 2); spectacle: exited with exit status: 1: On Wayland, Spectacle requires KDE Plasma's KWin compositor, which does not seem to be available. Use Spectacle on KDE Plasma, or use a different screenshot tool.; import: No such file or directory (os error 2); scrot: No such file or directory (os error 2); maim: No such file or directory (os error 2)): OPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)" + } + ], + "success": false, + "warnings": [] + }, + "stderr": "\u001b[2m2026-10-03T20:53:43.042585Z\u001b[0m \u001b[33m WARN\u001b[0m Unity did not respond; falling back to OS screenshot \u001b[3merror\u001b[0m\u001b[2m=\u001b[0mOPERATION_FAILED: Timed out while waiting for Unity response header: deadline has elapsed (code: TIMEOUT)\n", + "passed": false, + "finished_at": "2026-10-03T20:53:43.687922+00:00" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/linux-x11-platform.txt b/docs/verification/issue-386/resume/linux-x11-platform.txt new file mode 100644 index 00000000..b26f7f50 --- /dev/null +++ b/docs/verification/issue-386/resume/linux-x11-platform.txt @@ -0,0 +1,14 @@ +unity-cli: unity-cli 0.18.1 (linux, home=/tmp/unity-cli-platform-checks-acyvccna/home) +[PASS] discovery: instances list succeeds: exit=0 +[PASS] discovery: live PID is discovered from its lockfile: {"active": false, "host": "127.0.0.1", "id": "127.0.0.1:59475", "last_checked_at": "1791059172", "lockfile": "/tmp/unity-cli-platform-checks-acyvccna/home/.unity-cli/editors/1492255.json", "pid": 1492255, "port": 59475, "project_path": "/tmp/unity-cli-platform-checks-acyvccna/LiveProject", "source": "lockfile", "state": "ready", "status": "down", "unity_version": "6000.3.25f1"} +[PASS] discovery: exited PID is listed as unreachable: {"active": false, "host": "127.0.0.1", "id": "127.0.0.1:34399", "last_checked_at": "1791059172", "lockfile": "/tmp/unity-cli-platform-checks-acyvccna/home/.unity-cli/editors/1492256.json", "pid": 1492256, "port": 34399, "project_path": "/tmp/unity-cli-platform-checks-acyvccna/DeadProject", "source": "lockfile", "stale_reason": "process 1492256 is not running", "state": "ready", "status": "unreachable", "unity_version": "6000.3.25f1"} +[PASS] discovery: exited PID is excluded from target selection: exit=7 codes=['EDITOR_NOT_FOUND'] candidates=[1492255] live=1492255 +[PASS] setup: --dry-run succeeds: exit=0 +[PASS] setup: plan lists binary, bridge, launch and wait steps: ["binary", "bridge", "launch", "wait"] +[PASS] setup: plan installs the Bridge into the project manifest: {"action": "install", "declared": "0.18.1", "dryRun": true, "inputBackends": {"changed": true, "previous": 0}, "installed": true, "manifestChanged": true, "manifestPath": "/tmp/unity-cli-platform-checks-acyvccna/Setup Project/Packages/manifest.json", "notes": ["Set PlayerSettings activeInputHandler to Both (2) so the Input System dependency imports without a restart prompt"], "package": "com.akiojin.unity-cli-bridge", "projectPath": "/tmp/unity-cli-platform-checks-acyvccna/Setup Project", "registry": true, "resolvedVersion": null, "source": "registry", "versionCheck": {"bridgeVersion": "0.18.1", "cliVersion": "0.18.1", "message": "CLI and bridge are both 0.18.1", "status": "match"}} +[PASS] setup: no Editor is contacted: {"checked": false, "endpoint": "127.0.0.1:59131"} +[PASS] setup: the manifest is left untouched +[PASS] screenshot: import writes a PNG after the Editor times out: exit=0 size=(1280, 720) bytes=250 path=/tmp/unity-cli-platform-checks-acyvccna/CaptureProject/.unity/capture/image_os_1791059176319.png +[PASS] screenshot: scrot writes a PNG after the Editor times out: exit=0 size=(1280, 720) bytes=2774 path=/tmp/unity-cli-platform-checks-acyvccna/CaptureProject/.unity/capture/image_os_1791059179434.png +[PASS] screenshot: maim writes a PNG after the Editor times out: exit=0 size=(1280, 720) bytes=5446 path=/tmp/unity-cli-platform-checks-acyvccna/CaptureProject/.unity/capture/image_os_1791059182508.png +12/12 checks passed diff --git a/docs/verification/issue-386/resume/markdownlint-final.txt b/docs/verification/issue-386/resume/markdownlint-final.txt new file mode 100644 index 00000000..0192bc92 --- /dev/null +++ b/docs/verification/issue-386/resume/markdownlint-final.txt @@ -0,0 +1,4 @@ +markdownlint-cli2 v0.23.3 (markdownlint v0.41.1) +Finding: docs/comparison.md docs/hot-reload.md docs/verification/issue-386/README.md docs/verification/issue-386/resume/*.md packaging/winget/README.md tasks/lessons.md +Linting: 7 files +Summary: 0 issues in 0 files diff --git a/docs/verification/issue-386/resume/mcp-live-editor-green.txt b/docs/verification/issue-386/resume/mcp-live-editor-green.txt new file mode 100644 index 00000000..03340507 --- /dev/null +++ b/docs/verification/issue-386/resume/mcp-live-editor-green.txt @@ -0,0 +1,10 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 1.08s + Running tests\mcp.rs (target\debug\deps\mcp-9035db26334793d1.exe) + +running 3 tests +test configure_all_clients_preserves_other_servers_and_dry_run ... ok +test malformed_requests_do_not_end_session_or_execute_tools_before_initialization ... ok +test stdio_catalog_and_failure_contract_without_editor ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 13.71s diff --git a/docs/verification/issue-386/resume/modal-summary.json b/docs/verification/issue-386/resume/modal-summary.json new file mode 100644 index 00000000..037becef --- /dev/null +++ b/docs/verification/issue-386/resume/modal-summary.json @@ -0,0 +1,49 @@ +{ + "started_at": "2026-10-03T20:33:31.809137+00:00", + "source_commit": "0458d7fa83d55a3e77cb833ba74c705b65927a30", + "binary_sha256": "0038934812c1881055a67f05e463719dac55813293402991e78ba75aa63dfd7a", + "cases": { + "modal-os-fallback": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "1000", + "raw", + "capture_screenshot", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 2.712, + "success": true + }, + "modal-fallback-disabled": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "1000", + "raw", + "capture_screenshot", + "--json", + "{\"osFallback\":false}" + ], + "exit_code": 6, + "elapsed_seconds": 1.381, + "success": false + } + }, + "png": { + "width": 1512, + "height": 949, + "sha256": "031d61efffff00d2c99dc2539edde622facb7bfb63ee0d7ef99592d5a1aee438" + }, + "finished_at": "2026-10-03T20:33:36.765486+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/more-e2e-results.json b/docs/verification/issue-386/resume/more-e2e-results.json new file mode 100644 index 00000000..7ed29c7d --- /dev/null +++ b/docs/verification/issue-386/resume/more-e2e-results.json @@ -0,0 +1,255 @@ +[ + { + "name": "bake-fixed", + "argv": [ + "py", + "-3", + "-X", + "utf8", + "-B", + "scripts/e2e-bake.py", + "--unity-cli", + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "--project-root", + "\\.cache\\issue-386\\staff-project" + ], + "started_at": "2026-10-03T21:54:38.678106+00:00", + "exit_code": 1, + "finished_at": "2026-10-03T21:57:28.578724+00:00" + }, + { + "name": "reference-longpath-fixed", + "argv": [ + "py", + "-3", + "-X", + "utf8", + "-B", + ".cache/issue-386/run-reference-native.py" + ], + "started_at": "2026-10-03T21:57:28.579122+00:00", + "exit_code": 1, + "finished_at": "2026-10-03T21:58:33.942750+00:00" + }, + { + "name": "BakeHandlerTests", + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "editmode", + "--filter", + "BakeHandlerTests", + "--timeout", + "180", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\BakeHandlerTests.xml" + ], + "started_at": "2026-10-03T21:58:33.943118+00:00", + "exit_code": 0, + "tests": 15, + "failed": 0, + "skipped": 0, + "finished_at": "2026-10-03T21:59:01.501715+00:00" + }, + { + "name": "InputActionsHandlerTests", + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "editmode", + "--filter", + "InputActionsHandlerTests", + "--timeout", + "180", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\InputActionsHandlerTests.xml" + ], + "started_at": "2026-10-03T21:59:01.502095+00:00", + "exit_code": 0, + "tests": 12, + "failed": 0, + "skipped": 0, + "finished_at": "2026-10-03T21:59:07.499792+00:00" + }, + { + "name": "InputActionNotificationTests", + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "editmode", + "--filter", + "InputActionNotificationTests", + "--timeout", + "180", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\InputActionNotificationTests.xml" + ], + "started_at": "2026-10-03T21:59:07.500173+00:00", + "exit_code": 0, + "tests": 4, + "failed": 0, + "skipped": 0, + "finished_at": "2026-10-03T21:59:15.275551+00:00" + }, + { + "name": "AnimationCurveHandlerTests", + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "editmode", + "--filter", + "AnimationCurveHandlerTests", + "--timeout", + "180", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\AnimationCurveHandlerTests.xml" + ], + "started_at": "2026-10-03T21:59:15.275874+00:00", + "exit_code": 0, + "tests": 26, + "failed": 0, + "skipped": 0, + "finished_at": "2026-10-03T21:59:24.666670+00:00" + }, + { + "name": "SceneHandlerTests", + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "editmode", + "--filter", + "SceneHandlerTests", + "--timeout", + "180", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\SceneHandlerTests.xml" + ], + "started_at": "2026-10-03T21:59:24.667026+00:00", + "exit_code": 0, + "tests": 11, + "failed": 0, + "skipped": 0, + "finished_at": "2026-10-03T21:59:31.323415+00:00" + }, + { + "name": "InputSimulationAutomationPlayModeTests", + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "playmode", + "--filter", + "InputSimulationAutomationPlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\InputSimulationAutomationPlayModeTests.xml" + ], + "started_at": "2026-10-03T21:59:31.323762+00:00", + "exit_code": 8, + "tests": 7, + "failed": 2, + "skipped": 0, + "finished_at": "2026-10-03T21:59:44.010030+00:00" + }, + { + "name": "GamepadStickInputPlayModeTests", + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "playmode", + "--filter", + "GamepadStickInputPlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\GamepadStickInputPlayModeTests.xml" + ], + "started_at": "2026-10-03T21:59:44.010397+00:00", + "exit_code": 0, + "tests": 2, + "failed": 0, + "skipped": 0, + "finished_at": "2026-10-03T21:59:47.331843+00:00" + }, + { + "name": "TouchGesturePlayModeTests", + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "playmode", + "--filter", + "TouchGesturePlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\TouchGesturePlayModeTests.xml" + ], + "started_at": "2026-10-03T21:59:47.332206+00:00", + "exit_code": 8, + "tests": 15, + "failed": 14, + "skipped": 0, + "finished_at": "2026-10-03T22:00:09.232996+00:00" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/official-windows-binary.json b/docs/verification/issue-386/resume/official-windows-binary.json new file mode 100644 index 00000000..2479c1a0 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-binary.json @@ -0,0 +1,11 @@ +{ + "url": "https://public-cdn.cloud.unity3d.com/hub/prod/cli/1.0.0-beta.11/unity-windows-x64.exe", + "manifest_url": "https://public-cdn.cloud.unity3d.com/hub/prod/cli/1.0.0-beta.11/latest.json", + "version": "1.0.0-beta.11", + "sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", + "official_sha256_matched": true, + "bytes": 26154920, + "binary": "\\.cache\\issue-386\\resume\\official-windows\\unity.exe", + "version_exit": 0, + "version_stdout": "{\n \"success\": true,\n \"command\": \"version\",\n \"data\": {\n \"version\": \"1.0.0-beta.11\",\n \"channel\": \"beta\",\n \"commit\": null,\n \"platform\": \"win32\",\n \"arch\": \"x64\",\n \"runtime\": \".NET 10.0.12\"\n },\n \"errors\": [],\n \"warnings\": []\n}\n" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/official-windows-comparison-resident.txt b/docs/verification/issue-386/resume/official-windows-comparison-resident.txt new file mode 100644 index 00000000..41b7dfa3 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-comparison-resident.txt @@ -0,0 +1,23 @@ +resident frontmost: cycle 1/103 +resident frontmost: cycle 2/103 +resident frontmost: cycle 3/103 +resident frontmost: cycle 4/103 +resident frontmost: cycle 5/103 +resident frontmost: cycle 6/103 +resident frontmost: cycle 7/103 +resident frontmost: cycle 8/103 +resident frontmost: cycle 9/103 +resident frontmost: cycle 10/103 +resident frontmost: cycle 11/103 +resident frontmost: cycle 12/103 +resident frontmost: cycle 13/103 +resident frontmost: cycle 14/103 +resident frontmost: cycle 15/103 +resident frontmost: cycle 16/103 +resident frontmost: cycle 17/103 +resident frontmost: cycle 18/103 +resident frontmost: cycle 19/103 +resident frontmost: cycle 20/103 +resident frontmost: cycle 21/103 +resident frontmost: cycle 22/103 +resident frontmost: cycle 23/103 diff --git a/docs/verification/issue-386/resume/official-windows-comparison.txt b/docs/verification/issue-386/resume/official-windows-comparison.txt new file mode 100644 index 00000000..1f14b2e0 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-comparison.txt @@ -0,0 +1,9 @@ +done: create_gameobject +done: hierarchy +done: eval +process background PASS +resident frontmost FAIL Invalid official NDJSON response: {'id': '15', 'exitCode': 6, 'envelope': {'success': False, 'command': 'unity command find_assets', 'data': None, 'errors': [{'code': 'COMMAND_FAILED', 'message': 'Pipeline server returned 400 Bad Request: Parameter Validation Failed. Illegal characters in path.'}], 'warnings': []}} +Traceback (most recent call last): + File "\.cache\issue-386\windows-comparison.py", line 168, in + raise RuntimeError(report['error']) +RuntimeError: Invalid official NDJSON response: {'id': '15', 'exitCode': 6, 'envelope': {'success': False, 'command': 'unity command find_assets', 'data': None, 'errors': [{'code': 'COMMAND_FAILED', 'message': 'Pipeline server returned 400 Bad Request: Parameter Validation Failed. Illegal characters in path.'}], 'warnings': []}} diff --git a/docs/verification/issue-386/resume/official-windows-process-background.json b/docs/verification/issue-386/resume/official-windows-process-background.json new file mode 100644 index 00000000..368adad7 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-process-background.json @@ -0,0 +1,725 @@ +{ + "mode": "process", + "focus": "background", + "started_at": "2026-10-03T23:33:33.671584+00:00", + "conditions": { + "started_at": "2026-10-03T23:33:26.503448+00:00", + "os": "Windows-11-10.0.26300-SP0", + "arch": "AMD64", + "logical_cpus": 32, + "unity": "6000.4.4f1", + "editor_pid": 34324, + "iterations": 100, + "warmup": 3, + "unity_cli_build": "native Windows debug 0.18.1", + "official_cli_version": "1.0.0-beta.11", + "pipeline_version": "0.8.0-exp.1", + "unity_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", + "official_cli_sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", + "benchmark_sha256": "857569c8c542221f43a27423ecfa8fce3d11a690ed979985ebc670a56912f372", + "windows_adapter_sha256": "1d72ca848808f1fcce45a46b133691c7c6119f908e67e9519f72759a19d5af7b", + "windows_adapter": "Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.", + "background_condition": "Owned Editor minimized, because Windows refused activation of the existing GWT background window. This differs from macOS visible-background measurements.", + "host_contention": "Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.", + "coexistence": { + "same_project": true, + "unity_version": "6000.4.4f1", + "official_state": "ready", + "project_identity_sha256": "f87f40b8af586b040ebc3f0d64bf076a0bebf421cd38cb9af459bc31f2a0c69a" + }, + "play_settings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeOptionsEnabled": true, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "unityd_pid": 52020 + }, + "status": "PASS", + "samples_ms": { + "unity-cli": { + "create_gameobject": [ + 605.6073000072502, + 328.3432000025641, + 52.89600000833161, + 323.1718000024557, + 269.5679000171367, + 328.02190000074916, + 272.35279997694306, + 873.4148999792524, + 280.29410002636723, + 108.38699998566881, + 271.4110999950208, + 1298.708100017393, + 262.3355000105221, + 646.5700000117067, + 163.0806000030134, + 324.06559999799356, + 911.1498999991454, + 107.37559999688528, + 394.60900000995025, + 324.73530000424944, + 166.38619999866933, + 551.3350999972317, + 60.97220000810921, + 108.35530000622384, + 380.8351999905426, + 107.689800002845, + 253.52009999915026, + 108.23890002211556, + 257.7762999862898, + 320.421600015834, + 379.545900010271, + 107.77209998923354, + 57.62800000957213, + 109.61210000095889, + 62.73849998251535, + 109.10699999658391, + 55.765500001143664, + 109.06109999632463, + 713.6243999993894, + 325.06450000801124, + 67.57169999764301, + 111.10899999039248, + 52.06960000214167, + 108.84870000882074, + 168.52589999325573, + 108.78359997877851, + 272.3863999999594, + 109.1415999981109, + 161.0631000075955, + 115.54700002307072, + 56.088399986037984, + 108.2559000060428, + 46.24559998046607, + 437.0536000060383, + 374.8059999779798, + 869.6661000140011, + 151.6811999899801, + 431.5096000209451, + 258.46380001166835, + 106.35400001774542, + 382.7330000058282, + 106.9609000114724, + 46.803199977148324, + 326.51099999202415, + 52.639400004409254, + 108.92790000070818, + 381.78339999285527, + 109.50960000627674, + 67.00179999461398, + 106.6378999967128, + 375.56829999084584, + 323.965199990198, + 173.64809999708086, + 324.5712999778334, + 53.623099985998124, + 323.34350000019185, + 367.6952999958303, + 109.92699998314492, + 54.16410000179894, + 538.1455000024289, + 279.6530000050552, + 106.7754999967292, + 164.15779999806546, + 107.20610001590103, + 169.57410000031814, + 106.03469997295178, + 277.19079999951646, + 111.10420001205057, + 54.99590002000332, + 107.77100000996143, + 271.4088000066113, + 871.121200005291, + 63.99480000254698, + 109.75269999471493, + 63.85119998594746, + 107.80530000920407, + 161.35559999383986, + 108.49320000852458, + 161.89449999365024, + 106.42229998484254 + ], + "hierarchy": [ + 50.26459999498911, + 109.1106999956537, + 271.0017999925185, + 109.17839998728596, + 262.58599999709986, + 650.4975999996532, + 146.37719999882393, + 327.8392999782227, + 57.53109999932349, + 328.0473000195343, + 269.3594000011217, + 328.48680001916364, + 707.0984999882057, + 1302.6483000139706, + 45.62580000492744, + 330.20440000109375, + 271.6000999789685, + 326.31190001848154, + 379.9581999774091, + 1195.2394999971148, + 161.05850000167266, + 449.62490000762045, + 270.31689998693764, + 449.05490000382997, + 152.98000001348555, + 322.588100010762, + 483.69360002106987, + 542.783499986399, + 369.3881000217516, + 108.12339998665266, + 276.10489999642596, + 323.7198000133503, + 52.696699975058436, + 109.29719998966902, + 267.73380002123304, + 109.5729999942705, + 166.59330000402406, + 105.71440000785515, + 48.77149997628294, + 326.49430001038127, + 382.93459999840707, + 107.09000000497326, + 56.64659998728894, + 108.36559999734163, + 378.2704000186641, + 106.21359999640845, + 278.1216000148561, + 325.0322999956552, + 392.92380001279525, + 107.24150002351962, + 156.76719998009503, + 107.28349999408238, + 265.5679000017699, + 112.07970001851209, + 380.36949999514036, + 323.34169998648576, + 1138.9557000075001, + 1093.0855000042357, + 49.35829999158159, + 108.73649999848567, + 379.45330000366084, + 324.04249999672174, + 265.04019999993034, + 106.39000000082888, + 166.0803999984637, + 109.55309998826124, + 378.9260999765247, + 649.7044999850914, + 248.00099999993108, + 107.48690000036731, + 372.2241999930702, + 109.1018000151962, + 492.05169998458587, + 1193.699800001923, + 58.659100002842024, + 331.50020000175573, + 270.3670000191778, + 328.31790001364425, + 50.01879998599179, + 107.97829998773523, + 273.0763999861665, + 108.96979999961331, + 380.0825000216719, + 654.2654999939259, + 157.72129999822937, + 107.55720001179725, + 274.3408000096679, + 216.09370000078343, + 385.3168000059668, + 537.2032000159379, + 52.93219999293797, + 110.05720001412556, + 58.168500021565706, + 436.8937000108417, + 1009.9586000142153, + 654.7008999914397, + 38.89840000192635, + 328.5396999854129, + 61.23490000027232, + 110.3706999856513 + ], + "eval": [ + 2339.5842000027187, + 4569.908800011035, + 1476.8792999966536, + 1519.1033000010066, + 2864.2985000042245, + 3047.111199994106, + 1683.7008999718819, + 2586.835699999938, + 2659.78589997394, + 2396.2425000208896, + 2995.506299979752, + 1525.5285000021104, + 3227.094900008524, + 1516.777099983301, + 2020.1173000095878, + 1731.1214999936055, + 2464.2919000179972, + 2160.475399985444, + 1488.6460999841802, + 1639.367299998412, + 1705.481899989536, + 2602.5162000150885, + 2112.8054999862798, + 1413.7207999883685, + 2234.1053999844007, + 1407.2282999986783, + 1920.039699994959, + 1628.7469000089914, + 1695.9859999769833, + 1627.3355000012089, + 1469.2592999781482, + 2819.4982999993954, + 1357.7188999915961, + 3256.913099990925, + 3542.0168999989983, + 1624.201600003289, + 2668.820199993206, + 1843.1704000104219, + 2996.5378000051714, + 1736.7984000011347, + 3553.7040999915916, + 1625.1032000000123, + 1373.6894000030588, + 2061.9820000138134, + 1592.7552999928594, + 1851.4304000127595, + 1492.5052000035066, + 3483.3035999909043, + 1260.4530999960843, + 2278.4625999920536, + 1267.0261999883223, + 2823.883500008378, + 1153.1535000249278, + 2823.89269999112, + 1687.7078000106849, + 2053.788099990925, + 1915.517200017348, + 2386.4805000193883, + 1472.3100000119302, + 1518.2515000051353, + 1700.7666999998037, + 1194.7454999899492, + 2894.102800026303, + 1635.5786999920383, + 1373.7651999981608, + 1414.3711000215262, + 1259.7027999872807, + 1634.8997000022791, + 2247.151899995515, + 1636.8799000047147, + 2894.4030000129715, + 1634.0859000047203, + 1575.139200023841, + 1413.0486999929417, + 1689.5557999960147, + 1740.3607000014745, + 1161.2214000197127, + 2076.0534000000916, + 1708.2287999801338, + 2710.64900001511, + 2039.9032999994233, + 1407.839099992998, + 2454.226200003177, + 2271.4825000148267, + 1365.3761000023223, + 2938.633000012487, + 1706.4500999986194, + 2387.900300003821, + 1374.623799987603, + 1960.1432000054047, + 2471.7923999996856, + 1632.8779000032227, + 1385.0200999877416, + 2059.381700004451, + 2134.0354999992996, + 1516.9847000215668, + 2781.4854999887757, + 1519.804400013527, + 1373.7229999969713, + 1191.391800006386 + ] + }, + "official": { + "create_gameobject": [ + 1692.9628000070807, + 607.91479999898, + 1141.0181999963243, + 596.7518000106793, + 926.2150000140537, + 1134.8158000037074, + 596.7947000171989, + 596.035100024892, + 807.0727000012994, + 597.3430999729317, + 813.3095999946818, + 597.0667999936268, + 932.9488000075798, + 1459.9370999785606, + 592.8506999916863, + 912.9013000056148, + 825.062899995828, + 920.4994999745395, + 905.9628999966662, + 598.6591000109911, + 806.9105000176933, + 804.8545999918133, + 591.0880999872461, + 592.5738999794703, + 809.1336000070442, + 600.3899999777786, + 832.4640999780968, + 586.9321000063792, + 609.3196000147145, + 595.2139000000898, + 1684.8775999969803, + 607.6966999971773, + 812.0400000188965, + 817.9273999994621, + 592.3167000000831, + 920.105400000466, + 596.0520000080578, + 587.9471999942325, + 811.6549999976996, + 596.1275000008754, + 698.5706000123173, + 815.9800999856088, + 817.6630999951158, + 598.8053000182845, + 593.50029999041, + 590.6177000142634, + 598.3680000063032, + 595.4998999950476, + 814.4608000002336, + 617.3426999885123, + 594.9384999985341, + 927.6695000007749, + 1691.1054000083823, + 591.1487999837846, + 602.5730000110343, + 603.9135000028182, + 599.5295000029728, + 816.0808999964502, + 603.949400014244, + 601.9237000145949, + 920.4767000046559, + 594.2809000262059, + 602.4394000123721, + 919.4945000053849, + 595.7070000004023, + 595.2001999830827, + 813.4987000084948, + 594.0910000063013, + 586.8322999740485, + 586.6260000038892, + 814.2831000150181, + 925.4302000044845, + 586.2817000015639, + 583.2201999728568, + 922.7895999792963, + 815.3183999820612, + 2013.6338000011165, + 581.0649000050034, + 924.2710999969859, + 923.1608000118285, + 590.269200009061, + 927.7079000021331, + 924.0717000211589, + 597.1237999910954, + 806.5069000003859, + 607.7913000190165, + 808.94580000313, + 592.0111000014003, + 596.323100005975, + 605.3160000010394, + 814.7871000110172, + 812.6983999973163, + 912.0663999929093, + 594.1832000098657, + 589.7402999980841, + 914.1923999995925, + 815.0052000128198, + 593.1709000142291, + 596.9922000076622, + 922.7933999791276 + ], + "hierarchy": [ + 628.257800010033, + 940.1053999899887, + 1057.5743000081275, + 594.4877000001725, + 653.7952999933623, + 1137.9101000202354, + 882.8850999998394, + 613.2660000002943, + 851.8154000048526, + 595.3104999789502, + 862.18260001624, + 913.5425999993458, + 762.9336999962106, + 586.4815999811981, + 883.6370999924839, + 611.025200021686, + 848.8696999847889, + 912.9889000032563, + 653.2727000012528, + 2115.616700000828, + 685.815700009698, + 608.068599976832, + 874.8232000216376, + 909.0695999911986, + 760.7724000117742, + 922.3499000072479, + 980.4536000010557, + 591.6617000184488, + 661.6693999967538, + 918.2953999843448, + 654.102900007274, + 807.4274999962654, + 1203.740500001004, + 608.6874000029638, + 636.6551999817602, + 600.6510999868624, + 644.3772000202443, + 817.6723000069614, + 979.86699998728, + 904.2066000110935, + 1750.249900011113, + 599.9688000010792, + 648.0336999811698, + 589.4606999936514, + 662.133800011361, + 811.5841000108048, + 646.9280000019353, + 1131.2644999998156, + 1192.7020000002813, + 590.2479000214953, + 661.5108999831136, + 917.1131999755744, + 657.4228999961633, + 817.2909999848343, + 641.9102999789175, + 935.9372000035364, + 1180.208199977642, + 578.4156000008807, + 669.708899979014, + 801.8150000134483, + 883.7103999976534, + 1134.4650000100955, + 870.5675999808591, + 596.9829999958165, + 646.5061999915633, + 932.8165999904741, + 748.7123000028078, + 1138.1800999806728, + 661.954200011678, + 598.480999993626, + 656.4611999783665, + 817.8262999863364, + 860.0339999829885, + 1145.6196999934036, + 647.0373999909498, + 593.7463000009302, + 865.344499994535, + 808.6051999998745, + 659.268899995368, + 599.5751000009477, + 644.9228000128642, + 799.860200000694, + 663.7532000022475, + 584.7528000012971, + 665.450200001942, + 916.1342000006698, + 754.4052999874111, + 812.1136000263505, + 862.4981000029948, + 1327.8749999881256, + 555.3261000022758, + 836.2561000103597, + 839.1202999919187, + 811.0423999896739, + 788.1098999932874, + 630.4722000204492, + 888.235699996585, + 602.4147999996785, + 638.2593000016641, + 811.0922999912873 + ], + "eval": [ + 663.7462000071537, + 590.5653999943752, + 559.6364999946672, + 803.1189999892376, + 1445.2729999902658, + 705.0703999993857, + 770.6877000164241, + 702.1824000112247, + 896.6027999995276, + 711.8371000105981, + 769.8750000272412, + 586.1918999871705, + 884.8713999905158, + 600.5400999856647, + 556.0431999911088, + 704.0178000170272, + 767.9735000128858, + 945.643499988364, + 1475.7234000135213, + 1354.0219999849796, + 555.2402999892365, + 920.9975999838207, + 783.4385000169277, + 704.422800015891, + 558.7172000086866, + 1310.3668999974616, + 712.0451999944635, + 1375.5561000143643, + 658.3643000049051, + 586.3456999941263, + 571.4160999923479, + 597.9102000128478, + 561.1664000025485, + 919.8132999881636, + 669.2735999822617, + 833.8019000075292, + 650.4381999839097, + 605.5811999831349, + 765.5293000279926, + 916.0731000010855, + 1004.6139000041876, + 926.5944000217132, + 883.6087000090629, + 1026.8939999805298, + 565.6873999978416, + 715.2320999884978, + 645.3178999945521, + 705.7334999844898, + 567.1363000001293, + 593.8037000014447, + 560.1671000185888, + 590.4756000090856, + 563.6312999995425, + 593.5501999920234, + 666.8066000274848, + 719.3939999851864, + 651.7794999817852, + 578.1452000082936, + 587.3210999998264, + 607.6965999964159, + 856.2536999816075, + 1140.2960999985225, + 773.8606999919284, + 600.5978000175674, + 664.0113999892492, + 708.3361000113655, + 556.5513999899849, + 1133.3578000194393, + 669.0946999879088, + 921.0164999822155, + 890.4925999813713, + 1139.2439000192098, + 581.3706000044476, + 1372.0850000099745, + 661.5189000149257, + 590.1499000028707, + 571.277100010775, + 612.2273000073619, + 643.242599995574, + 592.188000009628, + 550.8354000048712, + 588.0965999967884, + 895.3768000064883, + 1157.5292000197805, + 647.8508999862242, + 702.0497000194155, + 775.2321999869309, + 608.0096999939997, + 652.281699993182, + 819.7941000107676, + 667.3832999949809, + 1151.0103999753483, + 655.0244000100065, + 802.7354000078049, + 566.9175999937579, + 596.5594000008423, + 668.505700014066, + 610.5440999963321, + 1194.983900000807, + 607.7109000179917 + ] + } + }, + "details": { + "discarded_focus_pairs": { + "create_gameobject": 0, + "hierarchy": 0, + "eval": 0 + } + }, + "results": { + "unity-cli": { + "create_gameobject": { + "n": 100, + "p50_ms": 161.36, + "p95_ms": 713.62, + "mean_ms": 244.51, + "min_ms": 46.25, + "max_ms": 1298.71 + }, + "hierarchy": { + "n": 100, + "p50_ms": 270.32, + "p95_ms": 1009.96, + "mean_ms": 305.49, + "min_ms": 38.9, + "max_ms": 1302.65 + }, + "eval": { + "n": 100, + "p50_ms": 1708.23, + "p95_ms": 3227.09, + "mean_ms": 2008.18, + "min_ms": 1153.15, + "max_ms": 4569.91 + } + }, + "official": { + "create_gameobject": { + "n": 100, + "p50_ms": 607.91, + "p95_ms": 1141.02, + "mean_ms": 770.05, + "min_ms": 581.06, + "max_ms": 2013.63 + }, + "hierarchy": { + "n": 100, + "p50_ms": 788.11, + "p95_ms": 1180.21, + "mean_ms": 806.58, + "min_ms": 555.33, + "max_ms": 2115.62 + }, + "eval": { + "n": 100, + "p50_ms": 668.51, + "p95_ms": 1310.37, + "mean_ms": 760.99, + "min_ms": 550.84, + "max_ms": 1475.72 + } + } + }, + "finished_at": "2026-10-03T23:42:59.192326+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/official-windows-process-frontmost.json b/docs/verification/issue-386/resume/official-windows-process-frontmost.json new file mode 100644 index 00000000..f8a39dc3 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-process-frontmost.json @@ -0,0 +1,724 @@ +{ + "mode": "process", + "focus": "frontmost", + "started_at": "2026-10-03T23:20:37.824904+00:00", + "conditions": { + "started_at": "2026-10-03T23:20:30.496681+00:00", + "os": "Windows-11-10.0.26300-SP0", + "arch": "AMD64", + "logical_cpus": 32, + "unity": "6000.4.4f1", + "editor_pid": 34324, + "iterations": 100, + "warmup": 3, + "unity_cli_build": "native Windows debug 0.18.1", + "official_cli_version": "1.0.0-beta.11", + "pipeline_version": "0.8.0-exp.1", + "unity_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", + "official_cli_sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", + "benchmark_sha256": "857569c8c542221f43a27423ecfa8fce3d11a690ed979985ebc670a56912f372", + "windows_adapter_sha256": "dbe8d15ea394b39cea39f92764a45fbedaeae0b7fa8219061d0c2b281946a99c", + "windows_adapter": "Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.", + "host_contention": "Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.", + "coexistence": { + "same_project": true, + "unity_version": "6000.4.4f1", + "official_state": "ready", + "project_identity_sha256": "f87f40b8af586b040ebc3f0d64bf076a0bebf421cd38cb9af459bc31f2a0c69a" + }, + "play_settings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeOptionsEnabled": true, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "unityd_pid": 52020 + }, + "status": "PASS", + "samples_ms": { + "unity-cli": { + "create_gameobject": [ + 379.23620000947267, + 37.30220001307316, + 335.3181999991648, + 882.032599998638, + 43.45240001566708, + 44.612100027734414, + 119.85630000708625, + 46.17310001049191, + 477.07680001622066, + 40.632099990034476, + 193.04980000015348, + 62.874099996406585, + 251.00659998133779, + 1155.2138000261039, + 39.59599998779595, + 341.106400010176, + 47.12979999021627, + 42.41690001799725, + 181.321600015508, + 41.80400000768714, + 284.74149998510256, + 40.00030001043342, + 49.26150001119822, + 39.183200016850606, + 780.3609000111464, + 48.15170000074431, + 46.72099999152124, + 335.5914000130724, + 40.955200005555525, + 321.9041000120342, + 655.4335999826435, + 40.12510000029579, + 242.90069998824038, + 40.53659999044612, + 696.1764000006951, + 53.91079999390058, + 304.8699999926612, + 45.51309999078512, + 226.86130000511184, + 596.4386999839917, + 38.439399999333546, + 41.08940000878647, + 49.95689998031594, + 40.89929998735897, + 164.59599998779595, + 47.68290001084097, + 206.7834000044968, + 306.14780000178143, + 45.76819998328574, + 324.079600017285, + 454.7598999924958, + 41.45720001542941, + 466.12610001466237, + 854.4175999995787, + 36.36860000551678, + 339.08119998523034, + 38.971400004811585, + 52.21159997745417, + 772.0032000215724, + 39.19340000720695, + 307.40369998966344, + 310.92819999321364, + 37.96320001129061, + 40.92449997551739, + 259.25559998722747, + 924.9335000058636, + 41.59189999336377, + 322.91820002137683, + 73.3089999994263, + 43.23459998704493, + 217.73919998668134, + 567.6209000230301, + 37.50490001402795, + 344.2325000069104, + 157.09059999790043, + 37.61990001657978, + 162.66659999382682, + 290.41180000058375, + 185.68559997947887, + 312.15769998379983, + 35.77200000290759, + 43.68169998633675, + 90.67809997941367, + 42.41959998034872, + 312.2000999865122, + 594.0995999844745, + 300.993600016227, + 295.7701999985147, + 38.33480001776479, + 320.61399999656714, + 657.2042999905534, + 41.391000006115064, + 152.55790000082925, + 37.30120000545867, + 245.4913999827113, + 292.1578000241425, + 322.10039999336004, + 38.996599992970005, + 88.3077000034973, + 39.900400006445125 + ], + "hierarchy": [ + 35.91460001189262, + 46.82280000997707, + 292.7416999882553, + 36.95459998562001, + 80.3691000037361, + 34.123599994927645, + 241.17589998058975, + 36.039099999470636, + 35.7273000117857, + 35.09639998083003, + 259.5468999934383, + 39.4316999881994, + 383.55569998384453, + 40.131600020686164, + 38.082600018242374, + 38.202499999897555, + 140.82349999807775, + 316.81509999907576, + 658.1195000035223, + 40.71450000628829, + 267.08300001337193, + 38.2147999771405, + 375.2803999814205, + 873.3879999781493, + 308.37850001989864, + 41.16180000710301, + 677.9377000057139, + 604.5374000095762, + 944.425699999556, + 1349.0058000024874, + 45.71770000620745, + 40.753600012976676, + 433.2070000236854, + 1433.735800004797, + 58.318299998063594, + 35.479400015901774, + 82.23610001732595, + 36.680699995486066, + 146.22359999339096, + 35.92319999006577, + 146.84299999498762, + 43.738200009102, + 182.11900000460446, + 554.9292000068817, + 36.86230001039803, + 35.96760000800714, + 188.1160000048112, + 1126.1574999953154, + 36.91900000558235, + 33.44689999357797, + 187.06879997625947, + 320.30700001632795, + 619.1199000168126, + 549.8272999830078, + 38.657299999613315, + 36.97319998173043, + 264.25899998866953, + 300.6753000081517, + 247.43370001669973, + 37.76619999553077, + 41.150899982312694, + 39.282499987166375, + 39.28119997726753, + 36.48260000045411, + 100.0726000056602, + 315.3327999752946, + 36.09750000759959, + 36.20470000896603, + 269.0707999863662, + 36.95259999949485, + 256.4090999949258, + 308.8982999906875, + 37.397800013422966, + 37.53520001191646, + 37.593299988657236, + 39.553900016471744, + 37.36260000732727, + 37.19969998928718, + 37.394999992102385, + 36.273299978347495, + 261.4248000027146, + 36.116500006755814, + 36.45039998809807, + 36.28709999611601, + 282.69409999484196, + 38.638199999695644, + 671.4688999927603, + 39.14710000390187, + 165.4227999970317, + 36.0538000240922, + 118.26560000190511, + 294.553999992786, + 86.02170000085607, + 36.87150002224371, + 35.68099997937679, + 315.6048000091687, + 663.403799990192, + 37.68599999602884, + 36.411300010513514, + 37.10190000128932 + ], + "eval": [ + 1122.2228000115138, + 2184.8367999773473, + 1465.3466999880038, + 3199.8299000260886, + 1283.9716000016779, + 2758.778200019151, + 1332.5039999908768, + 2451.4867999823764, + 1481.917600001907, + 2240.3870999987703, + 1869.3315999989863, + 1335.664899990661, + 2084.36380000785, + 1195.9346000221558, + 4447.494099993492, + 1690.1799999759533, + 2740.0732999958564, + 1484.3457999813836, + 1044.3052999908105, + 1349.8792000173125, + 2596.7012999753933, + 1334.2152000113856, + 1453.9805999957025, + 2240.8099000167567, + 1236.6826000215951, + 3058.8268999999855, + 2382.3672000144143, + 2617.990300001111, + 2798.078199994052, + 2361.4052000048105, + 1702.6805999921635, + 1595.0356999819633, + 2431.8580999970436, + 1819.6503999934066, + 3780.548600014299, + 2939.343700010795, + 1330.7397000025958, + 2531.5621999907307, + 2186.5448000025935, + 1224.6409000072163, + 2775.6010000011884, + 1427.3137999989558, + 1655.0097000144888, + 2386.183099995833, + 1509.4224999775179, + 1537.9924000008032, + 1948.7420999794267, + 2618.6880999885034, + 1465.4988000111189, + 2778.2095999864396, + 2688.282600021921, + 1638.9205000014044, + 2430.2959000051487, + 1900.2047999820206, + 1841.9775000074878, + 3523.7804999924265, + 2766.7572000063956, + 1517.3430000140797, + 2501.9542000081856, + 1417.5220000033733, + 2784.905100008473, + 2166.4723999856506, + 1617.452400008915, + 1307.3021000018343, + 1611.870499997167, + 1475.8675999764819, + 1263.3239999995567, + 3636.337800009642, + 1281.7352999991272, + 2034.6357999951579, + 1568.691199994646, + 1212.3496999847703, + 2449.4135999993887, + 1410.7231000089087, + 2064.1815999988467, + 2032.3689999931958, + 2764.947200019378, + 1749.753200012492, + 2212.8204999899026, + 1284.6533000119962, + 1444.8642999923322, + 2228.0969999847002, + 1871.8006999988575, + 2242.743700015126, + 1291.015700000571, + 1271.8228999874555, + 1699.9154999793973, + 1531.1534999927972, + 1520.1436000061221, + 1175.5138000007719, + 1318.5999999986961, + 1372.12390001514, + 1438.1820000126027, + 3522.4537999893073, + 1503.9091000217013, + 1806.5246999904048, + 3674.8812000150792, + 1873.7338000210002, + 1485.005899972748, + 1335.8233000035398 + ] + }, + "official": { + "create_gameobject": [ + 836.8951999873389, + 552.3287999967579, + 837.0877999986988, + 1400.4030999785755, + 571.9647000078112, + 841.7656000237912, + 824.8915000003763, + 572.2386999987066, + 539.7041999967769, + 561.3454999984242, + 537.6740999927279, + 555.9048000141047, + 550.6917999882717, + 543.282900005579, + 533.4060000022873, + 850.2990000124555, + 558.1093000073452, + 869.3073999893386, + 837.1387999795843, + 556.1094000004232, + 552.4989999830723, + 554.1457000072114, + 551.212000020314, + 536.4024000009522, + 811.7838999896776, + 559.122299979208, + 551.1394999921322, + 823.489200003678, + 548.9821000082884, + 566.9062999950256, + 841.8235999997705, + 574.5290000049863, + 549.0537000005133, + 835.4294000018854, + 1755.6846000079531, + 582.0211000100244, + 801.0702999890782, + 541.0677999898326, + 555.3280999884009, + 1928.0552999989595, + 548.4133999852929, + 801.7754000029527, + 555.5991999863181, + 537.9204000055324, + 798.4765000001062, + 556.074299995089, + 859.1498000023421, + 1385.6996999820694, + 598.7552999868058, + 564.0027000044938, + 847.1705999982078, + 554.4733999995515, + 816.8571999995038, + 555.1908000197727, + 806.4855000120588, + 1420.810799987521, + 558.8617000030354, + 824.25519998651, + 835.7659000030253, + 553.0859999998938, + 821.3891000195872, + 814.9581000034232, + 559.5436999865342, + 539.7870000160765, + 633.4399999759626, + 1410.4073000198696, + 536.7832999909297, + 544.8117000050843, + 547.1652999985963, + 853.8895000237972, + 550.6004999915604, + 1606.1584999843035, + 830.6690999888815, + 550.6563999806531, + 1373.1058000121266, + 542.3157000041101, + 549.7940999921411, + 1374.5527999999467, + 579.1980000212789, + 812.7319999912288, + 543.7557999975979, + 846.5046000201255, + 1124.6145000040997, + 548.5615000070538, + 1240.6709999777377, + 1085.980700008804, + 535.2843999862671, + 548.5031999996863, + 549.704400007613, + 549.726199998986, + 814.5881000091322, + 566.8900000164285, + 557.2279999905732, + 561.8774000031408, + 813.0667000077665, + 1032.941999990726, + 544.0036999934819, + 820.9096000064164, + 1380.4475000069942, + 553.1272999942303 + ], + "hierarchy": [ + 616.3446000136901, + 549.2249999952037, + 539.2072000249755, + 803.4602999978233, + 645.9189000015613, + 813.637999992352, + 592.8158999886364, + 557.9418999841437, + 534.359699988272, + 538.6368999897968, + 561.0653999901842, + 546.9243999978062, + 647.0127999782562, + 544.7272000019439, + 650.0313000287861, + 542.985400010366, + 552.3729999840725, + 815.803200006485, + 1426.5312000061385, + 604.1093000094406, + 849.5179000019561, + 837.1186000003945, + 684.860999986995, + 576.269199984381, + 553.750899998704, + 826.0745999868959, + 719.1768000193406, + 815.6349999771919, + 887.2531999950297, + 552.3322999943048, + 695.4934000095818, + 532.5211999879684, + 803.5999999847263, + 1074.8677000228781, + 558.1949999905191, + 823.4121999994386, + 952.8983999916818, + 555.181600007927, + 537.8537999931723, + 551.6974999918602, + 607.1682999900077, + 556.682099995669, + 802.9559999995399, + 1360.6298999802675, + 551.541199994972, + 545.5173999944236, + 771.6000000073109, + 1084.4878999923822, + 738.5234999819659, + 561.5104000025894, + 772.8671999939252, + 804.5443000155501, + 906.0814999975264, + 1109.0810999739915, + 523.7291000084952, + 544.0490999899339, + 813.1792999920435, + 1082.5282000005245, + 1652.0352000079583, + 547.4735000170767, + 542.4660000135191, + 544.3130000203382, + 620.8670999913011, + 810.3768000146374, + 809.3845999974292, + 798.1396999966819, + 840.8345999778248, + 550.7075999921653, + 557.234799984144, + 553.5084000148345, + 554.8393999924883, + 823.5937999852467, + 1288.4242000000086, + 559.2820000019856, + 548.7732000183314, + 833.1147000135388, + 995.9725000080653, + 549.4322000013199, + 546.4693999965675, + 541.5608000184875, + 809.7404000000097, + 787.1995999885257, + 1144.8302999779116, + 547.3175999941304, + 838.9052999846172, + 833.1672000058461, + 742.3469999921508, + 541.562200000044, + 720.5833999905735, + 538.4854000003543, + 732.0183000119869, + 1063.097000005655, + 578.3069000171963, + 545.0112000107765, + 530.7324999885168, + 531.1866000120062, + 919.9921000108588, + 541.1679999961052, + 615.2790999913123, + 557.1909999998752 + ], + "eval": [ + 565.0669999886304, + 597.505599987926, + 577.5711000023875, + 563.0882999976166, + 564.7161000233609, + 837.112100009108, + 693.5228999936953, + 586.3650999963284, + 841.7087999987416, + 703.9086000004318, + 573.1265000067651, + 736.3982000097167, + 791.0812000045553, + 750.2384999825153, + 614.4908000133, + 579.6021000132896, + 924.4792999816127, + 565.2177000010852, + 643.8489000138361, + 785.3359000000637, + 675.6101000064518, + 602.0863000012469, + 1271.797699999297, + 593.0282999761403, + 585.741799994139, + 635.1495999842882, + 754.5419000089169, + 836.9341999932658, + 822.8387999988627, + 1111.6669999901205, + 1857.4872000026517, + 887.4290000239853, + 653.2504000060726, + 579.2431000154465, + 1000.8786999969743, + 1046.1273999826517, + 605.2696999977343, + 705.4572999768425, + 822.3813999793492, + 578.8104999810457, + 840.723999979673, + 820.0598999974318, + 936.073100019712, + 1368.6808999918867, + 584.868700010702, + 1417.5548999919556, + 587.5485999858938, + 741.7023000016343, + 600.949399988167, + 768.2687999913469, + 859.1997000039555, + 854.229899996426, + 696.2045000109356, + 895.1268999953754, + 1584.0171000163537, + 744.9928999994881, + 549.8604000022169, + 733.0984000000171, + 573.3010999974795, + 618.986399989808, + 978.1365999951959, + 1374.5965999842156, + 1187.5701999815647, + 598.1797999993432, + 1011.0834999941289, + 1083.71609999449, + 722.6399000210222, + 872.9446000070311, + 559.9683999898843, + 664.1824999824166, + 771.752300002845, + 558.3886000094935, + 958.1169000011869, + 572.7062999794725, + 898.2803000253625, + 763.5088999813888, + 575.7658999937121, + 577.8483999893069, + 991.2758999853395, + 1401.742899994133, + 561.7801999906078, + 1907.7893999929074, + 554.6922999783419, + 1371.8016000057105, + 563.3891000179574, + 553.3252999885008, + 1005.0155000062659, + 830.1905999833252, + 929.3857000011485, + 1032.1992999815848, + 552.6748000120278, + 1365.6160999962594, + 754.2814999760594, + 542.9434000106994, + 568.88269999763, + 866.9413000170607, + 623.1765999982599, + 595.4669000057038, + 1834.5123000035528, + 563.4424999880139 + ] + } + }, + "details": { + "discarded_focus_pairs": { + "create_gameobject": 0, + "hierarchy": 0, + "eval": 0 + } + }, + "results": { + "unity-cli": { + "create_gameobject": { + "n": 100, + "p50_ms": 152.56, + "p95_ms": 772.0, + "mean_ms": 226.76, + "min_ms": 35.77, + "max_ms": 1155.21 + }, + "hierarchy": { + "n": 100, + "p50_ms": 41.16, + "p95_ms": 677.94, + "mean_ms": 207.26, + "min_ms": 33.45, + "max_ms": 1433.74 + }, + "eval": { + "n": 100, + "p50_ms": 1749.75, + "p95_ms": 3522.45, + "mean_ms": 1982.54, + "min_ms": 1044.31, + "max_ms": 4447.49 + } + }, + "official": { + "create_gameobject": { + "n": 100, + "p50_ms": 566.91, + "p95_ms": 1400.4, + "mean_ms": 751.79, + "min_ms": 533.41, + "max_ms": 1928.06 + }, + "hierarchy": { + "n": 100, + "p50_ms": 616.34, + "p95_ms": 1109.08, + "mean_ms": 717.94, + "min_ms": 523.73, + "max_ms": 1652.04 + }, + "eval": { + "n": 100, + "p50_ms": 736.4, + "p95_ms": 1401.74, + "mean_ms": 815.95, + "min_ms": 542.94, + "max_ms": 1907.79 + } + } + }, + "finished_at": "2026-10-03T23:29:28.578618+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/official-windows-resident-frontmost-search-array-failure.json b/docs/verification/issue-386/resume/official-windows-resident-frontmost-search-array-failure.json new file mode 100644 index 00000000..5a8202b3 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-resident-frontmost-search-array-failure.json @@ -0,0 +1,47 @@ +{ + "mode": "resident", + "focus": "frontmost", + "started_at": "2026-10-03T23:42:59.193309+00:00", + "conditions": { + "started_at": "2026-10-03T23:33:26.503448+00:00", + "os": "Windows-11-10.0.26300-SP0", + "arch": "AMD64", + "logical_cpus": 32, + "unity": "6000.4.4f1", + "editor_pid": 34324, + "iterations": 100, + "warmup": 3, + "unity_cli_build": "native Windows debug 0.18.1", + "official_cli_version": "1.0.0-beta.11", + "pipeline_version": "0.8.0-exp.1", + "unity_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", + "official_cli_sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", + "benchmark_sha256": "857569c8c542221f43a27423ecfa8fce3d11a690ed979985ebc670a56912f372", + "windows_adapter_sha256": "1d72ca848808f1fcce45a46b133691c7c6119f908e67e9519f72759a19d5af7b", + "windows_adapter": "Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.", + "background_condition": "Owned Editor minimized, because Windows refused activation of the existing GWT background window. This differs from macOS visible-background measurements.", + "host_contention": "Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.", + "coexistence": { + "same_project": true, + "unity_version": "6000.4.4f1", + "official_state": "ready", + "project_identity_sha256": "f87f40b8af586b040ebc3f0d64bf076a0bebf421cd38cb9af459bc31f2a0c69a" + }, + "play_settings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeOptionsEnabled": true, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "unityd_pid": 52020 + }, + "status": "FAIL", + "error": "Invalid official NDJSON response: {'id': '15', 'exitCode': 6, 'envelope': {'success': False, 'command': 'unity command find_assets', 'data': None, 'errors': [{'code': 'COMMAND_FAILED', 'message': 'Pipeline server returned 400 Bad Request: Parameter Validation Failed. Illegal characters in path.'}], 'warnings': []}}", + "finished_at": "2026-10-03T23:43:15.759312+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/official-windows-resident-frontmost.json b/docs/verification/issue-386/resume/official-windows-resident-frontmost.json new file mode 100644 index 00000000..5a8202b3 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-resident-frontmost.json @@ -0,0 +1,47 @@ +{ + "mode": "resident", + "focus": "frontmost", + "started_at": "2026-10-03T23:42:59.193309+00:00", + "conditions": { + "started_at": "2026-10-03T23:33:26.503448+00:00", + "os": "Windows-11-10.0.26300-SP0", + "arch": "AMD64", + "logical_cpus": 32, + "unity": "6000.4.4f1", + "editor_pid": 34324, + "iterations": 100, + "warmup": 3, + "unity_cli_build": "native Windows debug 0.18.1", + "official_cli_version": "1.0.0-beta.11", + "pipeline_version": "0.8.0-exp.1", + "unity_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", + "official_cli_sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", + "benchmark_sha256": "857569c8c542221f43a27423ecfa8fce3d11a690ed979985ebc670a56912f372", + "windows_adapter_sha256": "1d72ca848808f1fcce45a46b133691c7c6119f908e67e9519f72759a19d5af7b", + "windows_adapter": "Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.", + "background_condition": "Owned Editor minimized, because Windows refused activation of the existing GWT background window. This differs from macOS visible-background measurements.", + "host_contention": "Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.", + "coexistence": { + "same_project": true, + "unity_version": "6000.4.4f1", + "official_state": "ready", + "project_identity_sha256": "f87f40b8af586b040ebc3f0d64bf076a0bebf421cd38cb9af459bc31f2a0c69a" + }, + "play_settings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeOptionsEnabled": true, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "unityd_pid": 52020 + }, + "status": "FAIL", + "error": "Invalid official NDJSON response: {'id': '15', 'exitCode': 6, 'envelope': {'success': False, 'command': 'unity command find_assets', 'data': None, 'errors': [{'code': 'COMMAND_FAILED', 'message': 'Pipeline server returned 400 Bad Request: Parameter Validation Failed. Illegal characters in path.'}], 'warnings': []}}", + "finished_at": "2026-10-03T23:43:15.759312+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/official-windows-summary.json b/docs/verification/issue-386/resume/official-windows-summary.json new file mode 100644 index 00000000..c03472da --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-summary.json @@ -0,0 +1,61 @@ +{ + "conditions": { + "started_at": "2026-10-03T23:33:26.503448+00:00", + "os": "Windows-11-10.0.26300-SP0", + "arch": "AMD64", + "logical_cpus": 32, + "unity": "6000.4.4f1", + "editor_pid": 34324, + "iterations": 100, + "warmup": 3, + "unity_cli_build": "native Windows debug 0.18.1", + "official_cli_version": "1.0.0-beta.11", + "pipeline_version": "0.8.0-exp.1", + "unity_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", + "official_cli_sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", + "benchmark_sha256": "857569c8c542221f43a27423ecfa8fce3d11a690ed979985ebc670a56912f372", + "windows_adapter_sha256": "1d72ca848808f1fcce45a46b133691c7c6119f908e67e9519f72759a19d5af7b", + "windows_adapter": "Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.", + "background_condition": "Owned Editor minimized, because Windows refused activation of the existing GWT background window. This differs from macOS visible-background measurements.", + "host_contention": "Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.", + "coexistence": { + "same_project": true, + "unity_version": "6000.4.4f1", + "official_state": "ready", + "project_identity_sha256": "f87f40b8af586b040ebc3f0d64bf076a0bebf421cd38cb9af459bc31f2a0c69a" + }, + "play_settings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeOptionsEnabled": true, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "unityd_pid": 52020 + }, + "runs": [ + { + "mode": "process", + "focus": "frontmost", + "status": "PASS", + "source": "previous completed run, original conditions preserved" + }, + { + "mode": "process", + "focus": "background", + "status": "PASS", + "error": null + }, + { + "mode": "resident", + "focus": "frontmost", + "status": "FAIL", + "error": "Invalid official NDJSON response: {'id': '15', 'exitCode': 6, 'envelope': {'success': False, 'command': 'unity command find_assets', 'data': None, 'errors': [{'code': 'COMMAND_FAILED', 'message': 'Pipeline server returned 400 Bad Request: Parameter Validation Failed. Illegal characters in path.'}], 'warnings': []}}" + } + ] +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/prefab-results.json b/docs/verification/issue-386/resume/prefab-results.json new file mode 100644 index 00000000..d1e32549 --- /dev/null +++ b/docs/verification/issue-386/resume/prefab-results.json @@ -0,0 +1,17 @@ +{ + "started_at": "2026-10-03T21:05:33.051246+00:00", + "editors": [ + { + "version": "6000.4.4f1", + "status": "PASS", + "passed": 45, + "failed": 0, + "artifacts": "\\.cache\\issue-386\\resume\\prefab-final\\existing", + "editmode": { + "passed": 22, + "failed": 0, + "runId": "2dcd238f-7de3-4150-96d2-619a59fd3afb" + } + } + ] +} diff --git a/docs/verification/issue-386/resume/prefab.txt b/docs/verification/issue-386/resume/prefab.txt new file mode 100644 index 00000000..a23600d9 --- /dev/null +++ b/docs/verification/issue-386/resume/prefab.txt @@ -0,0 +1,65 @@ +Evidence: \.cache\issue-386\resume\prefab-final +Unity 6000.4.4f1 +PASS existing create_prefab creates inherited Variant: expected 'Variant', got 'Variant' +PASS Variant and base are explicit apply targets +PASS Variant apply leaves base unchanged: expected 1, got 1.0 +PASS base edit propagates to Variant: expected 7, got 7.0 +PASS Variant override survives base edit: expected 3, got 3.0 +PASS individual property applies to base through Variant: expected 2.5, got 2.5 +PASS individual property reverts: expected 7, got 7.0 +PASS revert preserves unrelated override: expected 4, got 4.0 +PASS object override reverts: expected 2.5, got 2.5 +PASS object override applies to Variant: expected 5, got 5.0 +PASS structured property override +PASS structured added and removed components +PASS revert added component: expected False, got False +PASS revert removed component: expected True, got True +PASS structured property override +PASS structured added and removed components +PASS apply added component: expected True, got True +PASS apply removed component: expected False, got False +PASS component apply to Variant leaves base intact: expected True, got True +PASS manage_prefab_overrides rejects INVALID_APPLY_TARGET +PASS ineligible base apply fails before other overrides change: expected False, got False +PASS existing create_prefab creates inherited Variant: expected 'Variant', got 'Variant' +PASS all properties applied to Variant: expected 11, got 11.0 +PASS all addition applied to Variant: expected True, got True +PASS all removal applied to Variant: expected True, got True +PASS all property overrides reverted: expected 11, got 11.0 +PASS all removed components restored: expected True, got True +PASS all added components reverted: expected True, got True +PASS existing create_prefab creates inherited Variant: expected 'Variant', got 'Variant' +PASS all properties applied to Base: expected 11, got 11.0 +PASS all addition applied to Base: expected True, got True +PASS all removal applied to Base: expected True, got True +PASS all property overrides reverted: expected 11, got 11.0 +PASS all removed components restored: expected True, got True +PASS all added components reverted: expected True, got True +PASS Variant override persists after reload: expected 3, got 3.0 +PASS base apply persists after reload: expected 11, got 11.0 +PASS Outermost disconnects outer root +PASS Outermost reports nested connections accurately +PASS Outermost nested connection verified independently: expected True, got True +PASS Completely disconnects outer root +PASS Completely reports nested connections accurately +PASS Completely nested connection verified independently: expected False, got False +PASS unpack_prefab rejects NOT_PREFAB_INSTANCE_ROOT +PASS inactive Prefab root can be inspected +PASS focused EditMode: 22 passed, 0 failed +{ + "started_at": "2026-10-03T21:05:33.051246+00:00", + "editors": [ + { + "version": "6000.4.4f1", + "status": "PASS", + "passed": 45, + "failed": 0, + "artifacts": "\\.cache\\issue-386\\resume\\prefab-final\\existing", + "editmode": { + "passed": 22, + "failed": 0, + "runId": "2dcd238f-7de3-4150-96d2-619a59fd3afb" + } + } + ] +} diff --git a/docs/verification/issue-386/resume/process-liveness-final.txt b/docs/verification/issue-386/resume/process-liveness-final.txt new file mode 100644 index 00000000..a949810d --- /dev/null +++ b/docs/verification/issue-386/resume/process-liveness-final.txt @@ -0,0 +1,9 @@ +test_exit_code_still_active_does_not_mean_process_is_running (test_process_liveness.ProcessLivenessTests.test_exit_code_still_active_does_not_mean_process_is_running) ... ok +test_exited_process_is_not_alive_or_eligible_for_authentication (test_process_liveness.ProcessLivenessTests.test_exited_process_is_not_alive_or_eligible_for_authentication) ... ok +test_invalid_process_ids_are_not_alive_or_eligible_for_authentication (test_process_liveness.ProcessLivenessTests.test_invalid_process_ids_are_not_alive_or_eligible_for_authentication) ... ok +test_live_process_survives_authentication_and_lifecycle_probes (test_process_liveness.ProcessLivenessTests.test_live_process_survives_authentication_and_lifecycle_probes) ... ok + +---------------------------------------------------------------------- +Ran 4 tests in 0.782s + +OK diff --git a/docs/verification/issue-386/resume/python-linux.txt b/docs/verification/issue-386/resume/python-linux.txt new file mode 100644 index 00000000..1e17cc78 --- /dev/null +++ b/docs/verification/issue-386/resume/python-linux.txt @@ -0,0 +1,9 @@ +test_exit_code_still_active_does_not_mean_process_is_running (test_process_liveness.ProcessLivenessTests.test_exit_code_still_active_does_not_mean_process_is_running) ... skipped 'Windows process exit code contract' +test_exited_process_is_not_alive_or_eligible_for_authentication (test_process_liveness.ProcessLivenessTests.test_exited_process_is_not_alive_or_eligible_for_authentication) ... ok +test_invalid_process_ids_are_not_alive_or_eligible_for_authentication (test_process_liveness.ProcessLivenessTests.test_invalid_process_ids_are_not_alive_or_eligible_for_authentication) ... ok +test_live_process_survives_authentication_and_lifecycle_probes (test_process_liveness.ProcessLivenessTests.test_live_process_survives_authentication_and_lifecycle_probes) ... ok + +---------------------------------------------------------------------- +Ran 4 tests in 0.486s + +OK (skipped=1) diff --git a/docs/verification/issue-386/resume/python-windows.txt b/docs/verification/issue-386/resume/python-windows.txt new file mode 100644 index 00000000..e6967764 --- /dev/null +++ b/docs/verification/issue-386/resume/python-windows.txt @@ -0,0 +1,9 @@ +test_exit_code_still_active_does_not_mean_process_is_running (test_process_liveness.ProcessLivenessTests.test_exit_code_still_active_does_not_mean_process_is_running) ... ok +test_exited_process_is_not_alive_or_eligible_for_authentication (test_process_liveness.ProcessLivenessTests.test_exited_process_is_not_alive_or_eligible_for_authentication) ... ok +test_invalid_process_ids_are_not_alive_or_eligible_for_authentication (test_process_liveness.ProcessLivenessTests.test_invalid_process_ids_are_not_alive_or_eligible_for_authentication) ... ok +test_live_process_survives_authentication_and_lifecycle_probes (test_process_liveness.ProcessLivenessTests.test_live_process_survives_authentication_and_lifecycle_probes) ... ok + +---------------------------------------------------------------------- +Ran 4 tests in 1.493s + +OK diff --git a/docs/verification/issue-386/resume/reference-auth-green.txt b/docs/verification/issue-386/resume/reference-auth-green.txt new file mode 100644 index 00000000..46308604 --- /dev/null +++ b/docs/verification/issue-386/resume/reference-auth-green.txt @@ -0,0 +1,9 @@ + Compiling base64 v0.22.1 + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 20.56s + Running unittests src\main.rs (target\debug\deps\unity_cli-6f9d4071c936636c.exe) + +running 1 test +test reference::fetcher::tests::public_refs_use_basic_authentication_for_git_http ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 555 filtered out; finished in 0.14s diff --git a/docs/verification/issue-386/resume/reference-auth-probe.json b/docs/verification/issue-386/resume/reference-auth-probe.json new file mode 100644 index 00000000..0b355727 --- /dev/null +++ b/docs/verification/issue-386/resume/reference-auth-probe.json @@ -0,0 +1,27 @@ +[ + { + "mode": "anonymous", + "exit_code": 0, + "found_branch": true + }, + { + "mode": "current-token", + "exit_code": 128, + "found_branch": false + }, + { + "mode": "current-basic", + "exit_code": 0, + "found_branch": true + }, + { + "mode": "gh-token", + "exit_code": 128, + "found_branch": false + }, + { + "mode": "gh-basic", + "exit_code": 0, + "found_branch": true + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/reference-auth-red.txt b/docs/verification/issue-386/resume/reference-auth-red.txt new file mode 100644 index 00000000..d7139392 --- /dev/null +++ b/docs/verification/issue-386/resume/reference-auth-red.txt @@ -0,0 +1,21 @@ + Finished `test` profile [unoptimized + debuginfo] target(s) in 0.47s + Running unittests src\main.rs (target\debug\deps\unity_cli-66a997df271e997b.exe) + +running 1 test +test reference::fetcher::tests::public_refs_use_basic_authentication_for_git_http ... FAILED + +failures: + +---- reference::fetcher::tests::public_refs_use_basic_authentication_for_git_http stdout ---- + +thread 'reference::fetcher::tests::public_refs_use_basic_authentication_for_git_http' (47892) panicked at src\reference\fetcher.rs:630:9: +Git HTTP must authenticate with username and token credentials +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + +failures: + reference::fetcher::tests::public_refs_use_basic_authentication_for_git_http + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 555 filtered out; finished in 0.43s + +error: test failed, to rerun pass `--bin unity-cli` diff --git a/docs/verification/issue-386/resume/reference-fetch-summary.json b/docs/verification/issue-386/resume/reference-fetch-summary.json new file mode 100644 index 00000000..ebd9e979 --- /dev/null +++ b/docs/verification/issue-386/resume/reference-fetch-summary.json @@ -0,0 +1,26 @@ +{ + "passed": 5, + "failed": 0, + "results": [ + { + "name": "live Editor readiness", + "passed": true + }, + { + "name": "branch-only real fetch", + "passed": true + }, + { + "name": "branch-only cache reuse", + "passed": true + }, + { + "name": "omitted branch preserves cached provenance", + "passed": true + }, + { + "name": "explicit version and branch", + "passed": true + } + ] +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/reference-fetch.txt b/docs/verification/issue-386/resume/reference-fetch.txt new file mode 100644 index 00000000..a8c6a8ad --- /dev/null +++ b/docs/verification/issue-386/resume/reference-fetch.txt @@ -0,0 +1,8 @@ +Editor: {"assetsPath": "/.cache/issue-386/staff-project/Assets", "codeIndexRoot": "/.cache/issue-386/staff-project/.unity/cache/code-index", "packagesPath": "/.cache/issue-386/staff-project/Packages", "projectRoot": "/.cache/issue-386/staff-project", "unity": {"platform": "WindowsEditor", "productName": "staff-project", "unityVersion": "6000.4.4f1"}} +PASS: live Editor readiness +PASS: branch-only real fetch +PASS: branch-only cache reuse +PASS: omitted branch preserves cached provenance +PASS: explicit version and branch +Passed: 5; Failed: 0; Total: 5 +Artifacts: \.cache\issue-386\resume\reference-fixed\reference-fetch diff --git a/docs/verification/issue-386/resume/reference-longpath-green.txt b/docs/verification/issue-386/resume/reference-longpath-green.txt new file mode 100644 index 00000000..a8dec01c --- /dev/null +++ b/docs/verification/issue-386/resume/reference-longpath-green.txt @@ -0,0 +1,8 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 9.02s + Running unittests src\main.rs (target\debug\deps\unity_cli-6f9d4071c936636c.exe) + +running 1 test +test reference::fetcher::tests::fetch_selected_checks_out_long_windows_paths_without_global_configuration ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 557 filtered out; finished in 2.91s diff --git a/docs/verification/issue-386/resume/reference-longpath-red.txt b/docs/verification/issue-386/resume/reference-longpath-red.txt new file mode 100644 index 00000000..9ba5ca67 --- /dev/null +++ b/docs/verification/issue-386/resume/reference-longpath-red.txt @@ -0,0 +1,22 @@ + Compiling unity-cli v0.18.1 () + Finished `test` profile [unoptimized + debuginfo] target(s) in 9.86s + Running unittests src\main.rs (target\debug\deps\unity_cli-6f9d4071c936636c.exe) + +running 1 test +test reference::fetcher::tests::fetch_selected_checks_out_long_windows_paths_without_global_configuration ... FAILED + +failures: + +---- reference::fetcher::tests::fetch_selected_checks_out_long_windows_paths_without_global_configuration stdout ---- + +thread 'reference::fetcher::tests::fetch_selected_checks_out_long_windows_paths_without_global_configuration' (24288) panicked at src\reference\fetcher.rs:564:80: +called `Result::unwrap()` on an `Err` value: git checkout failed (exit code: 128): fatal: cannot create directory at 'ModuleModuleModuleModuleModuleModuleModule/GraphToolkitGraphToolkitGraphToolkitGraphToolkit/CommandStateObserverCommandStateObserverCommandStateObserver': Filename too long +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + +failures: + reference::fetcher::tests::fetch_selected_checks_out_long_windows_paths_without_global_configuration + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 557 filtered out; finished in 1.92s + +error: test failed, to rerun pass `--bin unity-cli` diff --git a/docs/verification/issue-386/resume/reference-resolution-summary.json b/docs/verification/issue-386/resume/reference-resolution-summary.json new file mode 100644 index 00000000..b9ff1516 --- /dev/null +++ b/docs/verification/issue-386/resume/reference-resolution-summary.json @@ -0,0 +1,22 @@ +{ + "passed": 4, + "failed": 0, + "results": [ + { + "name": "live Editor readiness", + "passed": true + }, + { + "name": "real project automatic fetch/status/grep", + "passed": true + }, + { + "name": "6000.4.12f1 automatic exact tag/status/grep", + "passed": true + }, + { + "name": "6000.4 explicit public ref/status/grep", + "passed": true + } + ] +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/reference-resolution.txt b/docs/verification/issue-386/resume/reference-resolution.txt new file mode 100644 index 00000000..c67a2650 --- /dev/null +++ b/docs/verification/issue-386/resume/reference-resolution.txt @@ -0,0 +1,6 @@ +PASS: live Editor readiness +PASS: real project automatic fetch/status/grep +PASS: 6000.4.12f1 automatic exact tag/status/grep +PASS: 6000.4 explicit public ref/status/grep +Passed: 4; Failed: 0; Total: 4 +Artifacts: \.cache\issue-386\resume\reference-fixed\reference-resolution diff --git a/docs/verification/issue-386/resume/rustdoc-final.txt b/docs/verification/issue-386/resume/rustdoc-final.txt new file mode 100644 index 00000000..e2bb95ea --- /dev/null +++ b/docs/verification/issue-386/resume/rustdoc-final.txt @@ -0,0 +1,3 @@ + Documenting unity-cli v0.18.1 () + Finished `dev` profile [unoptimized + debuginfo] target(s) in 9.06s + Generated \target\doc\unity_cli\index.html diff --git a/docs/verification/issue-386/resume/skills-lint-final.txt b/docs/verification/issue-386/resume/skills-lint-final.txt new file mode 100644 index 00000000..71751944 --- /dev/null +++ b/docs/verification/issue-386/resume/skills-lint-final.txt @@ -0,0 +1,5 @@ + Blocking waiting for file lock on package cache + Finished `dev` profile [unoptimized + debuginfo] target(s) in 12.26s + Running `target\debug\unity-cli.exe skills lint --severity error` + +23 skills checked, 0 violations diff --git a/docs/verification/issue-386/resume/source-snapshot.json b/docs/verification/issue-386/resume/source-snapshot.json new file mode 100644 index 00000000..a1ec0efe --- /dev/null +++ b/docs/verification/issue-386/resume/source-snapshot.json @@ -0,0 +1,35 @@ +{ + "recorded_at": "2026-10-04T00:10:05.758930+00:00", + "source_git_head_before_evidence_commit": "342f499fffba1d28c6e0839cd3c109b595083841", + "working_file_hashes": { + "Cargo.lock": "0189b962ae9a4c0d8cbf492b3994ddc964a61b7fb3684b1bda27bc5b463d887f", + "Cargo.toml": "d701e98bf9734c3bddea1f3f3bfdf49617141e598982bc09f309d09e6fe662bc", + "UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/BakeHandler.cs": "fcec0685c04aca0a16f4151a60433f0201c5a751676733bee7f95b2f24b66ec6", + "UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/SceneHandler.cs": "3d44351bdbeda87ffb1a432f3ac013e6c86f2709935bbc7462e01e057a3cc2f9", + "UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/BakeHandlerTests.cs": "0297a5ce0d0679fe02a0f5108e6aded7b053978765c34d975d6d15d4df9c8673", + "UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/SceneHandlerTests.cs": "381ffee4c4341d6ab7442523ff4e4cec82ae3d9fe8d8239de1edfbbb7bda4717", + "UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/InputSimulationAutomationPlayModeTests.cs": "a2dc48d02587b040e1356ebded544702a5d847ad1bb454db71bc09b39e16a44b", + "UnityCliBridge/Packages/unity-cli-bridge/Tests/PlayMode/TouchGesturePlayModeTests.cs": "c23e5769c36205ef9fbb41d13be465deab504a8d2aa312b30788928f5884a69e", + "scripts/bench-compare-official.py": "8b4a77c97260fec724a5d1187c1561a7a0f25d9c3734fe8eada1c0a3ca4bc1e6", + "scripts/bridge_auth.py": "132e3e36c2eb79e2983bdfdfdeb4d125d7b6cd8476ffaee7e85b91fdef13bf36", + "scripts/e2e-editor-lifecycle.py": "6436af1cdd7c36a40fe0d60fef708fcd07a10ad4b2ada7d6b80a1242b3596fff", + "src/app/editor.rs": "12ea2e975445003f9f47e5a8b9e62bbf9c5c7be5ca5e1393ef6bfab022c67199", + "src/app/setup.rs": "eab8bdf7cd59500812ac40c9acc104cf5a6c2c35140733e23571583a0829aa1f", + "src/app/test_runner.rs": "f8023e20459795926704614160cbb05b782f1fdc8b32e6c196d7695b38ae5691", + "src/core/failure.rs": "388e1cdd98d840f80d2bba9097ddb498ad14faf30d1c449ac633571e0c1970e5", + "src/daemon/unityd.rs": "3cbc5499fc3edb1b8ad3422a864e2e64c94a8f2be4f73f98513a4e5df55d629d", + "src/lsp/client.rs": "7c676ee0a967f79f6914140c1e147d29b58100ac5ec4fa41829b32563bbfd838", + "src/lsp/daemon.rs": "581ac8fd1f9df763069df66c0ed17d6507919ee63c52afff9741aa452f49fc7b", + "src/mcp/configure.rs": "eced95030b0b011ae2a661b4b8cec1420549064c4945aa74242cc6e38523be64", + "src/reference/fetcher.rs": "2b93e07601dae574b04ba45d7078ea68af4957dc0fc2145c6025b813617b75ba", + "src/skills/rules.rs": "8cd1c7333df34993769ec87c1fdafbb39f7a72072ef8a1ecc0c1eb04a17b6ce4", + "src/skills/tests.rs": "13a3b18495a14eec6b41cad87492481db7aa191ec963ba3651be785cbfb6a52b", + "tests/auth_warning.rs": "f777f9a364bc69a09c48b77f46a20a3eefdb2aef93e252658ec3e0c1fddaa348", + "tests/mcp.rs": "366a12d5cd72f856fe5318dc406dc020d59e0ec443313f2e5ef6ffb7e0c6f828", + "tests/scripts/test_process_liveness.py": "d6d4c51423dfee7d677c2e42922ed03bccc45c2bf9605c73f7ce7860c5634bf2", + "tests/setup_dry_run.rs": "b833e5151da71df57eba9770fa88d446a6142c605c5c56a94ae76f0e64344ea8" + }, + "latest_windows_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", + "public_linux_cli_sha256": "f0b12f5e4815e77a7c71098903ff9e1dd86ca350dd59e06f50fa27fd256b0a8e", + "source_note": "Native working-file hashes identify the tested source plus reviewable source changes; functional suite records preserve their earlier binary hashes separately. The evidence commit is created after collection." +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/staff-binary-environment.json b/docs/verification/issue-386/resume/staff-binary-environment.json new file mode 100644 index 00000000..d77c84e2 --- /dev/null +++ b/docs/verification/issue-386/resume/staff-binary-environment.json @@ -0,0 +1,26 @@ +{ + "head": "342f499fffba1d28c6e0839cd3c109b595083841", + "source_file_sha256": { + "UnityCliBridge/Packages/unity-cli-bridge/Editor/Handlers/SceneHandler.cs": "3d44351bdbeda87ffb1a432f3ac013e6c86f2709935bbc7462e01e057a3cc2f9", + "UnityCliBridge/Packages/unity-cli-bridge/Tests/Editor/Handlers/SceneHandlerTests.cs": "381ffee4c4341d6ab7442523ff4e4cec82ae3d9fe8d8239de1edfbbb7bda4717", + "src/app/editor.rs": "12ea2e975445003f9f47e5a8b9e62bbf9c5c7be5ca5e1393ef6bfab022c67199", + "src/app/setup.rs": "02f1150b2f6bccf6e77e2b2de772190f28dfd0b7c569c3a3d6b75a405c949228", + "src/app/test_runner.rs": "f8023e20459795926704614160cbb05b782f1fdc8b32e6c196d7695b38ae5691", + "src/daemon/unityd.rs": "15b55ff881abdd288d86ab0f05dc8762bf4d8f748c8176d2b002503930b419e4", + "src/lsp/client.rs": "3986aee934cb3ef91456bc309e3414d84b58450889c14728f6e5117103f6ea04", + "src/lsp/daemon.rs": "e9dddc765c4d0ee1f464919586bf68d7e121f16f307760ffd8cae9c41f43c154", + "src/skills/tests.rs": "047a67747538d40f650a88286d31c79592a50f9b8c5262ad2093f84445821ccd", + "tests/setup_dry_run.rs": "b833e5151da71df57eba9770fa88d446a6142c605c5c56a94ae76f0e64344ea8", + "src/mcp/configure.rs": "1c9b0401180bd9f560e074cfe686af17d752e613e58df3fcec6ff48d6ad78154", + "tests/mcp.rs": "bcecb2c5333ddff5d980c9d8f62bfcd6a0e802bda8b8e18b04e213ad7c73a9c8", + "src/skills/rules.rs": "8cd1c7333df34993769ec87c1fdafbb39f7a72072ef8a1ecc0c1eb04a17b6ce4", + "src/skills/distribution.rs": "6780927176d77454bdc6a35b4ba86759ce6a3c17a21806580a70bb728c52463f", + "scripts/bridge_auth.py": "8db17ca2a62d196462d87f7c0496401864963a0e00ebc39b56a154c53f3cad2c", + "scripts/e2e-editor-lifecycle.py": "1c9dabc140a843f687c2ae38aa8828a25dd0ec6dd9c4aed41a464369e8ca5be6", + "src/reference/fetcher.rs": "6462cd154d02efb70ede92b580c96a42fe58494d6718baeba4e0436e70bcf21e", + "Cargo.toml": "dd4620b7ab39892cba9ee092439762ce98231f10fa41b8f477a67f60f9c764e0", + "Cargo.lock": "71cdc258ee55f9e495ad99b150b95b3a2da0a83c79bb55e27f822631bb2142cd" + }, + "binary_sha256": "f51a12aa3ec63237a3185dceb4635758b35f4c9f4a37884c2a05a04d6a74998b", + "note": "The running staff suites use the binary built from this committed source. The later Git HTTP authentication fix is being validated separately; unsuccessful rebuilds did not replace this binary." +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/staff-extra-results.json b/docs/verification/issue-386/resume/staff-extra-results.json new file mode 100644 index 00000000..ca473d1a --- /dev/null +++ b/docs/verification/issue-386/resume/staff-extra-results.json @@ -0,0 +1,126 @@ +[ + { + "name": "prefab", + "command": [ + "py", + "-3", + "-X", + "utf8", + "-B", + "scripts/e2e-prefab.py", + "--unity-cli", + "\\target\\debug\\unity-cli.exe", + "--project-root", + "\\.cache\\issue-386\\staff-project", + "--port", + "6487", + "--output", + "\\.cache\\issue-386\\resume\\prefab-final", + "--editmode" + ], + "started_at": "2026-10-03T21:05:32.803502+00:00", + "exit_code": 0, + "finished_at": "2026-10-03T21:07:27.701078+00:00" + }, + { + "name": "timeline", + "command": [ + "py", + "-3", + "-X", + "utf8", + "-B", + "scripts/e2e-timeline.py", + "--unity-cli", + "\\target\\debug\\unity-cli.exe", + "--port", + "6487" + ], + "started_at": "2026-10-03T21:07:27.701498+00:00", + "exit_code": 0, + "finished_at": "2026-10-03T21:07:38.628970+00:00" + }, + { + "name": "eval", + "command": [ + "py", + "-3", + "-X", + "utf8", + "scripts/e2e-eval.py", + "--unity-cli", + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "--soak-iterations", + "1000" + ], + "started_at": "2026-10-03T21:07:38.629402+00:00", + "exit_code": 0, + "finished_at": "2026-10-03T21:25:25.741501+00:00" + }, + { + "name": "bake", + "command": [ + "py", + "-3", + "-X", + "utf8", + "-B", + "scripts/e2e-bake.py", + "--unity-cli", + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "--project-root", + "\\.cache\\issue-386\\staff-project" + ], + "started_at": "2026-10-03T21:25:25.741912+00:00", + "exit_code": 1, + "finished_at": "2026-10-03T21:25:28.565921+00:00" + }, + { + "name": "domain-reload", + "command": [ + "py", + "-3", + "-X", + "utf8", + "-B", + "scripts/e2e-test-domain-reload.py", + "--cli", + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "--output", + "\\.cache\\issue-386\\resume\\domain-reload.json" + ], + "started_at": "2026-10-03T21:25:28.566314+00:00", + "exit_code": 0, + "finished_at": "2026-10-03T21:25:44.845566+00:00" + }, + { + "name": "player-build", + "command": [ + "py", + "-3", + "-X", + "utf8", + "-B", + "scripts/e2e-player-build.py", + "--cli", + "\\target\\debug\\unity-cli.exe", + "--unity", + "C:/Program Files/Unity/Hub/Editor/6000.4.4f1/Editor/Unity.exe", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--port", + "6487", + "--target", + "StandaloneWindows64" + ], + "started_at": "2026-10-03T21:25:44.846047+00:00", + "exit_code": 1, + "finished_at": "2026-10-03T21:25:55.110575+00:00" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/staff-final-operations.json b/docs/verification/issue-386/resume/staff-final-operations.json new file mode 100644 index 00000000..7edc3aa3 --- /dev/null +++ b/docs/verification/issue-386/resume/staff-final-operations.json @@ -0,0 +1,140 @@ +[ + { + "name": "editor_state", + "tool": "get_editor_state", + "status": "PASS", + "elapsed_seconds": 0.268 + }, + { + "name": "hierarchy", + "tool": "get_hierarchy", + "status": "PASS", + "elapsed_seconds": 0.038 + }, + { + "name": "find_gameobject", + "tool": "find_gameobject", + "status": "PASS", + "elapsed_seconds": 0.036 + }, + { + "name": "transform", + "tool": "get_component_values", + "status": "PASS", + "elapsed_seconds": 0.039 + }, + { + "name": "position", + "tool": "modify_gameobject", + "status": "PASS", + "elapsed_seconds": 0.039 + }, + { + "name": "create_cube", + "tool": "create_gameobject", + "status": "PASS", + "elapsed_seconds": 0.063 + }, + { + "name": "add_component", + "tool": "add_component", + "status": "PASS", + "elapsed_seconds": 0.049 + }, + { + "name": "remove_component", + "tool": "remove_component", + "status": "PASS", + "elapsed_seconds": 0.045 + }, + { + "name": "delete_gameobject", + "tool": "delete_gameobject", + "status": "PASS", + "elapsed_seconds": 0.039 + }, + { + "name": "scene_info", + "tool": "get_scene_info", + "status": "PASS", + "elapsed_seconds": 0.038 + }, + { + "name": "scene_save", + "tool": "save_scene", + "status": "PASS", + "elapsed_seconds": 0.325 + }, + { + "name": "console", + "tool": "read_console", + "status": "PASS", + "elapsed_seconds": 0.046 + }, + { + "name": "screenshot", + "tool": "capture_screenshot", + "status": "PASS", + "elapsed_seconds": 0.099 + }, + { + "name": "material_search", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.043 + }, + { + "name": "asset_copy", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.07 + }, + { + "name": "asset_move", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.063 + }, + { + "name": "asset_delete", + "tool": "manage_asset_database", + "status": "PASS", + "elapsed_seconds": 0.305 + }, + { + "name": "import_settings", + "tool": "manage_asset_import_settings", + "status": "PASS", + "elapsed_seconds": 0.04 + }, + { + "name": "material_modify", + "tool": "modify_material", + "status": "PASS", + "elapsed_seconds": 0.055 + }, + { + "name": "time_settings", + "tool": "get_project_settings", + "status": "PASS", + "elapsed_seconds": 0.038 + }, + { + "name": "read_csharp", + "tool": "read", + "status": "PASS", + "elapsed_seconds": 0.06 + }, + { + "name": "play_until_ready", + "tool": "play_game", + "status": "PASS", + "elapsed_seconds": 0.739 + }, + { + "name": "stop_until_ready", + "tool": "stop_game", + "status": "PASS", + "elapsed_seconds": 0.429 + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/staff-final-summary.json b/docs/verification/issue-386/resume/staff-final-summary.json new file mode 100644 index 00000000..7f2b0e4b --- /dev/null +++ b/docs/verification/issue-386/resume/staff-final-summary.json @@ -0,0 +1,646 @@ +{ + "started_at": "2026-10-03T20:31:49.968912+00:00", + "source_commit": "0458d7fa83d55a3e77cb833ba74c705b65927a30", + "binary_sha256": "0038934812c1881055a67f05e463719dac55813293402991e78ba75aa63dfd7a", + "cases": { + "staff-play-settings": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "editor", + "eval", + "\nvar before = new { enabled = UnityEditor.EditorSettings.enterPlayModeOptionsEnabled,\n options = UnityEditor.EditorSettings.enterPlayModeOptions.ToString() };\nUnityEditor.EditorSettings.enterPlayModeOptionsEnabled = true;\nUnityEditor.EditorSettings.enterPlayModeOptions = UnityEditor.EnterPlayModeOptions.DisableDomainReload;\nvar assembly = typeof(UnityEditor.EditorWindow).Assembly;\nvar game = assembly.GetType(\"UnityEditor.GameView\", true);\nUnityEditor.EditorWindow.GetWindow(game, false, \"Game\", false);\nvar type = assembly.GetType(\"UnityEditor.PlayModeView\", true);\nvar property = type.GetProperty(\"enterPlayModeBehavior\");\nforeach (var view in UnityEngine.Resources.FindObjectsOfTypeAll(type))\n property.SetValue(view, System.Enum.Parse(property.PropertyType, \"PlayUnfocused\"));\nreturn before;\n", + "--mode", + "statements" + ], + "exit_code": 0, + "elapsed_seconds": 0.56, + "success": true + }, + "staff-get_editor_state-1": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.081, + "success": true + }, + "staff-create_scene-2": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "create_scene", + "--json", + "{\"sceneName\": \"Issue386_Staff_1791059510766711200\", \"path\": \"Assets/Scenes/Generated/E2E/Performance\", \"loadScene\": true}" + ], + "exit_code": 0, + "elapsed_seconds": 0.143, + "success": true + }, + "staff-create_gameobject-3": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "create_gameobject", + "--json", + "{\"name\": \"Perf394Target\", \"primitiveType\": \"cube\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.18, + "success": true + }, + "staff-create_material-4": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "create_material", + "--json", + "{\"materialPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\", \"shader\": \"Unlit/Color\", \"overwrite\": true}" + ], + "exit_code": 0, + "elapsed_seconds": 0.074, + "success": true + }, + "staff-save_scene-5": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "save_scene", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.293, + "success": true + }, + "staff-get_editor_state-6": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.267, + "success": true + }, + "staff-get_hierarchy-7": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_hierarchy", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.038, + "success": true + }, + "staff-find_gameobject-8": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "find_gameobject", + "--json", + "{\"name\": \"Perf394Target\", \"exactMatch\": true}" + ], + "exit_code": 0, + "elapsed_seconds": 0.036, + "success": true + }, + "staff-get_component_values-9": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_component_values", + "--json", + "{\"gameObjectName\": \"Perf394Target\", \"componentType\": \"Transform\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.039, + "success": true + }, + "staff-modify_gameobject-10": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "modify_gameobject", + "--json", + "{\"path\": \"/Perf394Target\", \"position\": {\"x\": 1, \"y\": 2, \"z\": 3}}" + ], + "exit_code": 0, + "elapsed_seconds": 0.039, + "success": true + }, + "staff-create_gameobject-11": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "create_gameobject", + "--json", + "{\"name\": \"Perf394Cube\", \"primitiveType\": \"cube\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.063, + "success": true + }, + "staff-add_component-12": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "add_component", + "--json", + "{\"gameObjectPath\": \"/Perf394Cube\", \"componentType\": \"Rigidbody\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.049, + "success": true + }, + "staff-remove_component-13": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "remove_component", + "--json", + "{\"gameObjectPath\": \"/Perf394Cube\", \"componentType\": \"Rigidbody\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.044, + "success": true + }, + "staff-delete_gameobject-14": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "delete_gameobject", + "--json", + "{\"path\": \"/Perf394Cube\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.039, + "success": true + }, + "staff-get_scene_info-15": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_scene_info", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.038, + "success": true + }, + "staff-save_scene-16": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "save_scene", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.325, + "success": true + }, + "staff-read_console-17": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "read_console", + "--json", + "{\"count\": 20}" + ], + "exit_code": 0, + "elapsed_seconds": 0.045, + "success": true + }, + "staff-capture_screenshot-18": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "capture_screenshot", + "--json", + "{\"captureMode\": \"game\", \"width\": 1280, \"height\": 720, \"includeUI\": false, \"encodeAsBase64\": false, \"osFallback\": false}" + ], + "exit_code": 0, + "elapsed_seconds": 0.098, + "success": true + }, + "staff-manage_asset_database-19": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_database", + "--json", + "{\"action\": \"find_assets\", \"filter\": \"t:Material\", \"searchInFolders\": [\"Assets/Scenes/Generated/E2E/Performance\"]}" + ], + "exit_code": 0, + "elapsed_seconds": 0.042, + "success": true + }, + "staff-manage_asset_database-20": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_database", + "--json", + "{\"action\": \"copy_asset\", \"fromPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\", \"toPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.069, + "success": true + }, + "staff-manage_asset_database-21": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_database", + "--json", + "{\"action\": \"move_asset\", \"fromPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat\", \"toPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.063, + "success": true + }, + "staff-manage_asset_database-22": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_database", + "--json", + "{\"action\": \"delete_asset\", \"assetPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.305, + "success": true + }, + "staff-manage_asset_import_settings-23": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "manage_asset_import_settings", + "--json", + "{\"action\": \"get\", \"assetPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\"}" + ], + "exit_code": 0, + "elapsed_seconds": 0.039, + "success": true + }, + "staff-modify_material-24": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "modify_material", + "--json", + "{\"materialPath\": \"Assets/Scenes/Generated/E2E/Performance/PerfSource.mat\", \"properties\": {\"_Color\": [0.2, 0.4, 0.8, 1]}}" + ], + "exit_code": 0, + "elapsed_seconds": 0.054, + "success": true + }, + "staff-get_project_settings-25": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_project_settings", + "--json", + "{\"includeTime\": true, \"includePlayer\": false}" + ], + "exit_code": 0, + "elapsed_seconds": 0.037, + "success": true + }, + "staff-read-26": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "read", + "--json", + "{\"path\": \"Packages/com.akiojin.unity-cli-bridge/Editor/Core/UnityCliBridgeHost.cs\", \"maxLines\": 50}" + ], + "exit_code": 0, + "elapsed_seconds": 0.059, + "success": true + }, + "staff-play_game-27": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "play_game", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.3, + "success": true + }, + "staff-get_editor_state-28": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.043, + "success": true + }, + "staff-get_editor_state-29": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.035, + "success": true + }, + "staff-get_editor_state-30": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.036, + "success": true + }, + "staff-get_editor_state-31": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.293, + "success": true + }, + "staff-stop_game-32": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "stop_game", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.042, + "success": true + }, + "staff-get_editor_state-33": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.142, + "success": true + }, + "staff-get_editor_state-34": { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--output", + "json", + "--project-path", + "\\.cache\\issue-386\\red-project", + "--timeout-ms", + "60000", + "raw", + "get_editor_state", + "--json", + "{}" + ], + "exit_code": 0, + "elapsed_seconds": 0.233, + "success": true + } + }, + "play_settings": { + "enterPlayModeOptionsEnabled": true, + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeBehavior": "PlayUnfocused", + "previous": { + "enabled": true, + "options": "DisableDomainReload" + } + }, + "finished_at": "2026-10-03T20:31:54.429601+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/staff-scope-reconstruction.md b/docs/verification/issue-386/resume/staff-scope-reconstruction.md new file mode 100644 index 00000000..00c38caf --- /dev/null +++ b/docs/verification/issue-386/resume/staff-scope-reconstruction.md @@ -0,0 +1,144 @@ +# Issue #386: reconstructed staff coverage and Windows execution entrypoints + +Read-only scope investigation, 2026-10-04. The original +`project-state/pm-scratch/staff-report.md` has **not been obtained**. Its text, +original row order, precise ○/△/— marks, all positive scenarios, and attachment +identity cannot be guaranteed by this reconstruction. Do not mark AC-5 complete +solely because the rows below pass. + +The following **13 verification categories** consolidate primary Issues +[#243–260](https://github.com/akiojin/unity-cli/issues/243), plus +[#390–395](https://github.com/akiojin/unity-cli/issues/390). This grouping is an +inference for managing coverage, not a claim to reproduce the original report's +13 rows. #393 explicitly says the report had 13 △/— rows, of which 12 had been +implemented by v0.13–v0.15. Original issues record the actual Windows investigation +on 2026-09-26; #390–395 describe the report received on 2026-09-30. Both dates +belong in provenance, rather than silently treating them as the same event. + +| Reconstructed category | Primary source and original expected behavior | Current verification entrypoint | Windows fixture/package/module requirements | Coverage beyond the public 23 operations | +| --- | --- | --- | --- | --- | +| 1. Keyboard / gamepad / touch simulation | #243: keyboard hold duration uses elapsed seconds at 30/60/120/unlimited fps; original measurement also compared physical-priority and isolated Keyboard, absent/0.2/1/2-second holds, three repeats (72 trials). #245: tap/swipe occupy multiple game frames without blocking Update. #246: processed individual stick axes match zero, single-axis, diagonal and maximum requests. #393 names this combined feature row. | Real PlayMode fixtures `InputSimulationAutomationPlayModeTests` (including four fps hold cases), `TouchGesturePlayModeTests`, `GamepadStickInputPlayModeTests`; `scripts/e2e-input-tools.sh` for TCP input calls. The original observation C# source is embedded verbatim in fetched `243.md`/`244.md`/`245.md`/`246.md`; use its `Issue Repro/Setup`, Configure, Reset, Snapshot and Positive menus to reproduce original trials. | `com.unity.inputsystem` 1.19.0 for the reported stream, activeInputHandler Both or Input System, game Update running, InputSystem focus routing. Input UI script additionally needs UGUI, `UnityCliInputTestSceneGenerator.cs`, `UnityCliInputSimulationTestBootstrap.cs`, `InputStateDisplay.cs`; generated scenes remain inside the disposable project's `Assets/Scenes/Generated/E2E`. | None of the input variants is among the 23 benchmark operations. Basic command success alone does not prove the original 72 duration trials or game-frame observations. | +| 2. InputAction callback notification | #244: pre-enabled PassThrough actions must receive both press=1 and release=0 for keyboard, mouse and gamepad, regardless of Editor/Dynamic update timing. Positive QueueStateEvent control must still notify. | `InputActionNotificationTests` real EditMode suite; original `IssueInputProbe` records callbacks with frame, time and InputState currentUpdateType. The Input Tools script observes device states but is not a replacement for callback evidence. | Input System; observer must be active before the CLI input. Test 30/120/unlimited fps and compare positive controls. | Not measured by the 23 operations. | +| 3. Input Actions type and persistence | #247: both create_action_map and add_input_action preserve Button/PassThrough/Value. #248: JSON source, memory state, reimport and full Editor restart agree. | `InputActionsHandlerTests` has all type cases for both creation paths; `InputActionsPersistenceTests` checks 10 edit variants and negative cases. `scripts/e2e-input-actions-persistence.py` performs disk/reimport/restart verification (50 assertions in macOS evidence). | Input System, Newtonsoft.Json, package listed in manifest testables. Standalone dedicated fixture with `UnityCliInputBatchHost.cs`; **no live Editor already using that project or its selected port**. Supply --unity-path and --project-path explicitly. | Asset copy/move/delete benchmarks do not exercise .inputactions source rewriting. Persistence E2E adds Button on map creation and Value via add; also run full type cases to cover PassThrough. | +| 4. Video recording formats | #249: mp4/webm/png_sequence must correspond to actual file headers; returned outputPath exists, PNG sequence contains multiple frames. | Python payload embedded in `scripts/e2e-video-formats.sh`, six named tests, validates MP4/WebM/PNG signatures and session lifecycle. | `com.unity.recorder` 5.1.6 for Unity 6000.4, Game View with a rendered Camera, graphics-enabled real Editor. Native Python extraction of the heredoc is appropriate; Linux Python plus Windows CLI cannot use Linux params-file paths. | Screenshot benchmark does not prove recording or any video format. | +| 5. PlayMode test results and Domain Reload | #250: two real FrameAdvances/RigidbodyFalls tests finish with Domain Reload enabled and disabled, with Scene Reload preserved. #251: totals count exactly two leaf tests, not fixture/assembly/root suites. | `scripts/e2e-test-domain-reload.py` against existing listener, **without --batch-host on Windows**; it exercises both settings and checks leaf counts. Focused real tests: `DomainReloadResultTests`, `TestResultCountingPlayModeTests`; collector/persistence unit tests separately. | `com.unity.test-framework`, package in `testables`, `DomainReloadE2ESettings.cs` menus available. Existing listener mode avoids lsof. The script restores settings. Do not run the full Bridge EditMode suite through the Bridge's own TestExecutionHandler: handler tests deliberately replace/reset the same static state. Use Unity's external native test runner for that suite. | Benchmark Play/Stop readiness is not run_tests/get_test_status and does not prove Domain Reload result recovery or counts. | +| 6. C# reference source resolution | #252: project version 6000.4.12f1 plus explicit branch 6000.4 works. #254: discover exact public tag / explicit branch, retain ref/commit provenance, never silently substitute an unrelated minor. | Python payloads embedded in `scripts/e2e-reference-fetch.sh` (5 checks) and `scripts/e2e-reference-resolution.sh` (4 checks), real Editor readiness plus isolated project-version fixtures and caches. | Network, native Git, license acceptance already requested by these suites; scratch cache only. Native Python must own the temp files supplied to the Windows CLI. No extra Unity package required. | `read_csharp` benchmark is local file reading; it does not exercise reference source acquisition, public ref selection or provenance. | +| 7. unityd on-demand / idle recovery and latency | #253: ordinary operations start a stopped daemon; recover after idle exit; concurrent first calls start only one daemon; preserve endpoint and report cold/warm costs. #394 adds performance regression coverage. | `scripts/e2e-unityd.py` owns its Editor but hardcodes the repository UnityCliBridge project: use its logic in a dedicated copied fixture, not that launch entrypoint against the live checkout. `scripts/bench-eval.py` can run native Windows without --require-frontmost/--activate; use 100 samples and explicit CLI/port. | Dedicated tools root; normal CLI daemon path; own project/port. Windows foreground observation requires a Windows implementation rather than the script's macOS osascript/lsof checks. | Existing 23 calls demonstrate successful ordinary operations, not concurrent cold-start / idle recovery. One sample per operation is not a performance comparison. | +| 8. Animation numeric curves | #255: localPosition.x keys 0s=0 and 1s=2, interpolation, key editing/removal, reject unsupported bindings, saved asset persists. | `scripts/e2e-animation-curves.sh` against existing listener; `AnimationCurveHandlerTests`. Port its shell assertions or run Git Bash with jq and native paths; its launch wrapper is macOS oriented. | Animation module, Newtonsoft.Json, disposable asset path. No optional package; jq required by shell runner. | Not covered by the 23 operations. | +| 9. Timeline track / clip / binding editing | #256: Animation Track with start/duration/binding, save/reload persistence, PlayableDirector evaluation reaches expected Animator pose, explicit unsupported-track/package errors. | `scripts/e2e-timeline.py` is native Windows compatible with existing listener and explicit --unity-cli / --port. `TimelineHandlerTests` separately. | `com.unity.timeline` 1.8.12, animation/director modules, `UnityCliTimelineE2EFixture.cs` copied into isolated Assets/Editor. Current full suite also calls capture_video_status, so Recorder is needed; --without-timeline expects both Timeline and Recorder missing. | Not covered by the 23 operations. | +| 10. In-Editor C# eval and caching | #257: numeric3, scene object read/create/modify, syntax error vs runtime exception, no persistent .cs file required. #391: correct reference invalidation across domain/new assembly and 1000 evals within memory/assembly bounds, plus 100-sample latency. | `scripts/e2e-eval.py` is native Windows compatible; default --soak-iterations1000, explicit CLI/port. `scripts/bench-eval.py` measures 100 samples; omit macOS-only focus flags. | Roslyn bundled with Bridge, graphics or batch listener. Set UNITY_PROJECT_ROOT to owned fixture. Its no-source-write assertion snapshots repository UnityCliBridge, so independently inspect the actual selected fixture when claiming AC-5 no persistent C# writes. | Benchmark eval1+2 is only one successful sample, not error contracts, objects, invalidation, soak or performance. | +| 11. Play Mode method hot reload | #258/#390: change existing calculation without stopping Play or losing scene/object/HP/score/state; invalid source, stale revision and partial/unobserved patch must not be successful. | `scripts/e2e-hot-reload.py --project ... --unity-cli ... --port ... --expect supported --require-arch X64`; prepare an isolated fixture from the existing batch-host wrapper. | **FastScriptReload 1.8.0**, separately installed at pinned commit `51140b71d9e5df1de231b33ec20ee089b18bebec`, plus copied `tests/fixtures/hot-reload/HotReloadProbe.cs` and `HotReloadE2EFixture.cs`. Disable FSR automatic/on-demand reload as documented. Adapter code allows X64 on Windows; ARM64 is limited to macOS. | Missing-package or unsupported-platform error-contract PASS does not prove real method replacement. No benchmark coverage. | +| 12. Lighting / navigation / occlusion bake | #259/#392: actual lightmap data plus saved scene references; legacy NavMesh and NavMeshSurface distinct; SamplePosition / path usable; Occlusion data assigned; failed/empty/no-output cases cannot report success. | `scripts/e2e-bake.py --unity-cli ... --project-root ... --port ... --targets lighting,navmesh-legacy,navmesh-surface,occlusion`; `UnityCliBakeE2EFixture.cs` creates/validates isolated bake scenes. | `com.unity.ai.navigation` 2.0.13, AI/terrain/lighting modules, fixture Editor source. **Graphics enabled** for real lightmap bake, not -nographics. Test legacy support for selected Unity; an UNSUPPORTED error is separate from a successful bake. | No benchmark coverage. Job acceptance alone is not generated/persisted artifact proof. | +| 13. Windows Player build / launch | #260/#392: .exe, _Data and BuildReport paths agree; execute generated Player; distinguish headless process from actual rendered game/input; preserve settings; errors are failures. | `scripts/e2e-player-build.py --cli ... --unity ... --project-path ... --target StandaloneWindows64` on existing listener; dedicated --launch --isolated-project mode adds compiler/build-failure/interruption cases. Safe Windows auth helper has been fixed in this worktree. | Windows Standalone Build Support for selected Editor, writable scratch output, saved minimal scene. Use --isolated-project with --launch to avoid Unix fcntl branch. Existing module probing looks under editor.parent.parent/PlaybackEngines; audit native Hub Editor/Data layout. | Script validates Windows artifacts but currently only launches the generated Player for StandaloneOSX. Windows headless and graphical/input launch observations require additional actual execution; script's final "Windows hardware pending" must not be misreported as verified. | + +## Additional known original positive row + +Issue #395 explicitly quotes the original report's **Prefab creation/placement/editing** +row as ○ for both products, with only direct editing/Prefab Mode save verified on +unity-cli and Variant/Overrides/Unpack verified on official CLI. This row is +outside the inferred 13 △/— categories above and illustrates why the missing +complete report still matters. Native existing-listener `scripts/e2e-prefab.py` +adds 45 meaningful runtime assertions plus 22 focused EditMode tests, covering +Variant inheritance, preserved overrides, apply destinations, individual/whole +revert/apply, and Outermost/Completely semantics. No optional Unity package is +needed. Supply --project-root, --unity-cli, --port and new --output; omit --launch +because its launch path and ownership lsof are macOS specific. + +## Native Windows commands for an already prepared owned listener + +These are reviewable commands, **not evidence that they have been executed**. +The owner must set the process-local UNITY_PROJECT_ROOT, UNITY_CLI_TOOLS_ROOT, +UNITY_CLI_NO_AUTO_UPDATE and any owned lockfile directory consistently. Invoke +all shell wrappers using `bash -lc` and the repository workdir as required. + +```text +py.exe -3 -X utf8 -B scripts/e2e-prefab.py --unity-cli /target/debug/unity-cli.exe --project-root /.cache/issue-386/red-project --port 6487 --output /.cache/issue-386/staff-prefab-final --editmode + +py.exe -3 -X utf8 -B scripts/e2e-eval.py --unity-cli /target/debug/unity-cli.exe --port 6487 --soak-iterations 1000 + +py.exe -3 -X utf8 -B scripts/e2e-timeline.py --unity-cli /target/debug/unity-cli.exe --port 6487 + +py.exe -3 -X utf8 -B scripts/e2e-bake.py --unity-cli /target/debug/unity-cli.exe --project-root /.cache/issue-386/red-project --port 6487 --targets lighting,navmesh-legacy,navmesh-surface,occlusion + +py.exe -3 -X utf8 -B scripts/e2e-test-domain-reload.py --cli /target/debug/unity-cli.exe --port 6487 --output /.cache/issue-386/staff-domain-reload.json + +py.exe -3 -X utf8 -B scripts/bench-eval.py --unity-cli /target/debug/unity-cli.exe --port 6487 --iterations 100 --warmup 3 --out /.cache/issue-386/staff-eval-100.json + +py.exe -3 -X utf8 -B scripts/e2e-player-build.py --cli /target/debug/unity-cli.exe --unity C:/Program\ Files/Unity/Hub/Editor/6000.4.4f1/Editor/Unity.exe --project-path /.cache/issue-386/red-project --port 6487 --target StandaloneWindows64 +``` + +For Input Actions restart E2E, close any Editor using **that dedicated copied +fixture only**, then call: + +```text +py.exe -3 -X utf8 -B scripts/e2e-input-actions-persistence.py --unity-cli /target/debug/unity-cli.exe --unity-path "C:/Program Files/Unity/Hub/Editor/6000.4.4f1/Editor/Unity.exe" --project-path /.cache/issue-386/staff-persistence-project --port 6489 +``` + +Use the actual installed Editor path; the path above is illustrative. The owner +uses a process argument array, so shell backslash escaping is unnecessary there. +For video/reference scripts whose Python bodies are heredocs, extract the body +without changing assertions, set UNITY_CLI_BIN, and run it through native Python +with native Windows artifact/project/CLI paths. Keep original source hash and +extraction hash in the evidence. Running Linux Python with native CLI params-file +paths creates false failures. The macOS e2e-matrix entrypoint cannot be directly +claimed Windows-compatible: Hub layout, lsof, osascript and os.killpg are embedded. + +## Safety repair performed during this investigation + +`scripts/bridge_auth.py` now shares `process_alive()` with +`scripts/e2e-editor-lifecycle.py`. Windows uses OpenProcess with SYNCHRONIZE, +WaitForSingleObject(timeout0) and closes the handle. Unix preserves signal-zero +existence behavior, with invalid/out-of-range PID rejection. + +The original Windows Python signal-zero path is **not an observation**: +CPython 3.14 maps zero to CTRL_C_EVENT and calls GenerateConsoleCtrlEvent; with +nonzero target PID it can succeed without observing the process. It therefore +reported already exited children as alive and selected stale credentials. +PID zero broadcasts a console event. The first exploratory RED was interrupted +by that behavior; the formal safe RED uses only already exited owned child PIDs. +No Editor PID was passed to these regression tests. + +- Formal RED: `process-liveness-exited-red.txt`, child-based authentication and + lifecycle checks both fail because an exited child is considered live, exit1. +- Windows GREEN: `process-liveness-green.txt`, 4/4 tests; existing auth tests + `bridge-auth-green.txt`, 3/3. +- Linux regression: `process-liveness-linux.txt`, 3 PASS / 1 Windows-specific + exit-code skip; existing auth3/3 PASS. +- New tests cover a live child surviving both probes, exited child rejection, + zero/negative/nonrepresentable IDs, and Windows child exit259, which must not be + confused with STILL_ACTIVE. No source commit was made by this investigator. + +Primary runtime references: +[CPython os.kill implementation](https://github.com/python/cpython/blob/3.14/Modules/posixmodule.c#L9067) +and [Microsoft GenerateConsoleCtrlEvent semantics](https://learn.microsoft.com/en-us/windows/console/generateconsolectrlevent). + +## Canonical verification / PM handoff ruling provenance + +The exact clause "canonical verify.run が他の holder のホスト排他で待たされる場合は +待たず、PR の CI を最終確認とする。push したら Board で『PR作成可』と引き継ぐ。 +PR は PM が作成する" appears in the live owner-authored **Issue bodies #390–395**, +under Notes. #390/#391/#393 comments explicitly applied it to their own work. +Issue #392 author is akiojin; body last updated 2026-09-30T11:48:06Z in this snapshot. + +This proves a ruling shared by that Issue batch. It does **not** establish a +project-wide permanent override, and #386's current body has no such clause. +It does not authorize bypassing #386's blocked execution.reopen or protected +verification records. Ask the PM for a #386-specific ruling if needed; preserve +direct local PASS evidence while canonical tooling recovery is coordinated. + +## Original-report search result + +Parent's filename searches covered the worktree, E:/unity-cli, E:/gwt and user +home. Additional investigation found no matching tracked file in `git log --all +-- '*staff*report*' '*pm-scratch*' '*project-state*'`. GitHub code search for +staff-report in akiojin/unity-cli found only `scripts/bench-editor-ops.py`, not the +report. Issue-body search found references, not an attached complete report. +Fetched primary issue snapshots and complete comments remain in this directory +as `.json` / `.md`, and the pre-implementation scenario summaries +are in `original-scenarios.md`. + +Next verification should run the portable focused suites on prepared isolated +Windows fixtures and record each category's actual PASS/FAIL/UNSUPPORTED plus +raw evidence. Keep the completeness comparison and original positive feature +rows pending until the original report is supplied or the owner explicitly +rules that a reconstructed scope replaces it. diff --git a/docs/verification/issue-386/resume/timeline.txt b/docs/verification/issue-386/resume/timeline.txt new file mode 100644 index 00000000..3cc6ab31 --- /dev/null +++ b/docs/verification/issue-386/resume/timeline.txt @@ -0,0 +1,42 @@ +PASS get_editor_info {"assetsPath": "/.cache/issue-386/staff-project/Assets", "codeIndexRoot": "/.cache/issue-386/staff-project/.unity/cache/code-index", "packagesPath": "/.cache/issue-386/staff-project/Packages", "projectRoot": "/.cache/issue-386/staff-project", "unity": {"platform": "WindowsEditor", "productName": "staff-project", "unityVersion": "6000.4.4f1"}} +Unity version: 6000.4.4f1 +PASS capture_video_status {"isRecording": false} +PASS execute_menu_item {"executed": true, "executionTime": 403, "menuExists": true, "menuPath": "Tools/Unity CLI/Timeline/Generate E2E Fixture", "message": "Menu item executed successfully", "success": true} +PASS fixture menu executed +PASS manage_timeline {"action": "create_asset", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": null, "tracks": []} +PASS manage_timeline {"action": "assign_director", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "tracks": []} +PASS manage_timeline {"action": "create_track", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": null, "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "tracks": [{"binding": null, "clips": [], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS manage_timeline {"action": "add_clip", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "clipIndex": 0, "directorPath": null, "tracks": [{"binding": null, "clips": [{"animationClipPath": "Assets/Scenes/Generated/E2E/Timeline/Motion.anim", "duration": 2.0, "index": 0, "start": 1.0}], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS manage_timeline {"action": "set_binding", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "tracks": [{"binding": "/TimelineActor", "clips": [{"animationClipPath": "Assets/Scenes/Generated/E2E/Timeline/Motion.anim", "duration": 2.0, "index": 0, "start": 1.0}], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS get_timeline {"assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "tracks": [{"binding": "/TimelineActor", "clips": [{"animationClipPath": "Assets/Scenes/Generated/E2E/Timeline/Motion.anim", "duration": 2.0, "index": 0, "start": 1.0}], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS AC-1 timing and Animator binding readback +PASS manage_timeline INVALID +PASS manage_timeline $.trackType must be one of +PASS execute_menu_item {"executed": true, "executionTime": 115, "menuExists": true, "menuPath": "Tools/Unity CLI/Timeline/Generate Unsupported Track", "message": "Menu item executed successfully", "success": true} +PASS unsupported fixture menu executed +PASS get_timeline {"assetPath": "Assets/Scenes/Generated/E2E/Timeline/Unsupported.playable", "directorPath": null, "tracks": [{"binding": null, "clips": [], "name": "Audio", "trackId": "9aa7d0e7c0f043944b5d21e90044712e:-7584492291630700093", "type": "AudioTrack"}]} +PASS manage_timeline UNSUPPORTED_TRACK +PASS manage_timeline STALE_CLIP +PASS get_timeline {"assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "tracks": [{"binding": "/TimelineActor", "clips": [{"animationClipPath": "Assets/Scenes/Generated/E2E/Timeline/Motion.anim", "duration": 2.0, "index": 0, "start": 1.0}], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS invalid operations leave Timeline unchanged +PASS save_scene {"isDirty": false, "originalPath": null, "saved": true, "sceneName": "TimelineTest", "scenePath": "Assets/Scenes/Generated/E2E/Timeline/TimelineTest.unity", "summary": "Saved scene \"TimelineTest\" to \"Assets/Scenes/Generated/E2E/Timeline/TimelineTest.unity\""} +PASS execute_menu_item {"executed": true, "executionTime": 602, "menuExists": true, "menuPath": "Tools/Unity CLI/Timeline/Reload E2E Assets", "message": "Menu item executed successfully", "success": true} +PASS asset unloaded, reimported and scene reopened +PASS get_timeline {"assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "tracks": [{"binding": "/TimelineActor", "clips": [{"animationClipPath": "Assets/Scenes/Generated/E2E/Timeline/Motion.anim", "duration": 2.0, "index": 0, "start": 1.0}], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS AC-2 saved scene/asset reload roundtrip +PASS manage_timeline {"action": "evaluate", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "time": 2.0, "tracks": [{"binding": "/TimelineActor", "clips": [{"animationClipPath": "Assets/Scenes/Generated/E2E/Timeline/Motion.anim", "duration": 2.0, "index": 0, "start": 1.0}], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS get_gameobject_details {"components": [{"enabled": true, "properties": {"position": {"x": 5.0, "y": 0.0, "z": 0.0}, "rotation": {"x": 0.0, "y": 0.0, "z": 0.0}, "scale": {"x": 1.0, "y": 1.0, "z": 1.0}}, "type": "Transform"}, {"enabled": true, "properties": {"angularVelocity": {"x": 0.0, "y": 0.0, "z": 0.0}, "deltaPosition": {"x": 0.0, "y": 0.0, "z": 0.0}, "deltaRotation": {"eulerAngles": {"x": 0.0, "y": 0.0, "z": 0.0}, "w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0}, "hasRootMotion": false, "humanScale": 1.0, "isHuman": false, "isInitialized": true, "isOptimizable": false, "rootPosition": {"x": 5.0, "y": 0.0, "z": 0.0}, "velocity": {"x": 0.0, "y": 0.0, "z": 0.0}}, "type": "Animator"}], "isActive": true, "isStatic": false, "layer": "Default", "name": "TimelineActor", "path": "/TimelineActor", "prefabInfo": {"isInstance": false, "isPrefab": false}, "summary": "GameObject \"TimelineActor\" with 2 components at /TimelineActor", "tag": "Untagged", "transform": {"position": {"x": 5.0, "y": 0.0, "z": 0.0}, "rotation": {"x": 0.0, "y": 0.0, "z": 0.0}, "scale": {"x": 1.0, "y": 1.0, "z": 1.0}, "worldPosition": {"x": 5.0, "y": 0.0, "z": 0.0}}} +PASS AC-3 PlayableDirector evaluation animates Transform.x=5 +PASS manage_timeline {"action": "update_clip", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "clipIndex": 0, "directorPath": null, "tracks": [{"binding": null, "clips": [{"animationClipPath": "Assets/Scenes/Generated/E2E/Timeline/Motion.anim", "duration": 3.0, "index": 0, "start": 2.0}], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS get_timeline {"assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": null, "tracks": [{"binding": null, "clips": [{"animationClipPath": "Assets/Scenes/Generated/E2E/Timeline/Motion.anim", "duration": 3.0, "index": 0, "start": 2.0}], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS clip timing update +PASS manage_timeline {"action": "remove_clip", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": null, "tracks": [{"binding": null, "clips": [], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS get_timeline {"assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": null, "tracks": [{"binding": null, "clips": [], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS clip removal +PASS manage_timeline {"action": "clear_binding", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "tracks": [{"binding": null, "clips": [], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS get_timeline {"assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "tracks": [{"binding": null, "clips": [], "name": "Motion", "trackId": "9e72b0320f47758408c175009c832bea:-8359094986150629512", "type": "AnimationTrack"}]} +PASS binding clear +PASS manage_timeline {"action": "delete_track", "assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": "/TimelineDirector", "tracks": []} +PASS get_timeline {"assetPath": "Assets/Scenes/Generated/E2E/Timeline/Sequence-78b703c10f90467aa56906709bbbbd94.playable", "directorPath": null, "tracks": []} +PASS track deletion +Timeline E2E: passed=40 failed=0 diff --git a/docs/verification/issue-386/resume/video-formats.txt b/docs/verification/issue-386/resume/video-formats.txt new file mode 100644 index 00000000..7769575d --- /dev/null +++ b/docs/verification/issue-386/resume/video-formats.txt @@ -0,0 +1,13 @@ +Video format E2E: 127.0.0.1:6487; artifacts=\.cache\issue-386\resume\video-final +PASS recording outside Play Mode returns error +PASS invalid format returns error +Output mp4: \.cache\issue-386\staff-project\.unity\capture\video_game_2026-10-04_06-46-00_b4345be096744e71a48455453419794c.mp4 (83309 bytes, header=00000018667479706d703432000000006d70343169736f6d0000002875756964) +PASS mp4 file format and session lifecycle +Output webm: \.cache\issue-386\staff-project\.unity\capture\video_game_2026-10-04_06-46-03_68bdf052a04c45adae01da6c6126430d.webm (6079 bytes, header=1a45dfa39f4286810142f7810142f2810442f381084282847765626d42878102) +PASS webm file format and session lifecycle +PNG sequence: 24 frames in \.cache\issue-386\staff-project\.unity\capture\video_game_2026-10-04_06-46-07_389fff53335e4bbab47ba05c8a6eec8f +Output png_sequence: \.cache\issue-386\staff-project\.unity\capture\video_game_2026-10-04_06-46-07_389fff53335e4bbab47ba05c8a6eec8f\frame_0000.png (22843 bytes, header=89504e470d0a1a0a0000000d4948445200000140000000b40806000000e5e4f5) +PASS png_sequence file format and session lifecycle +Output mp4: \.cache\issue-386\staff-project\.unity\capture\video_game_2026-10-04_06-46-10_40e3f4e2d6e94e8c86b32cff6a25d3f7.mp4 (71048 bytes, header=00000018667479706d703432000000006d70343169736f6d0000002875756964) +PASS mp4 file format and session lifecycle +Passed: 6; Failed: 0; Total: 6 diff --git a/docs/verification/issue-386/resume/video-summary.json b/docs/verification/issue-386/resume/video-summary.json new file mode 100644 index 00000000..615d88df --- /dev/null +++ b/docs/verification/issue-386/resume/video-summary.json @@ -0,0 +1,8 @@ +{ + "passed": 6, + "failed": 0, + "total": 6, + "artifacts": "\\.cache\\issue-386\\resume\\video-final", + "host": "127.0.0.1", + "port": "6487" +} diff --git a/docs/verification/issue-386/resume/windows-comparison-adapter.py b/docs/verification/issue-386/resume/windows-comparison-adapter.py new file mode 100644 index 00000000..31839d06 --- /dev/null +++ b/docs/verification/issue-386/resume/windows-comparison-adapter.py @@ -0,0 +1,177 @@ +import ctypes +from ctypes import wintypes +import hashlib +import importlib.util +import json +import os +from pathlib import Path +import platform +import queue +import subprocess +import sys +import threading +import time +from datetime import datetime, timezone +from types import SimpleNamespace + +root = Path(__file__).resolve().parents[2] +cache = root / '.cache/issue-386' +out = cache / 'resume/official-windows' +project = cache / 'staff-project' +assert project.resolve().is_relative_to(cache.resolve()) +sys.path.insert(0, str(root / 'scripts')) +sys.dont_write_bytecode = True +spec = importlib.util.spec_from_file_location('comparison', root / 'scripts/bench-compare-official.py') +comparison = importlib.util.module_from_spec(spec) +spec.loader.exec_module(comparison) +bench = comparison.load_editor_bench() +comparison.load_editor_bench = lambda: bench +bench.READ_PATH = 'Packages/com.akiojin.unity-cli-bridge/Editor/Core/UnityCliBridgeHost.cs' +args = SimpleNamespace(project=project.resolve(), port=6487, unity_cli=str(root / 'target/debug/unity-cli.exe'), official=str(out / 'unity.exe'), timeout=60, iterations=100, warmup=3, focus='frontmost') +env = comparison.benchmark_environment(args.project, args.port) +env['UNITY_CLI_HOME'] = str(out / 'install') +env['PYTHONUTF8'] = '1' +(project / '.unity/perf-owned-project').write_text('Issue386-owned Windows comparison fixture\n', encoding='utf-8') +editor_pid = json.loads((cache / 'resume/staff-editor-open.json').read_text(encoding='utf-8'))['data']['pid'] +observed = subprocess.check_output(['powershell', '-NoProfile', '-Command', 'Get-NetTCPConnection -LocalPort 6487 -State Listen | Select-Object -ExpandProperty OwningProcess'], encoding='utf-8').split() +assert set(observed) == {str(editor_pid)}, 'Actual Bridge listener must be the owned Editor' +user = ctypes.WinDLL('user32', use_last_error=True) +user.GetForegroundWindow.restype = wintypes.HWND +user.GetWindowThreadProcessId.argtypes = [wintypes.HWND, ctypes.POINTER(wintypes.DWORD)] +user.SetForegroundWindow.argtypes = [wintypes.HWND] +user.SwitchToThisWindow.argtypes = [wintypes.HWND, wintypes.BOOL] +user.IsWindowVisible.argtypes = [wintypes.HWND] +user.IsWindow.argtypes = [wintypes.HWND] +user.ShowWindow.argtypes = [wintypes.HWND, ctypes.c_int] +user.ShowWindowAsync.argtypes = [wintypes.HWND, ctypes.c_int] +user.GetWindowTextW.argtypes = [wintypes.HWND, wintypes.LPWSTR, ctypes.c_int] +user.BringWindowToTop.argtypes = [wintypes.HWND] +user.AttachThreadInput.argtypes = [wintypes.DWORD, wintypes.DWORD, wintypes.BOOL] +user.SetWindowPos.argtypes = [wintypes.HWND, wintypes.HWND, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, wintypes.UINT] +original_window = user.GetForegroundWindow() + +def pid_for_window(window): + pid = wintypes.DWORD() + user.GetWindowThreadProcessId(window, ctypes.byref(pid)) + return pid.value + +def foreground_pid(): + return pid_for_window(user.GetForegroundWindow()) + +callback_type = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM) +windows = [] +background_windows = [] +@callback_type +def collect(window, parameter): + if user.IsWindowVisible(window): + title = ctypes.create_unicode_buffer(512) + user.GetWindowTextW(window, title, len(title)) + if pid_for_window(window) == editor_pid and 'staff-project' in title.value: + windows.append(window) + elif pid_for_window(window) != editor_pid and 'gwt' in title.value.lower(): + background_windows.append(window) + return True +user.EnumWindows(collect, 0) +assert windows, 'Owned graphical Editor window must exist' +editor_window = windows[0] +if pid_for_window(original_window) == editor_pid and background_windows: + original_window = background_windows[0] +assert original_window and pid_for_window(original_window) != editor_pid, 'Need a real background window distinct from Editor' + +def activate_window(window): + user.ShowWindowAsync(window, 9) + user.SwitchToThisWindow(window, True) + user.SetForegroundWindow(window) + +def ensure_focus(focus, pid): + assert pid == editor_pid + deadline = time.monotonic() + 5 + while not bench.focus_matches(focus, pid, foreground_pid()): + if time.monotonic() >= deadline: + raise RuntimeError('Unable to establish actual Windows ' + focus + ' focus') + if focus == 'frontmost': + activate_window(editor_window) + else: + user.ShowWindowAsync(editor_window, 6) + time.sleep(0.05) + +bench.ensure_focus = ensure_focus +bench._focus.frontmost_pid = foreground_pid + +class WindowsOfficialShell(comparison.OfficialShell): + def __init__(self, argv, environment, timeout): + super().__init__(argv, environment, timeout) + self.lines = queue.Queue() + def read(): + for line in iter(self.process.stdout.readline, b''): + self.lines.put(line) + self.lines.put(None) + self.reader = threading.Thread(target=read, daemon=True) + self.reader.start() + + def request(self, argv): + self.sequence += 1 + identity = str(self.sequence) + self.process.stdin.write((json.dumps({'id': identity, 'argv': argv}) + '\n').encode()) + self.process.stdin.flush() + try: + line = self.lines.get(timeout=self.timeout) + except queue.Empty: + raise TimeoutError('Official native Windows NDJSON timed out') + if line is None: + raise RuntimeError('Official native Windows NDJSON closed') + result = json.loads(line) + if result.get('id') != identity or result.get('exitCode') != 0: + raise ValueError('Invalid official NDJSON response: ' + str(result)) + envelope = result.get('envelope', {}) + if envelope.get('success') is not True: + raise ValueError('Official request failed: ' + str(envelope)) + return envelope + +comparison.OfficialShell = WindowsOfficialShell +editor = bench.Editor(args, env) +metadata = {'started_at': datetime.now(timezone.utc).isoformat(), 'os': platform.platform(), 'arch': platform.machine(), 'logical_cpus': os.cpu_count(), 'unity': '6000.4.4f1', 'editor_pid': editor_pid, 'iterations': 100, 'warmup': 3, 'unity_cli_build': 'native Windows debug 0.18.1', 'official_cli_version': '1.0.0-beta.11', 'pipeline_version': '0.8.0-exp.1', 'unity_cli_sha256': hashlib.sha256(Path(args.unity_cli).read_bytes()).hexdigest(), 'official_cli_sha256': hashlib.sha256(Path(args.official).read_bytes()).hexdigest(), 'benchmark_sha256': hashlib.sha256((root / 'scripts/bench-compare-official.py').read_bytes()).hexdigest(), 'windows_adapter_sha256': hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), 'windows_adapter': 'Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.', 'background_condition': 'Owned Editor minimized, because Windows refused activation of the existing GWT background window. This differs from macOS visible-background measurements.', 'host_contention': 'Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.'} +reports = [] +try: + info = editor.setup() + result = subprocess.run([args.official, 'command', 'editor_status', '--project-path', str(project), '--format', 'json'], cwd=root, env=env, capture_output=True, text=True, encoding='utf-8', timeout=60) + assert result.returncode == 0, result.stdout + result.stderr + comparison.check_official('editor_status', result.stdout) + metadata['coexistence'] = comparison.verify_coexistence(args.project, info, json.loads(result.stdout)['data']['result']) + metadata['play_settings'] = editor.raw('get_project_settings', {'includeEditor': True})['editor'] + daemon_before = editor.command(['unityd', 'status']) + assert daemon_before['running'] and daemon_before.get('connections', 0) > 0 + metadata['unityd_pid'] = daemon_before['pid'] + for mode in ['process', 'resident']: + for focus in ['frontmost', 'background']: + if mode == 'process': + previous = json.loads((out / (mode + '-' + focus + '.json')).read_text(encoding='utf-8')) + assert previous['status'] == 'PASS' + reports.append({'mode': mode, 'focus': focus, 'status': 'PASS', 'source': 'previous completed run, original conditions preserved'}) + continue + args.focus = focus + report = {'mode': mode, 'focus': focus, 'started_at': datetime.now(timezone.utc).isoformat(), 'conditions': metadata} + try: + measure = comparison.measure_process if mode == 'process' else comparison.measure_resident + samples, details = measure(args, env, editor, bench, editor_pid) + assert editor.command(['unityd', 'status'])['pid'] == daemon_before['pid'], 'Same warm unityd must survive' + assert all(len(values) == 100 for by_operation in samples.values() for values in by_operation.values()) + report.update(status='PASS', samples_ms=samples, details=details, results={name: {operation: comparison.summarize(values) for operation, values in operations.items()} for name, operations in samples.items()}) + except Exception as error: + report.update(status='FAIL', error=str(error)) + report['finished_at'] = datetime.now(timezone.utc).isoformat() + (out / (mode + '-' + focus + '.json')).write_text(json.dumps(report, indent=2), encoding='utf-8') + reports.append({'mode': mode, 'focus': focus, 'status': report['status'], 'error': report.get('error')}) + (out / 'summary.json').write_text(json.dumps({'conditions': metadata, 'runs': reports}, indent=2), encoding='utf-8') + print(mode, focus, report['status'], report.get('error', ''), flush=True) + if report['status'] != 'PASS': + raise RuntimeError(report['error']) +finally: + try: + if editor.raw('get_editor_state', {})['state']['isPlaying']: + bench.transition(editor.raw, False) + editor.restore_play_focus() + finally: + user.ShowWindowAsync(editor_window, 9) + if user.IsWindow(original_window): + activate_window(original_window) diff --git a/docs/verification/issue-386/resume/windows-player-graphical.json b/docs/verification/issue-386/resume/windows-player-graphical.json new file mode 100644 index 00000000..94c7e24a --- /dev/null +++ b/docs/verification/issue-386/resume/windows-player-graphical.json @@ -0,0 +1,26 @@ +{ + "started_at": "2026-10-03T21:56:57.372479+00:00", + "argv": [ + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player.exe", + "-screen-fullscreen", + "0", + "-screen-width", + "640", + "-screen-height", + "360", + "-logFile", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\graphical-launch.txt" + ], + "exe_sha256": "413a04009d5fc13e03fe4e5c6941a8606c63c103edd08853efc6c9bd57e6151b", + "passed": true, + "player_pid": 14980, + "visible_owned_window": true, + "pixels": { + "width": 640, + "height": 360, + "sampledChannelRange": 164 + }, + "png_sha256": "5680ebd152535218ac43870615c74e4ec0ea185751d762043176312b3cd5b32e", + "observation": "Windows Player rendered varying pixels in its visible client area; gameplay input was not tested", + "finished_at": "2026-10-03T21:57:03.031333+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/windows-player-result.json b/docs/verification/issue-386/resume/windows-player-result.json new file mode 100644 index 00000000..f45d2a18 --- /dev/null +++ b/docs/verification/issue-386/resume/windows-player-result.json @@ -0,0 +1,231 @@ +{ + "started_at": "2026-10-03T21:43:12.770455+00:00", + "binary_sha256": "1d176023f684dbe5fb3f0ae8d23222960d5618c4e3a8a03ae3535994891a8d72", + "passed": true, + "target": "StandaloneWindows64", + "build": { + "artifacts": [ + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\globalgamemanagers", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\globalgamemanagers.assets", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\globalgamemanagers.assets.resS", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\level0", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\resources.assets", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\resources.assets.resS", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Resources\\unity_builtin_extra", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\RuntimeInitializeOnLoads.json", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\ScriptingAssemblies.json", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\sharedassets0.assets", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\sharedassets0.assets.resS", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\boot.config", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Assembly-CSharp.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Mono.Security.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\mscorlib.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\netstandard.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Newtonsoft.Json.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.ComponentModel.Composition.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Configuration.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Core.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Data.DataSetExtensions.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Data.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Drawing.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.EnterpriseServices.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.IO.Compression.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.IO.Compression.FileSystem.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.IO.Hashing.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Memory.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Net.Http.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Numerics.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Runtime.CompilerServices.Unsafe.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Runtime.Serialization.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Security.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.ServiceModel.Internals.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Transactions.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Xml.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\System.Xml.Linq.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Addressables.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.AI.Navigation.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Burst.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Burst.Unsafe.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Collections.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Collections.LowLevel.ILSupport.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.InputSystem.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.InputSystem.ForUI.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.InternalAPIEngineBridge.004.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.InternalAPIEngineBridge.RenderPipelines.Core.Runtime.Shared.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Mathematics.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.PathTracing.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Profiling.Core.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Recorder.Base.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Recorder.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipeline.Universal.ShaderLibrary.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.Core.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.Core.Runtime.Shared.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.Core.ShaderLibrary.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.GPUDriven.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.Universal.2D.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.Universal.Config.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.Universal.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.RenderPipelines.Universal.Shaders.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.ResourceManager.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.ScriptableBuildPipeline.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Scripting.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.SurfaceCache.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.TextMeshPro.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.Timeline.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.UnifiedRayTracing.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\Unity.VisualEffectGraph.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityCliBridge.Runtime.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.AccessibilityModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.AdaptivePerformanceModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.AIModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.AMDModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.AndroidJNIModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.AnimationModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ARModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.AssetBundleModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.AudioModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ClothModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ClusterInputModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ClusterRendererModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ContentLoadModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.CoreModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.CrashReportingModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.DirectorModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.DSPGraphModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.GameCenterModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.GIModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.GraphicsStateCollectionSerializerModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.GridModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.HierarchyCoreModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.HierarchyModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.HotReloadModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.IdentifiersModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ImageConversionModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.IMGUIModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.InputForUIModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.InputLegacyModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.InputModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.InsightsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.JSONSerializeModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.LocalizationModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.MarshallingModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.MultiplayerModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.NVIDIAModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ParticleSystemModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.PerformanceReportingModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.Physics2DModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.PhysicsBackendPhysXModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.PhysicsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.PropertiesModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.RenderAs2DModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ScreenCaptureModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ScriptingModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.ShaderVariantAnalyticsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.SharedInternalsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.SpriteMaskModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.SpriteShapeModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.StreamingModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.SubstanceModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.SubsystemsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.TerrainModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.TerrainPhysicsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.TextCoreFontEngineModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.TextCoreTextEngineModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.TextRenderingModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.TilemapModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.TLSModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UI.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UIElementsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UIModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UmbraModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityAnalyticsCommonModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityAnalyticsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityConnectModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityConsentModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityCurlModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityWebRequestAssetBundleModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityWebRequestAudioModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityWebRequestModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityWebRequestTextureModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.UnityWebRequestWWWModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.VectorGraphicsModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.VehiclesModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.VFXModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.VideoModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.VirtualTexturingModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.VRModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.WindModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Managed\\UnityEngine.XRModule.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Plugins\\x86_64\\lib_burst_generated.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\app.info", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player_Data\\Resources\\unity default resources", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player.exe", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\AMDUnityPlugin.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\dstorage.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\dstoragecore.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\EmbedRuntime\\mono-2.0-bdwgc.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\EmbedRuntime\\MonoPosixHelper.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\2.0\\Browsers\\Compat.browser", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\2.0\\DefaultWsdlHelpGenerator.aspx", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\2.0\\machine.config", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\2.0\\settings.map", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\2.0\\web.config", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.0\\Browsers\\Compat.browser", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.0\\DefaultWsdlHelpGenerator.aspx", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.0\\machine.config", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.0\\settings.map", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.0\\web.config", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.5\\Browsers\\Compat.browser", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.5\\DefaultWsdlHelpGenerator.aspx", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.5\\machine.config", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.5\\settings.map", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\4.5\\web.config", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\browscap.ini", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\config", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\MonoBleedingEdge\\etc\\mono\\mconfig\\config.xml", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\nvngx_dlss.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\NVUnityPlugin.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\UnityCrashHandler64.exe", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\UnityPlayer.dll", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\D3D12\\D3D12Core.dll" + ], + "buildId": "775f6d4a8e374694be6bb3f948c7d451", + "changedProjectSettings": [], + "durationSeconds": 104.8804861, + "errors": [], + "outputPath": "/.cache/issue-386/resume/player-output/WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d/Player.exe", + "reportResult": "Succeeded", + "scenes": [ + "Assets/Scenes/Generated/E2E/WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d.unity" + ], + "startedAt": "2026-10-03T21:43:14.0725935Z", + "state": "succeeded", + "target": "StandaloneWindows64", + "totalErrors": 0, + "totalWarnings": 6, + "warnings": [ + "Assets\\Scripts\\UnityCliUiTest\\UnityCliUGuiTestSceneController.cs(31,31): warning CS0618: 'Object.FindFirstObjectByType()' is obsolete: 'FindFirstObjectByType has been deprecated because it relies on instance ID ordering. Use FindAnyObjectByType instead, which does not depend on ordering.'", + "Assets\\Scripts\\UnityCliUiTest\\UnityCliAllUiSystemsTestBootstrap.cs(39,31): warning CS0618: 'Object.FindFirstObjectByType()' is obsolete: 'FindFirstObjectByType has been deprecated because it relies on instance ID ordering. Use FindAnyObjectByType instead, which does not depend on ordering.'", + "Assets\\Scripts\\UnityCliPerfScenarioController.cs(190,30): warning CS0618: 'Object.FindFirstObjectByType()' is obsolete: 'FindFirstObjectByType has been deprecated because it relies on instance ID ordering. Use FindAnyObjectByType instead, which does not depend on ordering.'", + "Assets\\Scripts\\UnityCliUiTest\\UnityCliAllUiSystemsTestBootstrap.cs(66,17): warning CS0618: 'Object.FindFirstObjectByType()' is obsolete: 'FindFirstObjectByType has been deprecated because it relies on instance ID ordering. Use FindAnyObjectByType instead, which does not depend on ordering.'", + "Assets\\Scripts\\UnityCliUiTest\\UnityCliAllUiSystemsTestBootstrap.cs(301,17): warning CS0618: 'Object.FindFirstObjectByType()' is obsolete: 'FindFirstObjectByType has been deprecated because it relies on instance ID ordering. Use FindAnyObjectByType instead, which does not depend on ordering.'", + "Assets\\Scripts\\UnityCliUiTest\\UnityCliInputSimulationTestBootstrap.cs(530,31): warning CS0618: 'Object.FindFirstObjectByType()' is obsolete: 'FindFirstObjectByType has been deprecated because it relies on instance ID ordering. Use FindAnyObjectByType instead, which does not depend on ordering.'" + ] + }, + "player_pid": 49272, + "player_command": [ + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\Player.exe", + "-batchmode", + "-nographics", + "-logFile", + "\\.cache\\issue-386\\resume\\player-output\\WindowsPlayer_4b6c2fee84804da0a39f64ddb4dc292d\\player-launch.txt" + ], + "launch": "Windows headless Player remained alive for 5 seconds and emitted the expected engine version", + "player_log_sha256": "77db497c5cf1b497e7c753cdd202be851ade74ea9c61cf92726c500bc07fabf1", + "finished_at": "2026-10-03T21:45:05.142170+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/winget-manifest-validate.txt b/docs/verification/issue-386/resume/winget-manifest-validate.txt new file mode 100644 index 00000000..a35d5e6d --- /dev/null +++ b/docs/verification/issue-386/resume/winget-manifest-validate.txt @@ -0,0 +1 @@ +マニフェストの検証は成功しました。 diff --git a/scripts/bench-compare-official.py b/scripts/bench-compare-official.py index 886d4eed..09d8b982 100755 --- a/scripts/bench-compare-official.py +++ b/scripts/bench-compare-official.py @@ -127,7 +127,7 @@ def resident_operations(): ("save_scene", {}), ("console", {"tail": 20, "level": "log"}), ("screenshot", {"view": "game", "width": 1280, "height": 720}), - ("find_assets", {"type": "Material", "search_in": [bench.FIXTURE]}), + ("find_assets", {"type": "Material", "search_in": bench.FIXTURE}), ("copy_asset", {"asset": bench.SOURCE, "destination": bench.COPIED}), ("move_asset", {"asset": bench.COPIED, "destination": bench.MOVED}), ("delete_asset", {"asset": bench.MOVED, "confirm": True}), diff --git a/src/core/failure.rs b/src/core/failure.rs index b6438831..b9e3ec53 100644 --- a/src/core/failure.rs +++ b/src/core/failure.rs @@ -25,11 +25,15 @@ pub struct UnityCommandError { impl UnityCommandError { pub fn new(response: Value) -> Self { - let error = response + let detail = response + .as_array() + .and_then(|items| items.iter().find(|item| item["ok"] == false)) + .unwrap_or(&response); + let error = detail .get("error") .and_then(Value::as_str) .unwrap_or_else(|| { - if response + if detail .get("status") .and_then(Value::as_str) .is_some_and(|status| status.eq_ignore_ascii_case("error")) @@ -39,7 +43,7 @@ impl UnityCommandError { "Unity command failed" } }); - let code = response + let code = detail .get("code") .and_then(Value::as_str) .unwrap_or("UNKNOWN_ERROR"); @@ -150,3 +154,23 @@ pub fn batch_error(error: &Error) -> Value { let failure = classify(error); serde_json::json!({"ok":false, "code":failure.code, "error":failure.message, "details":failure.data}) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn failed_batch_preserves_first_failure_message_and_all_results() { + let response = serde_json::json!([ + {"ok": true, "result": {"message": "pong"}}, + {"ok": false, "code": "EDITOR_UNREACHABLE", "error": "Failed to connect to Unity at 127.0.0.1:9"}, + {"ok": false, "code": "UNAUTHORIZED", "error": "Missing credential"} + ]); + let error = check_response(&response).unwrap_err(); + assert!(format!("{error:#}").contains("Failed to connect to Unity at 127.0.0.1:9")); + let failure = classify(&error); + assert_eq!(failure.code, "EDITOR_UNREACHABLE"); + assert_eq!(failure.exit, exit_code::EDITOR_UNREACHABLE); + assert_eq!(failure.data, response); + } +} diff --git a/src/reference/fetcher.rs b/src/reference/fetcher.rs index d25cd432..449de131 100644 --- a/src/reference/fetcher.rs +++ b/src/reference/fetcher.rs @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use anyhow::{anyhow, Context, Result}; +use base64::Engine; pub const UNITY_CS_REFERENCE_URL: &str = "https://github.com/Unity-Technologies/UnityCsReference.git"; @@ -101,7 +102,7 @@ pub fn fetch_selected( dest, ); } - git_output(Command::new("git").arg("init").arg("--").arg(dest), "init")?; + git_output(git_command().arg("init").arg("--").arg(dest), "init")?; git_output( authenticated_git() .arg("-C") @@ -110,14 +111,14 @@ pub fn fetch_selected( "fetch", )?; git_output( - Command::new("git") + git_command() .arg("-C") .arg(dest) .args(["checkout", "--detach", "FETCH_HEAD"]), "checkout", )?; let actual = git_output( - Command::new("git") + git_command() .arg("-C") .arg(dest) .args(["rev-parse", "HEAD"]), @@ -132,13 +133,22 @@ pub fn fetch_selected( Ok(()) } -fn authenticated_git() -> Command { +fn git_command() -> Command { let mut command = Command::new("git"); + #[cfg(windows)] + command.args(["-c", "core.longpaths=true"]); command.env("GIT_TERMINAL_PROMPT", "0"); + command +} + +fn authenticated_git() -> Command { + let mut command = git_command(); if let Some(token) = github_token() { - command - .arg("-c") - .arg(format!("http.extraHeader=Authorization: token {token}")); + let credentials = + base64::engine::general_purpose::STANDARD.encode(format!("x-access-token:{token}")); + command.arg("-c").arg(format!( + "http.extraHeader=Authorization: Basic {credentials}" + )); } command } @@ -220,11 +230,7 @@ pub fn run_clone( } fn run_clone_via_git(url: &str, branch: &str, dest: &Path, depth: u32) -> Result<()> { - let mut cmd = Command::new("git"); - if let Some(token) = github_token() { - cmd.arg("-c") - .arg(format!("http.extraHeader=Authorization: token {token}")); - } + let mut cmd = authenticated_git(); cmd.arg("clone"); for arg in build_clone_args(url, branch, dest, depth) { cmd.arg(arg); @@ -536,6 +542,43 @@ mod tests { assert!(!dest.exists()); } + #[cfg(windows)] + #[test] + fn fetch_selected_checks_out_long_windows_paths_without_global_configuration() { + let _guard = env_lock().lock().unwrap(); + let _count = EnvVarGuard::set("GIT_CONFIG_COUNT", "1"); + let _key = EnvVarGuard::set("GIT_CONFIG_KEY_0", "core.longpaths"); + let _value = EnvVarGuard::set("GIT_CONFIG_VALUE_0", "false"); + let (repo, _) = fixture_repo(); + let relative = PathBuf::from("Module".repeat(7)) + .join("GraphToolkit".repeat(4)) + .join("CommandStateObserver".repeat(3)) + .join("PersistedStateComponent.cs"); + let source = repo.path().join(&relative); + fs::create_dir_all(source.parent().unwrap()).unwrap(); + fs::write(&source, "long path fixture").unwrap(); + fixture_git(repo.path(), &["-c", "core.longpaths=true", "add", "."]); + fixture_git( + repo.path(), + &["-c", "core.longpaths=true", "commit", "-m", "long path"], + ); + let selection = super::super::version::RefSelection { + source_ref: "refs/heads/6000.0".into(), + commit_sha: fixture_git(repo.path(), &["rev-parse", "HEAD"]), + exact_match: false, + selection_reason: "long Windows path fixture".into(), + }; + let root = tempfile::tempdir().unwrap(); + let dest = root.path().join("reference-cache").join("nested".repeat(8)); + assert!(dest.join(&relative).as_os_str().len() > 260); + fetch_selected(repo.path().to_str().unwrap(), &selection, &dest, true).unwrap(); + assert_eq!( + fs::read_to_string(dest.join(relative)).unwrap(), + "long path fixture" + ); + assert_eq!(env::var("GIT_CONFIG_VALUE_0").unwrap(), "false"); + } + #[test] fn build_clone_args_emits_shallow_single_branch() { let dest = PathBuf::from("/tmp/unity-cs-reference/2023.2.20f1"); @@ -602,6 +645,49 @@ mod tests { assert_eq!(github_token().as_deref(), Some("ghp_test_value")); } + #[test] + fn public_refs_use_basic_authentication_for_git_http() { + use std::io::Write; + use std::net::TcpListener; + + let _guard = env_lock().lock().unwrap(); + let _token = EnvVarGuard::set("GITHUB_TOKEN", "fixture-token"); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let address = listener.local_addr().unwrap(); + let server = std::thread::spawn(move || { + let (mut stream, _) = listener.accept().unwrap(); + stream + .set_read_timeout(Some(std::time::Duration::from_secs(10))) + .unwrap(); + let mut request = Vec::new(); + while !request.ends_with(b"\r\n\r\n") { + let mut byte = [0]; + stream.read_exact(&mut byte).unwrap(); + request.push(byte[0]); + } + let reference = format!("{} refs/heads/6000.4\0multi_ack\n", "a".repeat(40)); + let body = format!( + "001e# service=git-upload-pack\n0000{:04x}{}0000", + reference.len() + 4, + reference + ); + write!(stream, "HTTP/1.1 200 OK\r\nContent-Type: application/x-git-upload-pack-advertisement\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}", body.len(), body).unwrap(); + String::from_utf8(request).unwrap() + }); + let refs = list_public_refs(&format!("http://{address}/fixture.git")).unwrap(); + let request = server.join().unwrap(); + assert!( + request.lines().any(|line| line.eq_ignore_ascii_case( + "Authorization: Basic eC1hY2Nlc3MtdG9rZW46Zml4dHVyZS10b2tlbg==" + )), + "Git HTTP must authenticate with username and token credentials" + ); + assert!(refs + .iter() + .any(|reference| reference.name == "refs/heads/6000.4" + && reference.commit_sha == "a".repeat(40))); + } + #[test] fn ensure_git_available_succeeds_in_test_env() { ensure_git_available().expect("git is expected on dev/CI environment"); diff --git a/tasks/lessons.md b/tasks/lessons.md index e6e8ba62..73640d5f 100644 --- a/tasks/lessons.md +++ b/tasks/lessons.md @@ -84,3 +84,10 @@ - Context: gwt の Session 紐付け不整合で停止後、PM が workspace/build/verify の失敗を blocker にせず、直接実装・検証・push して「PR作成可」を報告するよう裁定した。 - Rule: 明示された復旧裁定がある場合は、失敗したライフサイクル操作を繰り返して停止せず、裁定の範囲で直接作業と検証を完了する。検証結果を偽装したり gwt の保護された状態ファイルを書き換えたりはしない。 - Checkpoint: 実装前の全 AC 監査、実機証跡、commit/push、Board の引き継ぎを確認する。PR 添付・レビューが残る AC は完了扱いにしない。 + +## 2026-10-04 — #386 Windows の待機条件と改行 + +- Context: 複合入力の実テストが失敗したが、表示には押下・解放カウンターが出ていた。原因は CRLF に一致しないテスト用正規表現で、読取値が0になったことだった。 +- Mistake: 実際に失敗する述語と読取値を確かめる前に、scrollやtouchの入力処理と保持時間を疑った。swipeのdurationを秒と解釈したが、実装はミリ秒だった。 +- Rule: 待機失敗は、対象の述語・表示文字列・解析値を先に照合する。Windowsの文字列解析はCRLF/LFを回帰テストに含め、パラメーターの単位はschemaと実装で確認してからfixtureを変更する。 +- Checkpoint: 1. どの待機が失敗したか記録 2. 元の表示と解析値を比較 3. 改行と単位を確認 4. 原因を再現するREDの後に最小修正 5. 元の実シナリオでGREENを確認 diff --git a/tests/auth_warning.rs b/tests/auth_warning.rs index c5d60f74..3b833f2b 100644 --- a/tests/auth_warning.rs +++ b/tests/auth_warning.rs @@ -10,7 +10,7 @@ fn legacy_opt_out_warns_on_stderr_only_for_exact_one() { ] { let mut command = Command::new(env!("CARGO_BIN_EXE_unity-cli")); command - .args(["tool", "list", "--output", "json"]) + .args(["--port", "1", "tool", "list", "--output", "json"]) .env("UNITY_CLI_NO_AUTO_UPDATE", "1") .env_remove("UNITY_CLI_ALLOW_UNAUTHENTICATED"); if let Some(value) = value { diff --git a/tests/mcp.rs b/tests/mcp.rs index 6b7af6b0..380e314d 100644 --- a/tests/mcp.rs +++ b/tests/mcp.rs @@ -123,7 +123,10 @@ fn stdio_catalog_and_failure_contract_without_editor() { .iter() .map(|t| t["name"].as_str().unwrap().to_string()) .collect(); - let list = cli().args(["tool", "list"]).output().unwrap(); + let list = cli() + .args(["--port", "1", "tool", "list"]) + .output() + .unwrap(); let mut expected: Vec<_> = String::from_utf8(list.stdout) .unwrap() .lines() From 3f9286a3be2fee36e6abbb5768b21c03545475df Mon Sep 17 00:00:00 2001 From: akiojin Date: Sun, 4 Oct 2026 10:37:00 +0900 Subject: [PATCH 07/73] docs(windows): record full CLI comparison and final GUI verification --- docs/comparison.md | 11 +- docs/verification/issue-386/README.md | 11 +- .../resume/InputActionNotificationTests.xml | 16 +- ...nAutomationPlayModeTests-counter-green.xml | 4 +- ...ionAutomationPlayModeTests-counter-red.xml | 6 +- ...ationAutomationPlayModeTests-gui-final.txt | 2 + ...ationAutomationPlayModeTests-gui-final.xml | 42 + ...InputSimulationAutomationPlayModeTests.xml | 48 +- docs/verification/issue-386/resume/README.md | 39 +- .../TouchGesturePlayModeTests-fresh.xml | 24 +- .../TouchGesturePlayModeTests-gui-final.txt | 2 + .../TouchGesturePlayModeTests-gui-final.xml | 25 + .../resume/comparison-historical-linux.txt | 10 + .../issue-386/resume/derived-lib-final.json | 18 + .../issue-386/resume/derived-plan-final.json | 1 + .../issue-386/resume/final-gui-results.json | 72 + .../resume/final-markdown-check.json | 4 +- .../issue-386/resume/markdownlint-final.txt | 2 +- ...al-windows-comparison-before-minimized.txt | 9 + ...windows-comparison-first-focus-failure.txt | 5 + .../official-windows-comparison-resident.txt | 185 + .../official-windows-resident-background.json | 5512 +++++++++++++++++ .../official-windows-resident-frontmost.json | 5481 +++++++++++++++- .../resume/official-windows-summary.json | 20 +- .../issue-386/resume/source-snapshot.json | 4 +- .../issue-386/resume/windows-comparison.md | 89 + .../issue-386/resume/winget-secret-state.json | 5 + .../issue-386/resume/winget-source-final.txt | 1 + 28 files changed, 11566 insertions(+), 82 deletions(-) create mode 100644 docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-gui-final.txt create mode 100644 docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-gui-final.xml create mode 100644 docs/verification/issue-386/resume/TouchGesturePlayModeTests-gui-final.txt create mode 100644 docs/verification/issue-386/resume/TouchGesturePlayModeTests-gui-final.xml create mode 100644 docs/verification/issue-386/resume/comparison-historical-linux.txt create mode 100644 docs/verification/issue-386/resume/derived-lib-final.json create mode 100644 docs/verification/issue-386/resume/derived-plan-final.json create mode 100644 docs/verification/issue-386/resume/final-gui-results.json create mode 100644 docs/verification/issue-386/resume/official-windows-comparison-before-minimized.txt create mode 100644 docs/verification/issue-386/resume/official-windows-comparison-first-focus-failure.txt create mode 100644 docs/verification/issue-386/resume/official-windows-resident-background.json create mode 100644 docs/verification/issue-386/resume/windows-comparison.md create mode 100644 docs/verification/issue-386/resume/winget-secret-state.json create mode 100644 docs/verification/issue-386/resume/winget-source-final.txt diff --git a/docs/comparison.md b/docs/comparison.md index 54ee44d5..cb400fd0 100644 --- a/docs/comparison.md +++ b/docs/comparison.md @@ -48,9 +48,11 @@ CLI / Bridge 0.18.1 with Unity 6000.4.4f1 verified real setup, lockfile discover OS screenshot fallback during an Editor modal, and all 23 listed operations with DisableDomainReload / PlayUnfocused. A separate Windows comparison with official CLI 1.0.0-beta.11 and Pipeline 0.8.0-exp.1 measured 100 process samples per operation -with the Editor frontmost and minimized; resident measurements are in progress. +with the Editor frontmost and minimized. Resident measurements covered all 23 +operations with 100 samples per tool and condition. [Windows timings](verification/issue-386/resume/windows-comparison.md) +record the debug build, a contended host, and the minimized background condition. The timings below remain macOS measurements. [Additional functional evidence](verification/issue-386/resume/README.md) -includes successful dedicated checks with Domain Reload enabled and disabled, +includes successful Test Runner result collection with Domain Reload enabled and disabled, Prefab, Timeline, InputActions persistence, animation, video, reference fetching, baking, real Hot Reload, and a built Windows Player. Complex input passed 11 checks after correcting the test's CRLF counter parsing. @@ -184,9 +186,10 @@ Windows の実機確認は [Issue #386 の証跡](verification/issue-386/README. CLI / Bridge 0.18.1、Unity 6000.4.4f1 で実 setup、lockfile 発見、Editor モーダル中の OS 画面取得、および DisableDomainReload / PlayUnfocused 条件で公開23操作を確認しています。 公式 CLI 1.0.0-beta.11 / Pipeline 0.8.0-exp.1 の Windows 比較では、プロセス方式を -各操作100回、Editor 前面・最小化の2条件で計測しました。常駐方式は計測中です。 +各操作100回、Editor 前面・最小化の2条件で計測しました。常駐方式も23操作を各100回完了しました。 +[Windows計測値](verification/issue-386/resume/windows-comparison.md)に、debugビルド・他の処理が稼働中のhost・最小化した背景条件を記録しています。 下の速度比較は macOS の計測です。 -[追加の機能検証](verification/issue-386/resume/README.md)では、Domain Reload 有効・無効の専用検証、 +[追加の機能検証](verification/issue-386/resume/README.md)では、Domain Reload 有効・無効でのTest Runnerの結果取得、 Prefab、Timeline、InputActions 保存、Animation、Video、Reference、Bake、実 Hot Reload、実 Windows Player が成功しました。 複合入力はテストのCRLFカウンター読取を修正して11件成功しました。Linux の画面取得ツールは TCP fixture で実画像を生成しましたが、 認証済み Linux Unity Editor、winget 導入、スタッフ原資料との網羅性確認は未検証です。 diff --git a/docs/verification/issue-386/README.md b/docs/verification/issue-386/README.md index 133e30f2..bb1c4f40 100644 --- a/docs/verification/issue-386/README.md +++ b/docs/verification/issue-386/README.md @@ -21,10 +21,13 @@ fmt / clippy と実 Unity の SceneHandlerTests 11件も成功した。 [継続検証の全コマンド・テスト名・証跡](resume/README.md)を追加した。 Prefab45+22、Timeline40、eval18+1000連続実行、InputActions保存/再起動50、動画6、Animation25+26、 参照取得/解決9、Bake4 backendの101チェック、Windows Playerの実ビルドとGUI描画が成功した。 -Domain Reload有効/無効の4件、InputActions型12・通知4、Gamepad2・Touch15も成功した。 +Test RunnerのDomain Reload有効/無効の4件、InputActions型12・通知4、Gamepad2・Touch15も成功した。 隔離したWindows x64 / FSR1.8.0で実Hot Reload25件が成功し、状態保持・部分適用・復旧を確認した。 -複合入力の失敗はCRLFを読めないテストhelperが原因で、改行回帰4件を含む11件がheadlessで成功した。 -原資料との網羅性と公式CLIのWindows比較の全条件は未確認である。 +複合入力の失敗はCRLFを読めないテストhelperが原因で、改行回帰4件を含む11件がheadlessと最終GUIで成功した。 +GUI再起動後のTouch15件・入力11件はerror / skip 0だった。 +公式CLIのWindows比較はプロセス/常駐・前面/最小化の4条件を各操作100回、計10,400測定完了。 +[Windows計測値](resume/windows-comparison.md)に全p50・p95、debugビルドとhost負荷、背景条件の違いを記録した。 +スタッフ原資料との網羅性は未確認である。 WSL Ubuntu 24.04 に各デスクトップ環境を導入し、実 CLI から grim / gnome-screenshot / spectacle と X11 の import / scrot / maim で実 PNG を生成した。 @@ -199,4 +202,4 @@ Agent Visual Check: n/a(CLI と Editor 連携を検証。Web/TUI の表示変 2. 用意した Linux Editor / Unity Hub でライセンス認証し、実 Editor を含む AC-4 を実行する。 3. winget 初回公開と `WINGET_TOKEN` の設定を行い、公開 source から install / ping を検証する。 4. 派生検証の binary-only Cargo 対応と共通検証枠を確保し、正式記録と必要なユーザー確認後に Ready PR を作成する。 -5. 原資料の全シナリオと公式CLIのWindows比較の全条件を照合する。 +5. 原資料の全シナリオを今回のWindows実測と照合し、追加の条件があれば検証する。 diff --git a/docs/verification/issue-386/resume/InputActionNotificationTests.xml b/docs/verification/issue-386/resume/InputActionNotificationTests.xml index d92b8622..07b226bf 100644 --- a/docs/verification/issue-386/resume/InputActionNotificationTests.xml +++ b/docs/verification/issue-386/resume/InputActionNotificationTests.xml @@ -21,10 +21,10 @@ [unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key press: space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key release: space (Keyboard) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverScheduledKeyboardRelease @@ -81,10 +81,10 @@ [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_DeliverTouchPhaseChanges -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.InputActionNotificationTests.EditorUpdates_PreserveOtherGamepadControls diff --git a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-green.xml b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-green.xml index ab926a83..6d8b6821 100644 --- a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-green.xml +++ b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-green.xml @@ -17,7 +17,7 @@ targetFrameRate=120, elapsed=1.005047s, frames=100 [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime [unity-cli-bridge][InputSystemHandler] Created virtual keyboard device [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) targetFrameRate=30, elapsed=1.004716s, frames=28 [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime @@ -28,7 +28,7 @@ targetFrameRate=60, elapsed=1.011087s, frames=55 [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime [unity-cli-bridge][InputSystemHandler] Created virtual keyboard device [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) targetFrameRate=-1, elapsed=1.002694s, frames=2028 [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","MouseReleases",1) diff --git a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-red.xml b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-red.xml index ca0a219b..700b2ce7 100644 --- a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-red.xml +++ b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests-counter-red.xml @@ -48,7 +48,7 @@ TouchReleases=0 TouchMaxSimultaneous=0 TouchLast=none [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime [unity-cli-bridge][InputSystemHandler] Created virtual keyboard device [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) targetFrameRate=120, elapsed=1.011509s, frames=98 [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime @@ -117,7 +117,7 @@ targetFrameRate=60, elapsed=1.009028s, frames=55 [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime [unity-cli-bridge][InputSystemHandler] Created virtual keyboard device [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (UnityCliVirtualKeyboard) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\resume\hot-reload-windows\Project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (UnityCliVirtualKeyboard) targetFrameRate=-1, elapsed=1.002823s, frames=2181 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.CreateInputSequence_AppliesDelayAndFinalState +[unity-cli-bridge][InputSystemHandler] Simulating key press: A (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: A (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardAndMouseInput_AreObserved +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating text input: "Hi" (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +targetFrameRate=120, elapsed=1.013509s, frames=84 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_30Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +targetFrameRate=30, elapsed=1.004072s, frames=27 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_60Fps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +targetFrameRate=60, elapsed=1.007810s, frames=51 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_UnlimitedFps_UsesElapsedTime +[unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) +[unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) +targetFrameRate=-1, elapsed=1.002497s, frames=535 +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","MouseReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","MouseReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("TouchPresses=2\nTouchReleases=1\n","TouchReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("TouchPresses=2\nTouchReleases=1\n","TouchReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1","MouseReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1","MouseReleases",1) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","TouchReleases",0) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.StatusCounterParser_HandlesLineEndings("MouseReleases=1\r\n","TouchReleases",0) + diff --git a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests.xml b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests.xml index e13936d7..f5dcc200 100644 --- a/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests.xml +++ b/docs/verification/issue-386/resume/InputSimulationAutomationPlayModeTests.xml @@ -107,14 +107,14 @@ TouchLast=0:Ended@100.0,200.0 [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.GamepadAndTouchInput_AreObserved -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.InputSimulationAutomationPlayModeTests.KeyboardHoldSeconds_120Fps_UsesElapsedTime @@ -235,10 +235,10 @@ TouchLast=0:Ended@100.0,200.0 [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) @@ -313,10 +313,10 @@ targetFrameRate=30, elapsed=1.034271s, frames=28 [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) @@ -354,10 +354,10 @@ targetFrameRate=60, elapsed=1.021651s, frames=51 [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key press: Space (Keyboard) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) [unity-cli-bridge][InputSystemHandler] Simulating key release: Space (Keyboard) diff --git a/docs/verification/issue-386/resume/README.md b/docs/verification/issue-386/resume/README.md index 211661bc..177e3f8f 100644 --- a/docs/verification/issue-386/resume/README.md +++ b/docs/verification/issue-386/resume/README.md @@ -15,11 +15,12 @@ | Python の PID 生存確認 | Windows4件、Linux3件成功・Windows専用1件skip | [Windows](python-windows.txt)、[Linux](python-linux.txt)、[最終Windows4件](process-liveness-final.txt) | | 実 Editor の公開23操作 | 23/23、各1回の機能確認 | [操作と結果](staff-final-operations.json)、[条件・バイナリ](staff-final-summary.json) | | Windows 公式 CLI 比較・プロセス方式 | 作成・階層・evalを両CLIで各100回、前面・最小化の2条件。3 warmup | [前面](official-windows-process-frontmost.json)、[最小化](official-windows-process-background.json)、[公式binary検証](official-windows-binary.json) | +| Windows 公式 CLI 比較・常駐方式 | 全23操作を両CLIで各100回、前面・最小化の2条件。3 warmup、同じunityd / shellを保持 | [前面](official-windows-resident-frontmost.json)、[最小化](official-windows-resident-background.json)、[p50・p95の全表](windows-comparison.md) | | 実 Editor モーダル / Windows GDI fallback | PNG生成、無効時 TIMEOUT | [結果](modal-summary.json) | | Prefab | 45 runtime +22 EditMode、失敗0 | [結果](prefab-results.json)、[実行ログ](prefab.txt) | | Timeline | 40 PASS / 0 FAIL | [実行ログ](timeline.txt) | | C# eval | 18 PASS / 0 FAIL、1000連続実行 | [実行ログ](eval.txt)。追加assembly4、管理memory増加2,658,304 bytes | -| Domain Reload | 有効2件・無効2件とも成功、設定復元 | [全テスト・実行条件](domain-reload.json) | +| Test Runner の Domain Reload | 有効2件・無効2件とも結果取得成功、設定復元 | [全テスト・実行条件](domain-reload.json) | | 実 Hot Reload | Windows x64 / FSR1.8.0、25 PASS / 0 FAIL | [実行ログ](hot-reload-results.txt)、[条件・終了処理](hot-reload-summary.json) | | InputActions の保存・再起動 | 50 PASS / 0 FAIL、Editor2回起動 | [実行ログ](input-actions-persistence.txt) | | InputActions の型 / 通知 | 型12件、通知4件とも成功 | [型](InputActionsHandlerTests.xml)、[通知](InputActionNotificationTests.xml) | @@ -29,8 +30,8 @@ | Bake | 4 backend、101チェック成功。保存・再読込・実NavMesh問い合わせを確認 | [実行ログ](bake-headed-final.txt)、[操作条件](bake-headed-result.json)、[実ファイルSHA256](bake-artifact-metadata.json) | | Bake / Scene の回帰テスト | 15件 /11件成功 | [Bake](BakeHandlerTests.xml)、[Scene](SceneHandlerTests.xml) | | Windows Player | 実ビルド、exe / Data / BuildReport一致、headless起動5秒、GUI描画 | [ビルド・起動](windows-player-result.json)、[640×360の描画観測](windows-player-graphical.json)。ゲーム入力は未確認 | -| Gamepad Stick / Touch | 2件 /15件成功 | [Gamepad](GamepadStickInputPlayModeTests.xml)、[Touch](TouchGesturePlayModeTests-fresh.xml) | -| 複合入力・カウンター読取 | Windows headlessで11/11成功。元の7件と改行回帰4件 | [RED: 11件中3失敗](InputSimulationAutomationPlayModeTests-counter-red.xml)、[GREEN: 11件成功](InputSimulationAutomationPlayModeTests-counter-green.xml)、[コマンド・exit](input-counter-green.json) | +| Gamepad Stick / Touch | 2件 /15件成功。最終GUI再起動後もTouch15件成功、error / skip 0 | [Gamepad](GamepadStickInputPlayModeTests.xml)、[最終Touch](TouchGesturePlayModeTests-gui-final.xml)、[条件・ソースhash](final-gui-results.json) | +| 複合入力・カウンター読取 | Windows headlessと最終GUIの双方で11/11成功。元の7件と改行回帰4件、error / skip 0 | [RED: 11件中3失敗](InputSimulationAutomationPlayModeTests-counter-red.xml)、[headless GREEN](InputSimulationAutomationPlayModeTests-counter-green.xml)、[最終GUI](InputSimulationAutomationPlayModeTests-gui-final.xml)、[条件・ソースhash](final-gui-results.json) | | Linux X11 | import / scrot / maim、12チェック成功 | [実行ログ](linux-x11-platform.txt) | | Linux Wayland | GNOME / sway(grim) / KWin(spectacle) の実PNG生成成功 | [GNOME](linux-gnome-fallback-result.json)、[grim](linux-wayland-first-results.json)、[spectacle](linux-wayland-extra-results.json) | | Linux 実 Unity | 起動exit198、認証未完了 | [匿名化した結果](linux-license.json)。上記captureはsilent TCP fixtureであり実Editorの証明ではない | @@ -65,6 +66,7 @@ UI操作なしの最初の実行はTIMEOUTだった。無人実行での成功 CRLF表示からカウンターを読み取れず0にしたことが原因だった。数値読取の`$`の前に任意の `\r`を認め、CRLF / LF / 末尾改行なし / キー欠落の4ケースを追加した。 旧正規表現では新CRLFケースと複合2件が失敗し、修正後は元の入力シナリオを含む11件が成功した。 +現在のソースをコピーしてGUI Editorを再起動した最終実行でも11件成功、error / skip 0を確認した。 入力runtime、50msのhold、ミリ秒単位のswipe20ms、元のアサーションは変更していない。 調査用のruntime変更や一時fixtureは製品差分から除外した。 @@ -74,25 +76,52 @@ CRLF表示からカウンターを読み取れず0にしたことが原因だっ 公開Linux CLIのSHA256はRelease 0.18.1の`SHA256SUMS`と一致する。 先に実行した23操作・Prefab等には、その時点のバイナリSHA256を別のJSONに保持している。 全結果を同一バイナリの実行と扱わない。 +公開ログは個人パス・ANSI表示と行末の空白を正規化した。元の実行データは`.cache/issue-386/resume`に保持している。 [スタッフ範囲の再構成](staff-scope-reconstruction.md)は#243–260 / #390–395からの推論であり、 未取得の`pm-scratch/staff-report.md`そのものではない。元の全行・印・正のシナリオとの一致は未確認。 -Windowsでの公式CLIプロセス比較は上表の2条件で計測済み、常駐23操作は計測中である。 +Windowsでの公式CLI比較はプロセス・常駐それぞれの前面・最小化、全4条件で完了した。 +合計10,400の測定値について、各操作100サンプルと全p50・p95の計算を確認した。 同じUnity6000.4.4f1のプロジェクトにBridge0.18.1とPipeline0.8.0-exp.1を入れ、 両CLIの応答からプロジェクトとUnityバージョンの一致を確認した。 背景条件は、Windowsが既存GWTウィンドウの前面化を拒否したため、自分のEditorだけを最小化した。 macOSの表示したままの背景条件とは異なる。ほかのプロジェクトの正式検証が稼働中のhostであり、 Windowsの性能予算や過去のbaselineを満たしたという結果ではない。 +[通常の背景へ切り替えられなかった実行](official-windows-comparison-before-minimized.txt)も保存している。 常駐方式の初回は、公式`find_assets`の文字列`search_in`に配列を渡して失敗した。 [失敗記録](official-windows-resident-frontmost-search-array-failure.json)を残し、 導入済みPipelineの実メソッド定義に合わせて文字列を渡すよう修正した。 [比較スクリプトの15件の回帰テスト](comparison-unit-linux.txt)も成功した。 +[既存macOS証跡と比較表の5件の検証](comparison-historical-linux.txt)も成功し、過去の表と計測値の一致を確認した。 + +Windows用の[計測アダプター](windows-comparison-adapter.py)は、既存スクリプトの操作・検証・交互順序・ +focus変化時の除外を使い、macOSのfocus取得をWindows HWNDへ、POSIXの`select`をreader threadへ置き換えた。 +実行場所は`.cache/issue-386/windows-comparison.py`で、所有するfixtureとTCP listenerのPIDを照合する。 +プロセス測定済みJSONを保持して常駐測定を再開した版を保存しており、各測定JSONのscript SHA256はその実行時の値を維持する。 +前面プロセス測定後に公式`search_in`を修正したため、全条件を同一scriptの実行とは扱わない。 正式な`verify.run`は共通host leaseを1500秒待って2回ともdeferred。 [1回目](canonical-verify.txt)、[2回目](canonical-verify-second.txt)。通常の直接実行とは区別する。 同一sessionのblocked復旧用deriveはbinary-only Cargoに`--lib`を生成し、 -[実Cargoがno library targets foundで拒否する](derived-lib-error.txt)。PMに修復裁定を依頼済み。 +[実Cargoがno library targets foundで拒否する](derived-lib-error.txt)。 +修正コミット後の[最新derive](derived-plan-final.json)も同じ`--lib`を生成し、 +[実Windows Cargoがexit101で拒否](derived-lib-final.json)した。PMに修復裁定を依頼済み。 User Verification Result: pending。Agentの描画観測を人の確認済みとは扱わない。 +最終確認でも[wingetの公開sourceはpackage not found](winget-source-final.txt)、 +[WINGET_TOKENというSecret名は未登録](winget-secret-state.json)だった。Secretの値は参照していない。 不足するLinux認証・スタッフ原資料・winget公開/Secretの操作経路・正式検証復旧が揃った後、 元資料と照合して必要なユーザー確認とReady PRへ進む。 + +## ユーザー確認の導線 + +手動起動sessionのため、正式ゲート復旧後に次の確認結果を記録する。現在は未確認である。 +コマンドはリポジトリルートのWindows PowerShellで実行する。 + +1. Build: `cargo build --bin unity-cli`でWindowsバイナリをビルドする。 +2. Launch: `target\debug\unity-cli.exe --port 6487 editor open --project-path .cache\issue-386\staff-project`で用意済みの隔離プロジェクトを開く。 +3. Navigate: `target\debug\unity-cli.exe instances list --output json`で、このプロジェクトを指す実Editorの発見を確認する。 +4. Observe: `target\debug\unity-cli.exe --port 6487 system ping`の成功と、コマンド終了後もEditorが開いていることを確認する。 + +確認項目は、実Editorのプロジェクトが隔離fixtureであること、lockfileからそのEditorを発見できること、 +CLIが終了待ちにならずpingの応答を返すこと。回答を得るまで`confirmed`とは記録しない。 diff --git a/docs/verification/issue-386/resume/TouchGesturePlayModeTests-fresh.xml b/docs/verification/issue-386/resume/TouchGesturePlayModeTests-fresh.xml index 4667fe12..39eee3b2 100644 --- a/docs/verification/issue-386/resume/TouchGesturePlayModeTests-fresh.xml +++ b/docs/verification/issue-386/resume/TouchGesturePlayModeTests-fresh.xml @@ -1,29 +1,29 @@ [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.DefaultTap_IsObservedAndReleased -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.DistinctSlots_OverlapAndRelease [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.NativeTouchControl_IsVisibleToUpdateProbe -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.RemovedDevice_DoesNotBreakSubsequentGesture -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.RemovingDevice_CancelsOnlyStartedGesture -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.SameSlotGestures_AreQueuedInOrder [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.SparseTouchId_HasOneLogicalStateEntry -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_120Fps -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_30Fps [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_Uncapped -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_120Fps -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_30Fps -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_FixedInputUpdate -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_Uncapped -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) [unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.ZeroDurationSwipe_ExposesStartEndpointAndRelease -[unity-cli-bridge][TestExecutionHandler] Persisted run state to \.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) diff --git a/docs/verification/issue-386/resume/TouchGesturePlayModeTests-gui-final.txt b/docs/verification/issue-386/resume/TouchGesturePlayModeTests-gui-final.txt new file mode 100644 index 00000000..8c4eb165 --- /dev/null +++ b/docs/verification/issue-386/resume/TouchGesturePlayModeTests-gui-final.txt @@ -0,0 +1,2 @@ +Reusing Editor (pid 28772) +15 tests, 0 failed; report: \.cache\issue-386\resume\TouchGesturePlayModeTests-gui-final.xml diff --git a/docs/verification/issue-386/resume/TouchGesturePlayModeTests-gui-final.xml b/docs/verification/issue-386/resume/TouchGesturePlayModeTests-gui-final.xml new file mode 100644 index 00000000..9cab4d3a --- /dev/null +++ b/docs/verification/issue-386/resume/TouchGesturePlayModeTests-gui-final.xml @@ -0,0 +1,25 @@ + +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.DefaultTap_IsObservedAndReleased +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.DistinctSlots_OverlapAndRelease +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.NativeTouchControl_IsVisibleToUpdateProbe +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.RemovedDevice_DoesNotBreakSubsequentGesture +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.RemovingDevice_CancelsOnlyStartedGesture +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.SameSlotGestures_AreQueuedInOrder +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.SparseTouchId_HasOneLogicalStateEntry +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_120Fps +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_30Fps +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Swipe_Uncapped +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_120Fps +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_30Fps +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_FixedInputUpdate +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.Tap_Uncapped +[unity-cli-bridge][TestExecutionHandler] Persisted run state to <workspace>\.cache\issue-386\staff-project\.unity\tests\test-run-state.json (status=running) +[unity-cli-bridge][TestExecutionHandler] Test started: UnityCliBridge.Tests.PlayMode.TouchGesturePlayModeTests.ZeroDurationSwipe_ExposesStartEndpointAndRelease + diff --git a/docs/verification/issue-386/resume/comparison-historical-linux.txt b/docs/verification/issue-386/resume/comparison-historical-linux.txt new file mode 100644 index 00000000..d478dc5e --- /dev/null +++ b/docs/verification/issue-386/resume/comparison-historical-linux.txt @@ -0,0 +1,10 @@ +test_all_readmes_link_comparison_and_relative_sources_exist (test_comparison_evidence.ComparisonEvidenceTests.test_all_readmes_link_comparison_and_relative_sources_exist) ... ok +test_document_tables_match_each_published_measurement (test_comparison_evidence.ComparisonEvidenceTests.test_document_tables_match_each_published_measurement) ... ok +test_each_feature_row_has_sources_in_both_languages (test_comparison_evidence.ComparisonEvidenceTests.test_each_feature_row_has_sources_in_both_languages) ... ok +test_four_runs_have_complete_raw_samples_and_correct_percentiles (test_comparison_evidence.ComparisonEvidenceTests.test_four_runs_have_complete_raw_samples_and_correct_percentiles) ... ok +test_identical_versions_and_script_and_quiet_host_are_recorded (test_comparison_evidence.ComparisonEvidenceTests.test_identical_versions_and_script_and_quiet_host_are_recorded) ... ok + +---------------------------------------------------------------------- +Ran 5 tests in 0.415s + +OK diff --git a/docs/verification/issue-386/resume/derived-lib-final.json b/docs/verification/issue-386/resume/derived-lib-final.json new file mode 100644 index 00000000..1687142b --- /dev/null +++ b/docs/verification/issue-386/resume/derived-lib-final.json @@ -0,0 +1,18 @@ +{ + "argv": [ + "cargo", + "test", + "--workspace", + "--lib", + "--all-features", + "--", + "--test-threads=1" + ], + "started_at": "2026-10-04T00:59:42.307486+00:00", + "source_commit": "d0c5ce21d85d171b285162b06edff03acdef53c9", + "canonical": false, + "exit_code": 101, + "finished_at": "2026-10-04T00:59:43.857498+00:00", + "stdout": "", + "stderr": "error: no library targets found in package `unity-cli`\n" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/derived-plan-final.json b/docs/verification/issue-386/resume/derived-plan-final.json new file mode 100644 index 00000000..78299429 --- /dev/null +++ b/docs/verification/issue-386/resume/derived-plan-final.json @@ -0,0 +1 @@ +{"exit_code":0,"ok":true,"operation":"verify.plan","output":"verify: derived matrix from changed surfaces [rust(workspace), other, docs(6)]\n - cargo fmt --all -- --check\n - cargo clippy --workspace --all-targets --all-features -- -D warnings\n - RUSTDOCFLAGS=\"-D warnings\" cargo doc --workspace --no-deps --document-private-items\n - cargo test --workspace --lib --all-features -- --test-threads=1\n - bunx markdownlint-cli2 \"docs/comparison.md\" \"docs/hot-reload.md\" \"docs/verification/issue-386/README.md\" \"docs/verification/issue-386/resume/README.md\" \"docs/verification/issue-386/resume/staff-scope-reconstruction.md\" \"packaging/winget/README.md\"\nverify: plan registered — 5 command(s) for session 58337a13-2327-417b-b9f2-9b4b847857c4 (owner #386, derived)\n"} diff --git a/docs/verification/issue-386/resume/final-gui-results.json b/docs/verification/issue-386/resume/final-gui-results.json new file mode 100644 index 00000000..8952be0a --- /dev/null +++ b/docs/verification/issue-386/resume/final-gui-results.json @@ -0,0 +1,72 @@ +[ + { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "playmode", + "--filter", + "TouchGesturePlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\TouchGesturePlayModeTests-gui-final.xml" + ], + "name": "TouchGesturePlayModeTests", + "source_hashes": { + "Editor/Handlers/InputSystemHandler.cs": "7ac08b4f3d6ae849269707f7d7db32cbdbe287617003705272e767864e6b2434", + "Tests/PlayMode/InputSimulationAutomationPlayModeTests.cs": "a2dc48d02587b040e1356ebded544702a5d847ad1bb454db71bc09b39e16a44b", + "Tests/PlayMode/TouchGesturePlayModeTests.cs": "c23e5769c36205ef9fbb41d13be465deab504a8d2aa312b30788928f5884a69e" + }, + "started_at": "2026-10-04T01:31:29.965189+00:00", + "editor": "native Windows GUI Unity 6000.4.4f1", + "exit_code": 0, + "tests": 15, + "failed": 0, + "errors": 0, + "skipped": 0, + "finished_at": "2026-10-04T01:31:54.269500+00:00" + }, + { + "argv": [ + "\\target\\debug\\unity-cli.exe", + "--port", + "6487", + "test", + "--project-path", + "\\.cache\\issue-386\\staff-project", + "--mode", + "playmode", + "--filter", + "InputSimulationAutomationPlayModeTests", + "--disable-domain-reload", + "--timeout", + "240", + "--report", + "junit", + "--output", + "\\.cache\\issue-386\\resume\\InputSimulationAutomationPlayModeTests-gui-final.xml" + ], + "name": "InputSimulationAutomationPlayModeTests", + "source_hashes": { + "Editor/Handlers/InputSystemHandler.cs": "7ac08b4f3d6ae849269707f7d7db32cbdbe287617003705272e767864e6b2434", + "Tests/PlayMode/InputSimulationAutomationPlayModeTests.cs": "a2dc48d02587b040e1356ebded544702a5d847ad1bb454db71bc09b39e16a44b", + "Tests/PlayMode/TouchGesturePlayModeTests.cs": "c23e5769c36205ef9fbb41d13be465deab504a8d2aa312b30788928f5884a69e" + }, + "started_at": "2026-10-04T01:31:54.270009+00:00", + "editor": "native Windows GUI Unity 6000.4.4f1", + "exit_code": 0, + "tests": 11, + "failed": 0, + "errors": 0, + "skipped": 0, + "finished_at": "2026-10-04T01:32:06.230517+00:00" + } +] \ No newline at end of file diff --git a/docs/verification/issue-386/resume/final-markdown-check.json b/docs/verification/issue-386/resume/final-markdown-check.json index 4f6ac307..de5a04cf 100644 --- a/docs/verification/issue-386/resume/final-markdown-check.json +++ b/docs/verification/issue-386/resume/final-markdown-check.json @@ -9,8 +9,8 @@ "packaging/winget/README.md", "tasks/lessons.md" ], - "started_at": "2026-10-04T00:07:27.072912+00:00", + "started_at": "2026-10-04T01:33:52.717106+00:00", "exit_code": 0, - "finished_at": "2026-10-04T00:07:28.544136+00:00", + "finished_at": "2026-10-04T01:33:53.455473+00:00", "log": "markdownlint-final.txt" } \ No newline at end of file diff --git a/docs/verification/issue-386/resume/markdownlint-final.txt b/docs/verification/issue-386/resume/markdownlint-final.txt index 0192bc92..8a831d38 100644 --- a/docs/verification/issue-386/resume/markdownlint-final.txt +++ b/docs/verification/issue-386/resume/markdownlint-final.txt @@ -1,4 +1,4 @@ markdownlint-cli2 v0.23.3 (markdownlint v0.41.1) Finding: docs/comparison.md docs/hot-reload.md docs/verification/issue-386/README.md docs/verification/issue-386/resume/*.md packaging/winget/README.md tasks/lessons.md -Linting: 7 files +Linting: 8 files Summary: 0 issues in 0 files diff --git a/docs/verification/issue-386/resume/official-windows-comparison-before-minimized.txt b/docs/verification/issue-386/resume/official-windows-comparison-before-minimized.txt new file mode 100644 index 00000000..1a295378 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-comparison-before-minimized.txt @@ -0,0 +1,9 @@ +done: create_gameobject +done: hierarchy +done: eval +process frontmost PASS +process background FAIL Unable to establish actual Windows background focus +Traceback (most recent call last): + File "\.cache\issue-386\windows-comparison.py", line 159, in + raise RuntimeError(report['error']) +RuntimeError: Unable to establish actual Windows background focus diff --git a/docs/verification/issue-386/resume/official-windows-comparison-first-focus-failure.txt b/docs/verification/issue-386/resume/official-windows-comparison-first-focus-failure.txt new file mode 100644 index 00000000..8001b4b6 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-comparison-first-focus-failure.txt @@ -0,0 +1,5 @@ +process frontmost FAIL Unable to establish actual Windows frontmost focus +Traceback (most recent call last): + File "\.cache\issue-386\windows-comparison.py", line 151, in + raise RuntimeError(report['error']) +RuntimeError: Unable to establish actual Windows frontmost focus diff --git a/docs/verification/issue-386/resume/official-windows-comparison-resident.txt b/docs/verification/issue-386/resume/official-windows-comparison-resident.txt index 41b7dfa3..dac073bb 100644 --- a/docs/verification/issue-386/resume/official-windows-comparison-resident.txt +++ b/docs/verification/issue-386/resume/official-windows-comparison-resident.txt @@ -21,3 +21,188 @@ resident frontmost: cycle 20/103 resident frontmost: cycle 21/103 resident frontmost: cycle 22/103 resident frontmost: cycle 23/103 +resident frontmost: cycle 24/103 +resident frontmost: cycle 25/103 +resident frontmost: cycle 26/103 +resident frontmost: cycle 27/103 +resident frontmost: cycle 28/103 +resident frontmost: cycle 29/103 +resident frontmost: cycle 30/103 +resident frontmost: cycle 31/103 +resident frontmost: cycle 32/103 +resident frontmost: cycle 33/103 +resident frontmost: cycle 34/103 +resident frontmost: cycle 35/103 +resident frontmost: cycle 36/103 +resident frontmost: cycle 37/103 +resident frontmost: cycle 38/103 +resident frontmost: cycle 39/103 +resident frontmost: cycle 40/103 +resident frontmost: cycle 41/103 +resident frontmost: cycle 42/103 +resident frontmost: cycle 43/103 +resident frontmost: cycle 44/103 +resident frontmost: cycle 45/103 +resident frontmost: cycle 46/103 +resident frontmost: cycle 47/103 +resident frontmost: cycle 48/103 +resident frontmost: cycle 49/103 +resident frontmost: cycle 50/103 +resident frontmost: cycle 51/103 +resident frontmost: cycle 52/103 +resident frontmost: cycle 53/103 +resident frontmost: cycle 54/103 +resident frontmost: cycle 55/103 +resident frontmost: cycle 56/103 +resident frontmost: cycle 57/103 +resident frontmost: cycle 58/103 +resident frontmost: cycle 59/103 +resident frontmost: cycle 60/103 +resident frontmost: cycle 61/103 +resident frontmost: cycle 62/103 +resident frontmost: cycle 63/103 +resident frontmost: cycle 64/103 +resident frontmost: cycle 65/103 +resident frontmost: cycle 66/103 +resident frontmost: cycle 67/103 +resident frontmost: cycle 68/103 +resident frontmost: cycle 69/103 +resident frontmost: cycle 70/103 +resident frontmost: cycle 71/103 +resident frontmost: cycle 72/103 +resident frontmost: cycle 73/103 +resident frontmost: cycle 74/103 +resident frontmost: cycle 75/103 +resident frontmost: cycle 76/103 +resident frontmost: cycle 77/103 +resident frontmost: cycle 78/103 +resident frontmost: cycle 79/103 +resident frontmost: cycle 80/103 +resident frontmost: cycle 81/103 +resident frontmost: cycle 82/103 +resident frontmost: cycle 83/103 +resident frontmost: cycle 84/103 +resident frontmost: cycle 85/103 +resident frontmost: cycle 86/103 +resident frontmost: cycle 87/103 +resident frontmost: cycle 88/103 +resident frontmost: cycle 89/103 +resident frontmost: cycle 90/103 +resident frontmost: cycle 91/103 +resident frontmost: cycle 92/103 +resident frontmost: cycle 93/103 +resident frontmost: cycle 94/103 +resident frontmost: cycle 95/103 +resident frontmost: cycle 96/103 +resident frontmost: cycle 97/103 +resident frontmost: cycle 98/103 +resident frontmost: cycle 99/103 +resident frontmost: cycle 100/103 +resident frontmost: cycle 101/103 +resident frontmost: cycle 102/103 +resident frontmost: cycle 103/103 +resident frontmost PASS +resident background: cycle 1/103 +resident background: cycle 2/103 +resident background: cycle 3/103 +resident background: cycle 4/103 +resident background: cycle 5/103 +resident background: cycle 6/103 +resident background: cycle 7/103 +resident background: cycle 8/103 +resident background: cycle 9/103 +resident background: cycle 10/103 +resident background: cycle 11/103 +resident background: cycle 12/103 +resident background: cycle 13/103 +resident background: cycle 14/103 +resident background: cycle 15/103 +resident background: cycle 16/103 +resident background: cycle 17/103 +resident background: cycle 18/103 +resident background: cycle 19/103 +resident background: cycle 20/103 +resident background: cycle 21/103 +resident background: cycle 22/103 +resident background: cycle 23/103 +resident background: cycle 24/103 +resident background: cycle 25/103 +resident background: cycle 26/103 +resident background: cycle 27/103 +resident background: cycle 28/103 +resident background: cycle 29/103 +resident background: cycle 30/103 +resident background: cycle 31/103 +resident background: cycle 32/103 +resident background: cycle 33/103 +resident background: cycle 34/103 +resident background: cycle 35/103 +resident background: cycle 36/103 +resident background: cycle 37/103 +resident background: cycle 38/103 +resident background: cycle 39/103 +resident background: cycle 40/103 +resident background: cycle 41/103 +resident background: cycle 42/103 +resident background: cycle 43/103 +resident background: cycle 44/103 +resident background: cycle 45/103 +resident background: cycle 46/103 +resident background: cycle 47/103 +resident background: cycle 48/103 +resident background: cycle 49/103 +resident background: cycle 50/103 +resident background: cycle 51/103 +resident background: cycle 52/103 +resident background: cycle 53/103 +resident background: cycle 54/103 +resident background: cycle 55/103 +resident background: cycle 56/103 +resident background: cycle 57/103 +resident background: cycle 58/103 +resident background: cycle 59/103 +resident background: cycle 60/103 +resident background: cycle 61/103 +resident background: cycle 62/103 +resident background: cycle 63/103 +resident background: cycle 64/103 +resident background: cycle 65/103 +resident background: cycle 66/103 +resident background: cycle 67/103 +resident background: cycle 68/103 +resident background: cycle 69/103 +resident background: cycle 70/103 +resident background: cycle 71/103 +resident background: cycle 72/103 +resident background: cycle 73/103 +resident background: cycle 74/103 +resident background: cycle 75/103 +resident background: cycle 76/103 +resident background: cycle 77/103 +resident background: cycle 78/103 +resident background: cycle 79/103 +resident background: cycle 80/103 +resident background: cycle 81/103 +resident background: cycle 82/103 +resident background: cycle 83/103 +resident background: cycle 84/103 +resident background: cycle 85/103 +resident background: cycle 86/103 +resident background: cycle 87/103 +resident background: cycle 88/103 +resident background: cycle 89/103 +resident background: cycle 90/103 +resident background: cycle 91/103 +resident background: cycle 92/103 +resident background: cycle 93/103 +resident background: cycle 94/103 +resident background: cycle 95/103 +resident background: cycle 96/103 +resident background: cycle 97/103 +resident background: cycle 98/103 +resident background: cycle 99/103 +resident background: cycle 100/103 +resident background: cycle 101/103 +resident background: cycle 102/103 +resident background: cycle 103/103 +resident background PASS diff --git a/docs/verification/issue-386/resume/official-windows-resident-background.json b/docs/verification/issue-386/resume/official-windows-resident-background.json new file mode 100644 index 00000000..a1bd9338 --- /dev/null +++ b/docs/verification/issue-386/resume/official-windows-resident-background.json @@ -0,0 +1,5512 @@ +{ + "mode": "resident", + "focus": "background", + "started_at": "2026-10-04T00:43:08.818390+00:00", + "conditions": { + "started_at": "2026-10-04T00:00:25.043499+00:00", + "os": "Windows-11-10.0.26300-SP0", + "arch": "AMD64", + "logical_cpus": 32, + "unity": "6000.4.4f1", + "editor_pid": 34324, + "iterations": 100, + "warmup": 3, + "unity_cli_build": "native Windows debug 0.18.1", + "official_cli_version": "1.0.0-beta.11", + "pipeline_version": "0.8.0-exp.1", + "unity_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", + "official_cli_sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", + "benchmark_sha256": "8b4a77c97260fec724a5d1187c1561a7a0f25d9c3734fe8eada1c0a3ca4bc1e6", + "windows_adapter_sha256": "c47d896f41e81c6db8ba63ced94e927388b55cc81796b54578b3135685929c8a", + "windows_adapter": "Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.", + "background_condition": "Owned Editor minimized, because Windows refused activation of the existing GWT background window. This differs from macOS visible-background measurements.", + "host_contention": "Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.", + "coexistence": { + "same_project": true, + "unity_version": "6000.4.4f1", + "official_state": "ready", + "project_identity_sha256": "f87f40b8af586b040ebc3f0d64bf076a0bebf421cd38cb9af459bc31f2a0c69a" + }, + "play_settings": { + "assetNamingUsesSpace": true, + "defaultBehaviorMode": "Mode3D", + "enterPlayModeOptions": "DisableDomainReload", + "enterPlayModeOptionsEnabled": true, + "prefabModeRegularEnvironment": "None", + "prefabModeUIEnvironment": "None", + "serializationMode": "ForceText", + "unityRemote": "", + "unityRemoteCompression": "", + "unityRemoteResolution": "" + }, + "unityd_pid": 56288 + }, + "status": "PASS", + "samples_ms": { + "unity-cli": { + "editor_state": [ + 123.60029999399558, + 102.08609999972396, + 230.93380001955666, + 201.9631000002846, + 348.2147000031546, + 36.12179998890497, + 546.7104999988806, + 48.864099982893094, + 116.34619999676943, + 105.47999999835156, + 631.9852999877185, + 310.12499998905696, + 113.92219999106601, + 405.79609997803345, + 135.29840001137927, + 307.83570001949556, + 232.27939999196678, + 210.46930001466535, + 426.05599999660626, + 105.5552999896463, + 826.8361999944318, + 100.06399999838322, + 41.035300004296005, + 38.13699999591336, + 411.32719998131506, + 202.55630000610836, + 118.45999999786727, + 305.99870000150986, + 122.31000000610948, + 101.03740001795813, + 434.4320000091102, + 204.70150001347065, + 108.3890000008978, + 1004.0328000031877, + 207.55159997497685, + 307.5640000170097, + 315.4836999892723, + 307.14270001044497, + 127.64470002730377, + 204.88860001205467, + 220.03600001335144, + 307.9353999928571, + 816.7226999939885, + 706.6772999824025, + 541.3767000136431, + 634.8133999854326, + 323.97280001896434, + 306.2294999836013, + 128.26729999505915, + 309.74299999070354, + 128.4289000032004, + 307.13359999936074, + 368.8362000102643, + 335.3606000018772, + 431.2031999870669, + 307.1084000112023, + 40.15759998583235, + 305.90550001943484, + 127.68760000471957, + 105.26739998022094, + 421.18780000600964, + 406.46500000730157, + 218.977000011364, + 104.82730000512674, + 219.77669998886995, + 105.40490000857972, + 1820.3703999752179, + 203.5557999915909, + 126.28090000362135, + 104.12129998439923, + 348.7765000027139, + 302.5478000054136, + 41.54899998684414, + 37.588999985018745, + 128.12060001306236, + 99.71449998556636, + 430.2912999992259, + 97.6678000006359, + 120.71659998036921, + 100.09329998865724, + 123.14320000587031, + 103.43759998795576, + 116.20940000284463, + 95.72529999422841, + 45.07680001552217, + 106.62659999798052, + 127.7952000091318, + 105.20610000821762, + 215.84920000168495, + 203.10579999932088, + 123.61180002335459, + 104.44590001134202, + 138.09690001653507, + 608.8491999835242, + 121.22879998059943, + 38.94820000277832, + 120.4804000153672, + 105.63569999067113, + 154.4869000208564, + 807.3340999835636 + ], + "hierarchy": [ + 40.62980000162497, + 400.83870000671595, + 312.7403999969829, + 100.14110000338405, + 40.91770001105033, + 39.27239999757148, + 595.601999986684, + 41.038099996512756, + 104.14589999709278, + 402.4109000165481, + 1398.2180999882985, + 299.8669999942649, + 102.35320002539083, + 101.83030000189319, + 39.516699995147064, + 300.4413999733515, + 398.81539999623783, + 291.692900005728, + 101.88659999403171, + 401.2229999934789, + 599.7502999962308, + 101.195800001733, + 40.463400015141815, + 39.606799982720986, + 401.8139000108931, + 103.45439999946393, + 304.5890999783296, + 399.4356999755837, + 299.5958999963477, + 101.56700000516139, + 600.3965999989305, + 899.072400003206, + 397.5194999948144, + 100.66759999608621, + 103.09839999536052, + 97.9100999829825, + 105.03790000802837, + 901.5735999855679, + 102.0313999906648, + 100.90609997860156, + 301.5443999902345, + 897.3343000106979, + 901.423999981489, + 702.6830999820959, + 52.35949999769218, + 582.5834000133909, + 401.6002000134904, + 304.32110000401735, + 100.56520000216551, + 299.0621000062674, + 100.03289999440312, + 602.075100003276, + 39.446900016628206, + 40.63299999688752, + 700.9872999915387, + 101.37560000293888, + 309.08910001744516, + 399.5456999982707, + 105.0344999821391, + 101.86490000342019, + 101.12159998971038, + 598.7063000211492, + 101.96810000343248, + 101.34039999684319, + 101.36269999202341, + 100.55149998515844, + 101.99899997678585, + 602.3709000146482, + 299.7660999826621, + 899.0093999891542, + 651.2907999858726, + 396.3183999876492, + 36.341700004413724, + 39.99290001229383, + 300.0861000036821, + 100.7347000122536, + 294.1988999955356, + 100.96619999967515, + 101.01439998834394, + 102.42080001626164, + 400.7695999753196, + 101.47850000066683, + 100.58520000893623, + 400.64649999840185, + 335.6610999908298, + 103.10869998647831, + 101.8671999918297, + 99.07599998405203, + 599.1988999885507, + 101.22559999581426, + 101.67279999586754, + 102.32879998511635, + 102.42480001761578, + 100.85240000626072, + 100.51769998972304, + 100.79850000329316, + 101.04619999765418, + 400.30880001722835, + 798.7540999893099, + 1300.2698000054806 + ], + "find_gameobject": [ + 40.198200003942475, + 100.68329999921843, + 885.5191000038758, + 100.70119998999871, + 38.42719999374822, + 328.20939997327514, + 100.8375000092201, + 39.87249999772757, + 99.37129999161698, + 405.4533999878913, + 105.44370001298375, + 603.5632000130136, + 303.500800015172, + 305.54540001321584, + 36.491000006208196, + 306.9202999759, + 605.7727999868803, + 406.2995999993291, + 104.80900001130067, + 306.4591999864206, + 106.73249998944812, + 304.6070999989752, + 45.28399999253452, + 39.58149999380112, + 302.734099997906, + 399.7999000130221, + 100.9292000089772, + 303.8511000049766, + 103.94030000315979, + 105.37390000536107, + 603.3592000021599, + 901.3418999966234, + 407.3291000095196, + 105.60619999887422, + 107.76879999320954, + 405.75090001220815, + 307.74699998437427, + 106.5822999808006, + 99.33500000624917, + 99.38070000498556, + 403.6199999973178, + 606.2966999888886, + 106.90869999234565, + 1507.4157000053674, + 71.94009999511763, + 320.1118000142742, + 409.7769999934826, + 403.96419999888167, + 101.7602999927476, + 405.82200000062585, + 304.42510001012124, + 604.6766999934334, + 37.8117999935057, + 365.11099999188446, + 106.71950000687502, + 305.6073999905493, + 316.2331000203267, + 307.1023999946192, + 103.63089997554198, + 104.61139999097213, + 100.1111000077799, + 604.3709999939892, + 405.2559999981895, + 105.58750000200234, + 108.3255999838002, + 407.2836000123061, + 99.70320001593791, + 305.32709998078644, + 102.8655000263825, + 803.1798000156414, + 37.83180000027642, + 303.04349999642, + 38.92049999558367, + 39.34649997972883, + 305.91190000995994, + 105.61599998618476, + 106.4343000180088, + 105.94749997835606, + 403.9273999806028, + 105.34420001204126, + 98.24620001018047, + 103.32229998311959, + 100.66979998373426, + 101.2674999947194, + 356.0213000164367, + 102.12510000565089, + 99.24209999735467, + 105.31970000010915, + 103.96020000916906, + 306.30769999697804, + 100.25519999908283, + 104.07820000546053, + 105.04319999017753, + 105.2227999898605, + 106.38189999735914, + 101.14390001399443, + 100.25899999891408, + 104.34299998451024, + 803.783499985002, + 707.9525999724865 + ], + "transform": [ + 39.7542999999132, + 107.24769998341799, + 44.56070001469925, + 308.7140000134241, + 46.28079998656176, + 43.5025000188034, + 408.1057999865152, + 41.89120000228286, + 306.6924000158906, + 401.7249000025913, + 103.65179998916574, + 1004.0961999911815, + 302.95479999040253, + 403.23029999854043, + 41.6992999962531, + 698.1608000060078, + 301.30089999875054, + 302.64849998638965, + 103.27089999918826, + 405.24309998727404, + 102.83209997578524, + 103.25350001221523, + 331.1952000076417, + 40.530099999159575, + 701.1148000019602, + 304.9190000165254, + 110.21699997945689, + 602.1996999916155, + 400.3030000021681, + 401.29770000930876, + 300.7623000012245, + 104.35619999771006, + 401.1291000060737, + 103.9677000080701, + 103.25139999622479, + 306.0777000209782, + 101.09139999258332, + 102.48089997912757, + 108.4415000223089, + 317.8937000047881, + 701.9722999830265, + 102.8445000119973, + 103.19329999038018, + 105.20819999510422, + 52.74540002574213, + 596.1354999744799, + 300.7194999954663, + 305.6116999941878, + 305.20909998449497, + 599.7762999904808, + 101.77989999647252, + 103.27639998286031, + 39.574299997184426, + 757.1615000197198, + 101.73939997912385, + 103.39000000385568, + 330.22959998925216, + 103.95970000536181, + 108.44559999532066, + 300.6034999853, + 308.353399974294, + 600.1191000104882, + 302.4143000075128, + 101.89250000985339, + 115.81859999569133, + 104.08170000300743, + 107.83789999550208, + 101.90159999183379, + 104.5565000094939, + 599.3805000034627, + 41.79419999127276, + 300.2093999821227, + 39.149200019892305, + 40.29649999574758, + 902.0781999861356, + 100.82170000532642, + 102.31419999036007, + 102.27649999433197, + 403.75079997465946, + 102.94000001158565, + 106.41780000878498, + 104.04160001780838, + 106.82600000291131, + 106.83929998776875, + 340.9603000036441, + 103.52800000691786, + 109.0680000197608, + 104.61170002236031, + 103.08059997623786, + 103.75520001980476, + 107.57720001856796, + 102.99479999230243, + 402.36549999099225, + 103.87590000755154, + 301.1547999922186, + 406.6471000260208, + 107.5309999869205, + 101.6685999929905, + 1203.6513999919407, + 106.05280002346262 + ], + "position": [ + 35.420000000158325, + 99.55889999400824, + 45.34559999592602, + 97.92150001158006, + 40.07109999656677, + 337.3796000087168, + 103.0505999806337, + 311.55139999464154, + 100.10569999576546, + 400.40919999592006, + 401.97550001903437, + 101.76660001161508, + 313.2374999986496, + 1300.1204999745823, + 39.77050000685267, + 1201.072199997725, + 604.0420999925118, + 399.79290001792833, + 103.86940001626499, + 301.66929998085834, + 402.233900007559, + 106.4615000213962, + 47.131900006206706, + 39.30259999469854, + 603.533299989067, + 399.8783999995794, + 302.2039999777917, + 103.7679000000935, + 302.2851999849081, + 101.32769998745061, + 1197.8272999986075, + 103.22039999300614, + 603.5846000013407, + 300.62190000899136, + 299.3315000203438, + 300.00429999199696, + 401.2265999917872, + 102.60209999978542, + 98.62030000658706, + 88.06330000516027, + 1102.6618999894708, + 100.01509997528046, + 101.80750000290573, + 102.4152000027243, + 370.54709999938495, + 51.60559999058023, + 406.46579998428933, + 399.69719998771325, + 100.96489998977631, + 301.2450000096578, + 98.63490000134334, + 100.51970000495203, + 35.66990001127124, + 1200.7422000169754, + 104.5559000049252, + 405.07849998539314, + 894.3173000006936, + 102.31069999281317, + 96.80150001076981, + 101.94469999987632, + 99.68650000519119, + 101.09199999715202, + 403.1803000252694, + 103.13110001152381, + 290.0886999850627, + 301.01310001919046, + 100.55649999412708, + 99.14200002094731, + 102.16910002054647, + 99.75900000426918, + 38.360899983672425, + 600.7325999962632, + 37.203999992925674, + 38.221800001338124, + 599.7836999886204, + 102.49800002202392, + 104.2306000017561, + 103.76579998410307, + 399.7271000116598, + 104.9166000157129, + 100.88579999865033, + 99.76139999344014, + 302.2373999992851, + 100.52880001603626, + 340.90770001057535, + 104.26009999355301, + 403.33209998789243, + 101.69400001177564, + 103.13190001761541, + 303.9760999963619, + 98.52189998491667, + 103.44430000986904, + 99.31930000311695, + 100.84110000752844, + 101.60840000025928, + 102.91180000058375, + 99.47469999315217, + 102.3849000048358, + 1207.9634999972768, + 97.94730000430718 + ], + "create_cube": [ + 39.79899999103509, + 103.87079999782145, + 44.9320999905467, + 106.5111999923829, + 36.671899986686185, + 41.287300002295524, + 102.21630000160076, + 37.993400008417666, + 104.69090001424775, + 401.59210001002066, + 102.9121000028681, + 99.39909999957308, + 590.3271000133827, + 902.3022000037599, + 36.29659998114221, + 600.9425999945961, + 601.9402999954764, + 805.070300004445, + 404.8966000264045, + 1197.73090002127, + 400.87809998658486, + 301.1482000001706, + 60.441099980380386, + 40.251700003864244, + 102.96709998510778, + 302.48260000371374, + 102.66010000486858, + 103.65959999035113, + 401.40199998859316, + 103.76249998807907, + 903.8210999860894, + 101.8692999787163, + 100.88270000414923, + 100.92229998554103, + 102.76529999100603, + 400.0710000109393, + 304.65959999128245, + 102.18990000430495, + 103.93300000578165, + 106.51400001370348, + 1401.4146000263281, + 103.87370001990348, + 403.1805999984499, + 406.9229000015184, + 60.19859999651089, + 53.692599991336465, + 306.0857000236865, + 599.702100007562, + 107.13899999973364, + 800.1347999961581, + 406.296500004828, + 109.15500001283363, + 37.583099998300895, + 100.32860000501387, + 100.70550002274103, + 299.8313000134658, + 37.38400002475828, + 103.62939999322407, + 102.54009999334812, + 303.61589998938143, + 105.50550001789816, + 105.94910001964308, + 400.3001000091899, + 100.23310000542551, + 100.0173999927938, + 100.94910001498647, + 105.1986999809742, + 406.786400009878, + 103.48180000437424, + 106.46279997308739, + 49.93179999291897, + 101.80420000688173, + 38.91239999211393, + 41.042700002435595, + 103.67630000109784, + 101.75199998775497, + 101.6024999844376, + 103.30220000469126, + 305.3999000112526, + 98.74929999932647, + 105.13840001658536, + 102.0561000041198, + 101.18950001196936, + 105.24219999206252, + 969.094000000041, + 100.24940001312643, + 103.56710001360625, + 99.92519998922944, + 99.60699998191558, + 400.6021000095643, + 103.84160000830889, + 399.01930000633, + 105.60789998271503, + 103.74149997369386, + 403.84959999937564, + 402.7038000058383, + 106.88120001577772, + 403.03729998413473, + 1209.8664999939501, + 406.0569000139367 + ], + "add_component": [ + 37.187299982178956, + 100.77670001192018, + 38.52360000018962, + 301.9837999891024, + 40.58979998808354, + 312.20500002382323, + 101.2674999947194, + 38.052800024161115, + 403.45569999772124, + 301.18450001464225, + 108.27160000917502, + 404.1586999956053, + 900.5166999995708, + 300.22679999819957, + 39.82850001193583, + 104.83789999852888, + 1197.8219999873545, + 898.7537999928463, + 104.28470000624657, + 600.9563999832608, + 401.36139999958687, + 102.37939999205992, + 38.602599990554154, + 338.06139999069273, + 100.94289999688044, + 600.1351999875624, + 303.5737999889534, + 101.53780001564883, + 1196.9687000091653, + 102.06820000894368, + 100.97550001228228, + 102.69480000715703, + 99.9456999998074, + 100.53009999683127, + 102.2145000169985, + 299.221099994611, + 98.42359999311157, + 301.32950001279823, + 101.38649999862537, + 327.1169999788981, + 1197.999299998628, + 101.65440000128001, + 101.99380002450198, + 98.77490001963452, + 58.5838999832049, + 44.99080000096001, + 600.4723000223748, + 702.8290000162087, + 301.6279000148643, + 99.76330000790767, + 399.86199999111705, + 99.70290001365356, + 38.75750000588596, + 102.70759998820722, + 403.5390999924857, + 403.2352000067476, + 40.549400000600144, + 100.92870000516996, + 403.45730000990443, + 400.82059998530895, + 299.85179999493994, + 103.75430001295172, + 300.7725000206847, + 102.86270000506192, + 101.57309999340214, + 305.5932999996003, + 102.03089998685755, + 99.72280001966283, + 102.10009998991154, + 99.74609999335371, + 46.21899998164736, + 101.93630002322607, + 37.20769999199547, + 38.538900000276044, + 101.3395999907516, + 307.36249999608845, + 101.15659999428317, + 100.761900015641, + 598.8934000197332, + 401.51049999985844, + 101.70400000060908, + 101.79830002016388, + 100.6995000061579, + 402.39829997881316, + 621.871800016379, + 100.40540000773035, + 99.31160000269301, + 300.7447000127286, + 100.97280002082698, + 300.3292000212241, + 300.70409999461845, + 100.47480001230724, + 102.00749998330139, + 97.9695999994874, + 99.87010000622831, + 299.6143999916967, + 115.54240001714788, + 400.2794999978505, + 297.2506000078283, + 100.77920000185259 + ], + "remove_component": [ + 327.7241000032518, + 100.59079999336973, + 40.58450000593439, + 400.2089999848977, + 36.418900010176, + 348.1616000062786, + 300.52690001321025, + 332.7139999892097, + 399.05360000557266, + 400.89969997643493, + 395.92670000274666, + 98.20209999452345, + 301.7684000078589, + 102.96819999348372, + 37.0489000051748, + 99.72189998370595, + 101.17650000029244, + 601.5674000082072, + 96.10019999672659, + 99.86410001874901, + 903.0206000024918, + 99.40750000532717, + 36.974099988583475, + 37.89190002135001, + 402.0085000083782, + 900.1072999963071, + 99.95720000006258, + 101.86779999639839, + 1196.3960000139195, + 299.4272999931127, + 100.84990001632832, + 99.83560000546277, + 104.04910001670942, + 102.09110000869259, + 299.60399999981746, + 701.346799993189, + 304.429900017567, + 100.72899999795482, + 299.51720000826754, + 101.77360000670888, + 102.19450001022778, + 302.4305999861099, + 99.86029998981394, + 98.87770001660101, + 403.3482999948319, + 344.6281999931671, + 700.4455999995116, + 603.7608000042383, + 101.27559999818914, + 100.88470001937822, + 1000.1589999883436, + 100.71960001369007, + 37.560900003882125, + 103.51570000057109, + 102.44260000763461, + 801.5567999973428, + 41.74429998965934, + 103.71610001311637, + 103.02959999535233, + 599.8547000053804, + 100.20809998968616, + 98.74290000880137, + 1198.8955999840982, + 99.40679999999702, + 101.1309000023175, + 897.0888000039849, + 298.6908000020776, + 104.20310002518818, + 101.09609999926761, + 98.37420002440922, + 37.289899977622554, + 100.89589998824522, + 36.564000009093434, + 36.77299999981187, + 108.60659999889322, + 94.78670000680722, + 398.9544000069145, + 402.35479999682866, + 1001.5232000150718, + 102.60859999107197, + 304.91219999385066, + 101.81140000349842, + 104.72079997998662, + 101.66499999468215, + 35.57810001075268, + 100.06180001073517, + 403.1321999791544, + 104.24420001800172, + 99.33170001022518, + 702.0825000072364, + 100.9974000044167, + 401.9918999983929, + 102.4877000018023, + 102.12270001647994, + 301.7366999993101, + 1005.607200000668, + 87.82860002247617, + 300.68310000933707, + 305.12309999903664, + 402.3002000176348 + ], + "delete_gameobject": [ + 36.689799977466464, + 99.36759999254718, + 43.62250000122003, + 598.9119999867398, + 342.2073000110686, + 630.0147000001743, + 101.04989999672398, + 38.999400014290586, + 906.1779000039678, + 599.9389000062365, + 99.59140000864863, + 400.40980000048876, + 99.18579997611232, + 99.81410001637414, + 305.4317999922205, + 100.29400000348687, + 99.25589998601936, + 100.65870001562871, + 101.76040002261288, + 100.91290000127628, + 602.9228999977931, + 399.4168999779504, + 40.02580000087619, + 39.82720000203699, + 100.31949999392964, + 102.96829999424517, + 300.646699994104, + 303.16120001953095, + 498.61799998325296, + 102.06810000818223, + 103.98729998269118, + 401.16489998763427, + 98.719900008291, + 303.05950000183657, + 101.61330000846647, + 302.5993999908678, + 405.47300002072006, + 101.12139998818748, + 100.47500001383014, + 101.87019998556934, + 99.00509999715723, + 103.75070001464337, + 400.096700002905, + 399.20519999577664, + 67.95619998592883, + 49.575099983485416, + 598.1172999890987, + 100.4831999889575, + 302.9911999765318, + 100.83359997952357, + 698.880999989342, + 301.2787999759894, + 44.36689999420196, + 101.0950000199955, + 100.98580000340007, + 102.26700000930578, + 39.8847000033129, + 101.1587000102736, + 100.39810001035221, + 598.2980000262614, + 298.51150000467896, + 300.8638999890536, + 597.3147999902721, + 101.04370000772178, + 299.5932000048924, + 900.848200020846, + 106.92590000689961, + 402.7912000019569, + 302.7623000089079, + 101.05510000721551, + 37.53100000903942, + 102.83210000488907, + 37.97149998717941, + 37.67099999822676, + 93.92730001127347, + 100.12310001184233, + 99.59950001211837, + 101.51999999652617, + 300.1896000059787, + 99.73700001137331, + 100.03119998145849, + 101.06759998598136, + 303.02980000851676, + 99.72170001128688, + 37.33230000943877, + 102.38520000712015, + 98.92040002159774, + 100.30920000281185, + 102.45460001169704, + 100.72550000040792, + 100.51880002720281, + 602.3324000125285, + 101.14799998700619, + 100.72279997984879, + 102.65739998430945, + 600.700200011488, + 98.95859999232925, + 599.3761999998242, + 95.77820001868531, + 100.87880000355653 + ], + "scene_info": [ + 35.99999999278225, + 99.8437000089325, + 35.36609999719076, + 600.1475999946706, + 41.482900007395074, + 318.7142999959178, + 102.92190001928248, + 316.97000001440756, + 1392.768599995179, + 1199.2457000014838, + 311.55320000834763, + 99.3568999983836, + 102.33339999103919, + 100.7650000101421, + 43.63279999233782, + 101.25779997906648, + 300.8153999981005, + 100.93039998901077, + 101.1620000062976, + 99.19040001113899, + 98.86009999900125, + 100.38740001618862, + 332.7312999754213, + 36.46030000527389, + 99.75839999970049, + 98.32059999462217, + 99.70190000603907, + 100.26209999341518, + 99.69959998852573, + 101.62870000931434, + 98.70919998502359, + 100.75320000760257, + 100.02799998619594, + 99.1879999928642, + 99.8216999869328, + 100.8053999976255, + 299.8260000022128, + 301.83969999779947, + 100.41929999715649, + 302.7830000210088, + 100.15790001489222, + 99.14869998465292, + 100.52629999700002, + 401.9583000044804, + 361.79639998590574, + 45.914199989056215, + 1198.2205999956932, + 400.4202000214718, + 300.7668999780435, + 99.93160000885837, + 100.92460000305437, + 99.91620000801049, + 39.42389998701401, + 297.78380002244376, + 101.3544000161346, + 101.23460000613704, + 41.601299977628514, + 101.61730000982061, + 100.43799999402836, + 300.37380001158454, + 100.71510000852868, + 99.10339998896234, + 103.33419998642057, + 405.4930999991484, + 101.51010000845417, + 100.75109999161214, + 96.6906999819912, + 97.73540002061054, + 100.42780000367202, + 300.66269999952056, + 38.37810002733022, + 99.83970000757836, + 36.70529997907579, + 38.11310001765378, + 99.12730002542958, + 100.9382999909576, + 101.17100001662038, + 101.02649999316782, + 98.82070001913235, + 102.79249999439344, + 99.681599996984, + 110.20870000356808, + 99.49839999899268, + 299.14689998258837, + 39.45489999023266, + 99.24499999033287, + 301.24490000889637, + 99.98620001715608, + 98.84239998064004, + 99.41309998976067, + 299.55719999270514, + 1296.1942999972962, + 100.0476999906823, + 100.39199999300763, + 299.493500002427, + 598.7959999765735, + 399.5164000079967, + 101.00760002387688, + 402.8188000083901, + 301.95299998740666 + ], + "scene_save": [ + 132.17749999603257, + 193.31600001896732, + 428.46749999444, + 193.78349999897182, + 131.20050000725314, + 682.3491000104696, + 490.1704999792855, + 131.9301999756135, + 993.4669999929611, + 192.1740000252612, + 491.4901999873109, + 495.9699000173714, + 490.0637000100687, + 196.19660000898875, + 125.83920001634397, + 189.29790001129732, + 190.7651999790687, + 490.653899993049, + 490.89819999062456, + 497.07880002097227, + 200.56490000570193, + 393.38819999829866, + 124.36300000990741, + 129.77739999769256, + 393.2660999998916, + 192.95309999142773, + 388.2580000208691, + 195.39599999552593, + 189.26859999191947, + 506.44800000009127, + 394.69119999557734, + 193.5360000061337, + 218.06930002640001, + 198.00440000835806, + 393.7745000002906, + 195.2521000057459, + 389.6106000174768, + 193.98869998985901, + 187.49929999466985, + 187.12200000300072, + 410.1538000104483, + 197.73249997524545, + 494.2217000061646, + 499.285099998815, + 148.12980001443066, + 130.42939998558722, + 195.98830002360046, + 198.06840000092052, + 785.9466999943834, + 191.3326999929268, + 189.80930000543594, + 190.66229998134077, + 130.35089999902993, + 198.90670001041144, + 189.87420000485145, + 189.18340001255274, + 143.79159998497926, + 492.63279998558573, + 189.29609999759123, + 689.5213999960106, + 386.2346000096295, + 192.62599997455254, + 191.56989999464713, + 187.5020999868866, + 487.53729998134077, + 193.7939000199549, + 188.77159999101423, + 391.7449999717064, + 487.66399998567067, + 191.0356000007596, + 127.26750000729226, + 493.31920000258833, + 125.23570001940243, + 130.6336999987252, + 190.33240000135265, + 489.8179000010714, + 188.1860000139568, + 491.06250001932494, + 192.7422999870032, + 188.8866999943275, + 493.7853000010364, + 179.46469999151304, + 185.92209997586906, + 195.58419997338206, + 126.98280002223328, + 189.1666999727022, + 193.8166000181809, + 191.59880001097918, + 189.35940001392737, + 193.73949998407625, + 488.0047999904491, + 192.4377999966964, + 189.3598999886308, + 197.83879999886267, + 1108.4847999736667, + 193.73840000480413, + 191.15070000407286, + 190.93420001445338, + 191.97309997980483, + 486.36459998670034 + ], + "console": [ + 43.66480000317097, + 220.38139999494888, + 46.33020001347177, + 322.7513000019826, + 370.41990002035163, + 38.655700016533956, + 324.79079999029636, + 282.3078000219539, + 119.79870000504889, + 124.43250001524575, + 618.8563000177965, + 321.64899999042973, + 122.62740000733174, + 422.4091999931261, + 44.22570002498105, + 221.92700000596233, + 120.50989997806028, + 321.86840000213124, + 121.81450001662597, + 119.12600000505336, + 123.20980001823045, + 318.00480000674725, + 315.6443999905605, + 39.46530001121573, + 122.1322999917902, + 219.48229998815805, + 621.0262000095099, + 421.29870000644587, + 121.69850000645965, + 322.2419999947306, + 120.87789998622611, + 320.88839999050833, + 221.09969999291934, + 323.1306000088807, + 118.40810001012869, + 124.83280000742525, + 219.40939998603426, + 317.5792999973055, + 318.3541000180412, + 222.0188999781385, + 421.0696999798529, + 223.0795999930706, + 423.3342000225093, + 320.30910000321455, + 296.5007000020705, + 257.8194999950938, + 323.9303000154905, + 327.11789998575114, + 820.6079000083264, + 327.444700000342, + 119.20320001081564, + 423.74180001206696, + 44.84219997539185, + 418.8913000107277, + 222.26680000312626, + 323.69169997400604, + 339.2939000041224, + 120.55779999354854, + 324.56940002157353, + 121.41009999322705, + 527.7233999804594, + 118.65419999230653, + 119.93480002274737, + 118.48929998814128, + 219.10749998642132, + 119.60500001441687, + 120.03280001226813, + 320.18030001199804, + 217.44209999451414, + 120.8121000090614, + 43.91380000743084, + 117.50719998963177, + 289.8288000142202, + 39.836700016167015, + 120.82860001828521, + 121.30959998467006, + 120.13990001287311, + 322.2124000021722, + 121.52430001879111, + 321.3248000247404, + 319.73079999443144, + 220.3690999886021, + 119.44300000322983, + 219.77029999834485, + 38.299800013192, + 120.78870000550523, + 422.51890001352876, + 119.58050000248477, + 119.2692999902647, + 120.70289999246597, + 318.55840000207536, + 119.90349998814054, + 320.747100020526, + 420.0321999960579, + 118.26109999674372, + 121.5037000074517, + 119.00560001959093, + 119.32290002005175, + 328.0365999962669, + 622.7534999779891 + ], + "screenshot": [ + 441.7319999774918, + 189.7171000018716, + 134.0924999967683, + 206.1833000043407, + 497.19569997978397, + 147.27670000866055, + 393.6245999939274, + 124.1104000073392, + 205.15490000252612, + 203.3872000174597, + 1081.1282999929972, + 480.2447999827564, + 500.32829999690875, + 204.8410999996122, + 134.1670000110753, + 188.59340000199154, + 425.5270000139717, + 501.61360000493005, + 204.03490000171587, + 389.714399992954, + 196.92779998877086, + 707.944599998882, + 150.17459998489358, + 429.16880000848323, + 403.0449999845587, + 207.42389999213628, + 1502.0467000140343, + 198.8466999900993, + 189.0930999943521, + 493.47459999262355, + 410.4325999796856, + 201.70419997884892, + 204.02920001652092, + 404.7468999924604, + 404.07640000921674, + 401.33310001692735, + 399.3010000267532, + 503.8839999760967, + 199.628100002883, + 489.0634999901522, + 489.9792000069283, + 187.9526000120677, + 1386.5692999970634, + 487.8661000111606, + 831.2114000145812, + 156.89829998882487, + 195.94799997867085, + 190.32870000228286, + 197.0028999785427, + 195.74090000241995, + 206.82570000644773, + 491.7637999751605, + 150.85070001077838, + 193.2133999944199, + 201.5559999854304, + 192.46409999323077, + 141.42589998664334, + 199.98899998608977, + 207.69070001551881, + 201.99960001627915, + 695.3800999908708, + 383.6359999841079, + 202.8569999965839, + 185.8883999811951, + 484.85780000919476, + 526.6219999757595, + 511.16860000183806, + 493.22650002432056, + 481.129099993268, + 180.67359999986365, + 151.30389999831095, + 203.7253999733366, + 141.65350000257604, + 133.53139997343533, + 403.51750000263564, + 391.2113000114914, + 208.41630001086742, + 1692.372699995758, + 506.9377000036184, + 491.4926000055857, + 191.10060000093654, + 188.7319999805186, + 493.97969999699853, + 491.4641999930609, + 131.32039998890832, + 499.7531999833882, + 496.43210001522675, + 379.74859998212196, + 489.262899995083, + 200.76009997865185, + 694.4402999943122, + 195.85260000894777, + 192.0776000188198, + 188.96749999839813, + 194.986999995308, + 195.72180000250228, + 204.87560000037774, + 203.53850000537932, + 498.04669999866746, + 1699.840499990387 + ], + "material_search": [ + 45.293400005903095, + 110.77959998510778, + 213.32720000646077, + 297.53049998544157, + 198.34390000323765, + 305.8346000034362, + 193.74849999439903, + 199.55960000515915, + 297.6196999952663, + 389.79240000480786, + 1602.8014000039548, + 493.90160001348704, + 99.21980000217445, + 105.00020001200028, + 204.38410001224838, + 100.07309998036362, + 294.1751999896951, + 297.1293999871705, + 201.9202000228688, + 405.71799999452196, + 192.39179999567568, + 1096.6773000254761, + 261.6083000029903, + 290.355000004638, + 295.8578999969177, + 109.11910000140779, + 102.41619998123497, + 190.3656999929808, + 193.01869999617338, + 296.86910001328215, + 310.56809998699464, + 399.5772000052966, + 102.46870000264607, + 197.2877000225708, + 187.89259999175556, + 106.52269999263808, + 194.56519998493604, + 200.25389999500476, + 390.3072999964934, + 399.8012999945786, + 199.50960000278428, + 300.57099999976344, + 1399.7795000032056, + 293.5744999849703, + 563.1939000159036, + 236.8586999946274, + 199.45970000117086, + 200.56729999487288, + 295.14539998490363, + 104.98650002409704, + 297.4687999812886, + 192.35520000802353, + 350.20000001532026, + 391.65109998430125, + 290.4446000175085, + 294.1203999798745, + 41.516700002830476, + 105.80029999255203, + 291.3107999775093, + 97.00039998278953, + 110.40130001492798, + 99.64520001085475, + 290.94749997602776, + 199.51669999863952, + 697.5136999972165, + 296.7408999975305, + 389.30840001557954, + 199.84360001399182, + 390.62449999619275, + 298.8830000103917, + 296.46620000130497, + 100.58579998440109, + 46.02720000548288, + 40.413200011244044, + 102.43790000095032, + 101.9840000080876, + 387.90569998673163, + 204.19540000148118, + 102.02350001782179, + 193.80849998560734, + 190.20039998576976, + 98.32190000452101, + 496.4756999979727, + 799.5377999905031, + 40.92899998067878, + 99.152500013588, + 203.27480000560172, + 95.49529998912476, + 101.79350001271814, + 298.691299976781, + 492.65159998321906, + 194.1219000145793, + 96.4648999797646, + 90.01280000666156, + 93.77989999484271, + 198.05910001741722, + 97.1049000218045, + 100.13209999306127, + 306.58500001300126, + 200.8891000004951 + ], + "asset_copy": [ + 378.4809999924619, + 175.94819999067113, + 98.93320000264794, + 460.4628999950364, + 358.5282000130974, + 107.38529998343438, + 660.8035999815911, + 948.1113999790978, + 166.20089998468757, + 159.52350001316518, + 168.84939998271875, + 1067.3654999991413, + 359.34500000439584, + 360.45199999352917, + 100.44270000071265, + 159.58469998440705, + 157.8741999983322, + 360.3984999936074, + 161.95999999763444, + 159.50619999784976, + 161.83150000870228, + 161.48729997803457, + 110.86539999814704, + 101.42680001445115, + 158.99759999592789, + 457.5298000127077, + 188.0687999946531, + 161.65940000792034, + 162.04519997700118, + 358.0794000008609, + 459.64859999367036, + 168.01110000233166, + 155.67740000551566, + 760.3306000237353, + 358.3117999951355, + 362.0277000009082, + 959.5750999869779, + 363.0659999907948, + 159.75900000194088, + 760.1419000129681, + 666.1326000175904, + 360.24050001287833, + 166.41440000967123, + 458.28410002286546, + 1055.4461000137962, + 108.74130000593141, + 162.42710000369698, + 162.18880002270453, + 161.41329999663867, + 159.8013000038918, + 152.38009998574853, + 659.8703000054229, + 100.21920001599938, + 466.73099999316037, + 159.0165000234265, + 156.92330000456423, + 110.13800001819618, + 357.80299999169074, + 163.0081000039354, + 158.4203999955207, + 162.55979999550618, + 461.3690999976825, + 157.2976000024937, + 162.26710000773892, + 358.03969998960383, + 357.0850999967661, + 160.2607000095304, + 364.32930000592023, + 1557.0047999790404, + 160.49179999390617, + 102.96129999915138, + 456.38630000757985, + 94.2808999971021, + 96.1640999885276, + 160.29040000285022, + 367.63510000309907, + 162.73839998757467, + 162.62400001869537, + 159.96990000712685, + 461.17900000535883, + 459.0106999967247, + 159.49910000199452, + 960.3646000032313, + 162.22639998886734, + 97.7405000012368, + 161.0694999981206, + 159.13380001438782, + 159.93049999815412, + 159.95370000018738, + 158.26369999558665, + 163.607199996477, + 161.50590000324883, + 159.01690002647229, + 159.7862999769859, + 176.3760000176262, + 162.3375000199303, + 159.47440001764335, + 159.2833999893628, + 1166.5054000040982, + 163.8671999971848 + ], + "asset_move": [ + 92.43910000077449, + 167.01309999916703, + 88.86099999654107, + 382.2436999762431, + 365.1279999758117, + 90.49760000198148, + 1251.6909999831114, + 603.0769000062719, + 160.2818999963347, + 163.81519997958094, + 473.4611000167206, + 172.96080000232905, + 464.16179998777807, + 163.88460001326166, + 87.01930000097491, + 362.2928000113461, + 365.0192000204697, + 365.363899996737, + 165.71580001618713, + 165.66759999841452, + 473.39140000985935, + 164.30030000628904, + 591.2602999887895, + 377.2033000132069, + 374.6857999940403, + 171.40249998192303, + 165.17710001789965, + 267.0520000101533, + 176.73330000252463, + 264.1750999900978, + 368.83679998572916, + 170.31580000184476, + 263.79899997846223, + 571.0292000148911, + 300.2184000215493, + 167.44409999228083, + 271.2469999969471, + 365.09920001844876, + 362.60970000876114, + 171.80030001327395, + 667.3908999946434, + 366.25820002518594, + 167.11920002126135, + 667.917499988107, + 668.0934999894816, + 359.4124999945052, + 365.89180000009947, + 270.721400011098, + 177.45129999821074, + 362.8593999892473, + 174.9098000000231, + 663.5187000210863, + 90.92479999526404, + 366.3980000128504, + 366.74739999580197, + 361.6821000177879, + 114.44030000711791, + 183.82330000167713, + 366.2177999794949, + 361.3649000180885, + 166.4786999754142, + 178.19159998907708, + 176.0587000171654, + 363.03120001684874, + 199.5662999979686, + 366.55430000973865, + 263.9587000012398, + 1139.0324999811128, + 270.14400000916794, + 365.484199981438, + 93.27149999444373, + 163.48429999197833, + 87.73619998828508, + 88.45039998413995, + 163.50920000695623, + 465.19960000296123, + 163.42609998537228, + 465.2242000156548, + 365.9561999957077, + 1151.2416999903508, + 362.4947000062093, + 161.60459999809973, + 164.4073999777902, + 167.62749999179505, + 136.4070000126958, + 164.97919999528676, + 463.04040000541136, + 162.00539999408647, + 163.76180000952445, + 364.39960001735017, + 164.92370000923984, + 164.86200000508688, + 165.5687000020407, + 481.2067000020761, + 170.49190000398085, + 168.9930999709759, + 165.28409998863935, + 189.12510000518523, + 402.3074999859091, + 168.08420000597835 + ], + "asset_delete": [ + 335.01469998736866, + 360.4163999843877, + 365.27399998158216, + 460.84960000007413, + 1450.4981000209227, + 362.00960000860505, + 91.34670000639744, + 88.29330001026392, + 359.61939999833703, + 362.6242999744136, + 164.86170000280254, + 164.36580001027323, + 361.3744000031147, + 361.664700001711, + 81.57460001530126, + 161.17350000422448, + 361.03519998141564, + 261.4124000247102, + 261.7933999863453, + 359.58749998826534, + 161.58409998752177, + 261.28520001657307, + 1205.9608999988995, + 369.4521999859717, + 462.60410000104457, + 357.99170000245795, + 362.93259999365546, + 662.5012999866158, + 366.00690000341274, + 661.0960999969393, + 361.0301000007894, + 257.8452000161633, + 161.74409998347983, + 658.2609000033699, + 359.47460000170395, + 261.0512999817729, + 163.98700000718236, + 373.138499999186, + 360.02449999796227, + 178.0311000184156, + 558.7736000015866, + 375.8032999758143, + 477.1084999956656, + 1211.895699991146, + 1185.0417999958154, + 368.86950000189245, + 363.6518999992404, + 462.35499999602325, + 362.9926999856252, + 163.51990000111982, + 159.84029998071492, + 276.1500999913551, + 85.00719998846762, + 662.0652999845333, + 359.44849997758865, + 460.6267999915872, + 328.78439998603426, + 359.06960000284016, + 358.8045999931637, + 158.63670001272112, + 157.42269999464042, + 357.01599999447353, + 258.60289999400266, + 457.6541999995243, + 160.30239997780882, + 358.03660002420656, + 158.78550001070835, + 305.8450999960769, + 165.56340001989156, + 357.22000000532717, + 88.54450000217184, + 356.7717999976594, + 83.06740000261925, + 86.7947000078857, + 360.46019999776036, + 556.6843999840785, + 158.61889999359846, + 161.34250001050532, + 160.86279999581166, + 331.1460000113584, + 362.11260000709444, + 159.8033000191208, + 160.44750000583008, + 364.29309999221005, + 85.15980001538992, + 164.06179999466985, + 459.513900015736, + 157.54680000827648, + 158.7837999977637, + 162.72600000957027, + 161.56389997922815, + 459.1925000131596, + 259.3485999968834, + 161.36990001541562, + 162.61430000304244, + 162.01030000229366, + 158.68660001433454, + 156.37189999688417, + 180.42340001557022, + 365.520799998194 + ], + "import_settings": [ + 574.0902000106871, + 115.95889998716302, + 41.5095999778714, + 813.6405999830458, + 870.8809999807272, + 35.57939999154769, + 46.46280000451952, + 35.877899994375184, + 112.95829998562112, + 116.53410000144504, + 313.71889999718405, + 211.95510000688955, + 313.38220002362505, + 117.26919998181984, + 326.56789998873137, + 311.30319999647327, + 615.8383000001777, + 311.295199993765, + 113.03519998909906, + 114.3671999743674, + 213.22730000247248, + 116.25709998770617, + 38.76599998329766, + 37.89829998277128, + 914.8994999995921, + 114.78530001477338, + 111.43000001902692, + 613.6683000077028, + 114.42490000627004, + 1619.4430000032298, + 613.8136000081431, + 118.9306000014767, + 314.55939999432303, + 1122.817199997371, + 313.51180002093315, + 416.5396000025794, + 115.68710001301952, + 514.528599975165, + 313.1885000038892, + 115.04220002098009, + 1525.3739000181668, + 310.9076999826357, + 120.67150001530536, + 2713.0612999899313, + 604.6422999934293, + 313.7882000009995, + 415.44929999508895, + 318.23330000042915, + 113.39169999700971, + 312.80359998345375, + 313.0278999742586, + 114.56770001677796, + 36.32149999612011, + 510.6509999895934, + 313.63199997576885, + 313.51760000688955, + 37.516500015044585, + 113.32639999454841, + 1122.541499993531, + 111.1951999773737, + 114.74459999590181, + 112.35350000788458, + 113.12720002024435, + 314.81119999079965, + 110.92680000001565, + 310.0560000166297, + 212.57730000070296, + 47.28239998803474, + 116.24920001486316, + 313.1495999987237, + 39.33250001864508, + 311.784700024873, + 38.356600009137765, + 39.036500005749986, + 114.57919998792931, + 511.3091999955941, + 412.6027000020258, + 313.6880999954883, + 114.70030000782572, + 39.07460000482388, + 213.31130000180565, + 115.48760000732727, + 110.91439999290742, + 115.12160001439042, + 38.641200022539124, + 113.6306999833323, + 310.93890001648106, + 313.8604999985546, + 111.50510000879876, + 311.78959997487254, + 115.12699999730103, + 112.97790001844987, + 114.7894999885466, + 115.56020000716671, + 112.96260001836345, + 413.3543999923859, + 213.8383999990765, + 111.74570000730455, + 418.0421000055503, + 113.64180000964552 + ], + "material_modify": [ + 351.816799986409, + 421.64889999548905, + 338.202499988256, + 932.1974999911617, + 68.74230000539683, + 63.45430001965724, + 70.25940000312403, + 64.27350000012666, + 325.39519999409094, + 334.1153999790549, + 124.75170000107028, + 128.59469998511486, + 937.6907999976538, + 325.64060000004247, + 60.977799992542714, + 126.19129999075085, + 835.338300006697, + 432.7358999871649, + 126.4394000172615, + 323.5865000169724, + 131.00270001450554, + 125.41480001527816, + 58.63600000157021, + 375.6258999928832, + 124.4814999809023, + 324.5131000003312, + 126.29719998221844, + 636.308299988741, + 425.89910002425313, + 120.8514999889303, + 635.3557000111323, + 430.1712000160478, + 124.93069999618456, + 127.09910000558011, + 622.1982999995816, + 332.2010999836493, + 324.5935999730136, + 935.6838999956381, + 624.3509000050835, + 324.8913999996148, + 139.27730001159944, + 634.8944999917876, + 326.47619998897426, + 1718.3381000068039, + 79.71849999739788, + 364.9046000209637, + 935.2078000083566, + 323.56059999438, + 325.01430000411347, + 425.317899993388, + 124.80370001867414, + 123.7459999974817, + 66.52139997459017, + 326.3048999942839, + 423.1107000086922, + 323.2570000109263, + 62.749800010351464, + 422.591900016414, + 622.1623000164982, + 126.03879999369383, + 123.04330000188202, + 323.18629999645054, + 124.62210000376217, + 624.6190000092611, + 323.6619000090286, + 323.79240001318976, + 935.9594999987166, + 64.84069998259656, + 129.19869998586364, + 623.4460000123363, + 63.459400000283495, + 123.50940000033006, + 60.45980000635609, + 333.7778999994043, + 326.6801999998279, + 633.8652999838814, + 124.69409999903291, + 444.8926000040956, + 326.45449999836273, + 73.80460001877509, + 425.184799998533, + 124.22040000092238, + 125.75109998579137, + 123.28630001866259, + 62.16380000114441, + 125.8969999908004, + 324.6283000044059, + 123.49420000100508, + 125.5282000056468, + 127.62640000437386, + 128.41229999321513, + 124.53140001161955, + 125.31070000841282, + 437.17740001739, + 126.17010000394657, + 124.31859999196604, + 126.25770000158809, + 126.26230000751093, + 124.03939999057911, + 131.62269999156706 + ], + "time_settings": [ + 355.43690001941286, + 417.4910000001546, + 321.74650000524707, + 1533.4181000071112, + 47.91640001349151, + 38.13900001114234, + 343.15000000060536, + 38.112200010800734, + 418.1080000125803, + 413.5205000056885, + 314.76279997150414, + 116.13730000681244, + 1123.5101000056602, + 113.02869999781251, + 36.28589998697862, + 313.91560001065955, + 115.32830001669936, + 816.9607000018004, + 313.58560000080615, + 113.94779998227023, + 314.91009998717345, + 316.92400001338683, + 36.26819999772124, + 354.56540001905523, + 117.56990000139922, + 313.6755999876186, + 114.33420001412742, + 113.48359999828972, + 315.3691000188701, + 117.8424000099767, + 118.24129999149591, + 216.0579999908805, + 317.6997999835294, + 116.55060001066886, + 618.4747999941465, + 1229.6041000226978, + 117.01129999710247, + 920.5764000071213, + 618.2411999907345, + 111.36270000133663, + 124.7086999937892, + 815.8373999758624, + 118.99149999953806, + 39.40470001543872, + 54.9821000022348, + 331.6962000099011, + 118.72099997708574, + 612.8883000055794, + 415.7940000004601, + 617.0339999953285, + 112.57900000782683, + 112.13039999711327, + 39.455799997085705, + 115.64030000590719, + 914.8963000043295, + 615.4202000179794, + 36.05749999405816, + 314.7684000141453, + 113.97779997787438, + 112.92479999247007, + 310.7691000041086, + 114.38699997961521, + 313.7253999884706, + 117.4483000067994, + 110.22649999358691, + 614.1808000102174, + 1212.4933000013698, + 40.701999998418614, + 311.42819998785853, + 813.9237000141293, + 38.08050000225194, + 312.8179000050295, + 39.03379998519085, + 36.78199998103082, + 116.43140000524, + 114.60519998217933, + 312.67810001736507, + 320.65229999716394, + 112.64420000952668, + 35.919099987950176, + 315.2795999776572, + 112.58360001374967, + 113.72059999848716, + 116.02090002270415, + 35.78030000790022, + 311.27780000679195, + 415.79760002787225, + 114.46620000060648, + 110.87619999307208, + 314.2232999962289, + 112.45379998581484, + 112.10460000438616, + 114.43849999341182, + 111.46099999314174, + 116.60680000204593, + 113.14190001576208, + 118.9322000136599, + 113.63680000067689, + 419.7801999980584, + 113.14080000738613 + ], + "read_csharp": [ + 859.1591999866068, + 284.9821999843698, + 326.2768000131473, + 37.57680000853725, + 34.591699979500845, + 313.53859999217093, + 48.579399997834116, + 36.845399998128414, + 248.45470002037473, + 289.2431999789551, + 40.46819999348372, + 34.02940000523813, + 1139.6377000201028, + 316.23559998115525, + 34.94420001516119, + 314.08849998842925, + 49.313099996652454, + 1170.5191000073683, + 35.773999989032745, + 268.3653999993112, + 333.0813000211492, + 35.71369999554008, + 35.19550000783056, + 319.17329999851063, + 35.89180001290515, + 332.6729999971576, + 36.528099997667596, + 32.44320000521839, + 550.6504999939352, + 35.78949999064207, + 37.443699984578416, + 329.3718000059016, + 314.7857000003569, + 286.9007999834139, + 34.941199992317706, + 35.62090001651086, + 36.31110000424087, + 1124.9854000052437, + 815.6552000145894, + 31.847500009462237, + 255.578099982813, + 32.938299991656095, + 351.9345999811776, + 35.96469998592511, + 349.5706999965478, + 297.5195999897551, + 331.07479999307543, + 548.6546000174712, + 295.29849998652935, + 580.0455999851692, + 34.91950000170618, + 34.42509999149479, + 37.02810002141632, + 33.63220000755973, + 34.78389998781495, + 34.051399998134, + 34.07069999957457, + 322.7301000151783, + 33.520600001793355, + 282.44189999531955, + 36.096900003030896, + 277.8666000231169, + 34.45899998769164, + 34.203599992906675, + 36.48320000502281, + 32.652399997459725, + 34.72009999677539, + 33.16009999252856, + 31.964599998900667, + 529.3628000072204, + 33.9469000173267, + 310.87980000302196, + 34.31540000019595, + 31.679000006988645, + 294.79720001108944, + 33.39200001209974, + 290.75850002118386, + 536.1588000087067, + 258.9356999960728, + 35.89800000190735, + 574.3953000055626, + 34.02199997799471, + 33.6890000035055, + 315.4746999789495, + 32.55360000184737, + 36.2044999783393, + 317.3229999956675, + 36.16039999178611, + 34.38999998616055, + 507.5899999937974, + 32.970900007057935, + 329.42150000599213, + 35.66950000822544, + 33.90499998931773, + 48.388399998657405, + 32.02010001405142, + 34.62530000251718, + 40.85039999336004, + 425.9609000000637, + 335.47180000459775 + ], + "play_until_ready": [ + 1881.1181000201032, + 850.8548000245355, + 1841.9109999958891, + 840.4517000017222, + 815.4221000149846, + 781.8409999890719, + 781.4288999943528, + 792.111599992495, + 1401.2156999961007, + 1409.5045999856666, + 831.7513999936637, + 819.701400003396, + 807.7850999834482, + 1466.4381000038702, + 813.9654000115115, + 829.5113000203855, + 796.610099991085, + 927.9164999898057, + 801.5133000153583, + 877.113599999575, + 817.0916000090074, + 815.1889000146184, + 767.2004000050947, + 1354.4474999944214, + 816.1939000128768, + 1419.2680999985896, + 807.3737999948207, + 817.1751000045333, + 1148.151000001235, + 818.9774000202306, + 829.5080999960192, + 831.6269999777433, + 820.8744000003207, + 871.760500012897, + 822.0104000065476, + 822.2166000050493, + 813.7068999931216, + 1409.459099988453, + 1962.3946999781765, + 806.9775000039954, + 796.5517000120599, + 838.7724999920465, + 789.9322000157554, + 797.0010999997612, + 790.1977000001352, + 1526.2862000090536, + 830.530400009593, + 1090.7686999998987, + 856.5762999933213, + 878.0122000025585, + 1211.2598000094295, + 804.5028999913484, + 811.9336000236217, + 818.7733000086155, + 811.022799985949, + 825.963099981891, + 1047.4256000015885, + 1023.2937000109814, + 804.9873000127263, + 856.54139998951, + 796.9301999837626, + 1066.6341000178363, + 1101.3904999999795, + 805.5284000001848, + 812.2918000153732, + 815.1272999821231, + 821.4273999910802, + 783.7242000096012, + 815.7671000226401, + 822.8745000087656, + 776.8795000156388, + 854.0618999977596, + 756.0319999756757, + 753.2034999749158, + 1039.992700010771, + 813.3346000104211, + 1151.3738999783527, + 1418.249599984847, + 878.8890000141691, + 769.2048999888357, + 1665.499099995941, + 1103.8736999907997, + 1119.512900011614, + 838.570299994899, + 773.0282999982592, + 1217.088600009447, + 1120.0480999832507, + 802.8253000229597, + 808.5042999882717, + 832.445199979702, + 808.3641999983229, + 827.6324000034947, + 810.4952999856323, + 809.8535999888554, + 838.2763999979943, + 827.3023000219837, + 817.6856999925803, + 800.7673000101931, + 1259.3414000002667, + 815.8469999907538 + ], + "stop_until_ready": [ + 643.8065000111237, + 840.6592000101227, + 1158.618599991314, + 770.5230999854393, + 946.1123999790289, + 621.2129999767058, + 737.0272999978624, + 812.1531000069808, + 950.222199986456, + 1737.5974000024144, + 652.1316000143997, + 851.8291999935172, + 952.2095999855082, + 642.9132999910507, + 586.0776999907102, + 838.504000013927, + 662.2585000004619, + 686.2025999871548, + 837.0467000058852, + 654.003500007093, + 1541.7626000125892, + 638.8774999941234, + 574.0714000130538, + 600.1164999906905, + 769.0760999976192, + 738.1536000175402, + 854.0485999837983, + 850.634300004458, + 1347.0112000068184, + 751.8810000037774, + 1161.8556000175886, + 1241.7416000098456, + 1553.4978000214323, + 652.5712999864481, + 679.3545999971684, + 951.6385000024457, + 977.4285000166856, + 848.4098999761045, + 648.7275999970734, + 657.3881000222173, + 861.0023000219371, + 657.8124999941792, + 940.6302999996115, + 789.4452000036836, + 755.6770999799483, + 607.2669000132009, + 662.9857000079937, + 2275.1172999851406, + 738.9941000146791, + 970.8306000102311, + 638.270299998112, + 645.0284000020474, + 595.9507999941707, + 655.6438000116032, + 742.6067000196781, + 664.4221999740694, + 949.3801000062376, + 669.1808000032324, + 651.2798999901861, + 947.1278999990318, + 673.1025999761187, + 1428.6546000221279, + 838.2126000069547, + 741.3567999901716, + 841.4533000031952, + 688.6248999799136, + 951.3059000018984, + 571.4535000151955, + 662.0842000120319, + 645.194899989292, + 833.4023999923375, + 847.6889999874402, + 564.2403999809176, + 635.8059999765828, + 1233.9158999966457, + 650.1101999892853, + 644.096099975286, + 847.7308000146877, + 950.2465999976266, + 575.92519998434, + 634.6712000085972, + 936.7084999976214, + 661.8625999835785, + 646.3319000031333, + 572.1782999753486, + 1544.3340000056196, + 641.0626999859232, + 646.5462000051048, + 848.1153000029735, + 640.0495999841951, + 664.1281000047456, + 665.2354999969248, + 670.699100010097, + 666.1617999779992, + 669.2022000206634, + 885.1299000089057, + 662.3255000158679, + 658.7356000090949, + 1059.6731000114232, + 839.1197999881115 + ] + }, + "official": { + "editor_state": [ + 597.3320000048261, + 586.3020000106189, + 950.7696999935433, + 772.6898000109941, + 795.8606999891344, + 959.7544000134803, + 599.111300020013, + 781.1711000103969, + 803.126400016481, + 779.2495000176132, + 614.0141999931075, + 572.1398000023328, + 555.1306999986991, + 876.3387000071816, + 608.3178000117186, + 677.6222000189591, + 871.559100021841, + 794.0587000048254, + 989.1562999982852, + 785.6836999999359, + 711.6510999912862, + 674.101900018286, + 1195.4103999887593, + 592.1543000149541, + 532.7690000121947, + 676.8314000219107, + 578.5713999939617, + 571.6371999878902, + 695.2138000051491, + 884.9656000093091, + 802.9129999922588, + 597.3534000222571, + 793.1100999994669, + 882.7077000169083, + 782.9386999947019, + 889.1425000037998, + 600.0016999896616, + 793.0058000201825, + 601.9960999838077, + 590.6383999972604, + 1188.3649000083096, + 802.7151999995112, + 593.515499989735, + 781.0484999790788, + 896.2423999910243, + 848.8914000045042, + 705.1149000180885, + 575.4371999937575, + 899.4782000081614, + 797.0853000006173, + 809.4153999991249, + 587.3002000153065, + 694.8114999977406, + 774.6751999948174, + 895.0425999937579, + 591.3979999895673, + 904.2730000219308, + 577.2268000000622, + 614.503099990543, + 1370.1807000034023, + 905.9248999983538, + 1095.766199985519, + 609.2775999859441, + 582.8708999906667, + 1008.0596999905538, + 678.687900013756, + 893.4624000103213, + 544.9351000133902, + 885.3362000081688, + 871.9281000085175, + 789.0314999967813, + 566.6139000095427, + 714.9068000144325, + 589.817200001562, + 1094.7684999846388, + 876.3442999916151, + 598.52420000243, + 682.53759999061, + 691.6074999899138, + 857.4473000189755, + 598.7469000101555, + 771.7732999881264, + 602.8548000031151, + 675.1780000049621, + 702.4606000049971, + 581.0679999995045, + 597.6115000084974, + 891.4476999780163, + 781.076800019946, + 879.2202000040561, + 595.2875000075437, + 689.139800000703, + 610.2752999868244, + 588.1144000159111, + 596.9659000111278, + 1472.7497000130825, + 907.0889999857172, + 585.1888000033796, + 610.11460001464, + 598.220100015169 + ], + "hierarchy": [ + 608.4141999890562, + 582.8692000068258, + 554.8596000007819, + 1113.7873000116087, + 1282.1937999979127, + 1816.3681000005454, + 598.2035000051837, + 939.6684999810532, + 588.0236999946646, + 592.5061000161804, + 891.3855999999214, + 1000.229400000535, + 834.9758999829646, + 611.3834999850951, + 889.7809000045527, + 618.4686000051443, + 702.8300999954809, + 983.1547000212595, + 712.3601000057533, + 687.7360000216868, + 697.7857000019867, + 1498.4377999790013, + 598.1673000205774, + 844.0508999919984, + 719.8122999980114, + 607.708299998194, + 723.7471000116784, + 920.9944999893196, + 1216.7487999831792, + 692.2341999888886, + 601.2970000156201, + 579.1079000046011, + 1816.4755000034347, + 593.8315000094008, + 912.1613999886904, + 908.8076000043657, + 603.9357999979984, + 593.6597000109032, + 780.5656999989878, + 890.3575000003912, + 600.0174999935552, + 1371.1859000031836, + 888.6765000061132, + 1245.9740999911446, + 801.1685999808833, + 820.01590001164, + 718.1289000145625, + 811.3643000251614, + 802.5256000109948, + 988.3459999982733, + 690.3897000011057, + 889.6359000063967, + 617.4208999727853, + 800.8249999838881, + 599.2247999820393, + 800.7627000042703, + 550.0301000138279, + 599.0954000153579, + 824.6120999974664, + 607.9499999759719, + 890.9501999733038, + 587.0479999866802, + 579.5351999986451, + 594.721200002823, + 595.6116000015754, + 687.3417999886442, + 796.796299982816, + 618.4474999899976, + 604.14129999117, + 690.862699993886, + 600.2171000000089, + 806.2786000082269, + 1271.79790000082, + 601.3785999966785, + 611.2908000068273, + 706.3515999761876, + 595.486299978802, + 607.1879000228364, + 605.3377999924123, + 650.4337000078522, + 615.15500000678, + 611.2441000004765, + 582.9467999865301, + 906.3048000098206, + 919.5497999899089, + 594.743900001049, + 695.581600011792, + 885.5671999917831, + 713.3347000053618, + 605.783299979521, + 602.804299996933, + 592.2900000005029, + 587.1970999869518, + 886.6291999875102, + 716.9651999720372, + 592.4948000174481, + 1272.5940000091214, + 590.5395000008866, + 599.1428000270389, + 691.8831999937538 + ], + "find_gameobject": [ + 683.7852000026032, + 606.6578000027221, + 582.71539999987, + 985.623399988981, + 587.7690000052098, + 604.779299988877, + 594.7111999848858, + 670.9323999821208, + 903.1882999988738, + 807.1974999911617, + 892.615199991269, + 801.3341999903787, + 731.3837999827228, + 789.6925000241026, + 1800.1506000000518, + 584.7955000062939, + 1006.2900000193622, + 1042.8230999968946, + 799.5777999749407, + 617.5288000085857, + 1203.6456000059843, + 811.1371999839321, + 598.4763999877032, + 929.4232000247575, + 1238.6527999769896, + 690.2551999955904, + 685.2248000213876, + 677.84320001374, + 586.925199982943, + 1198.5204000084195, + 594.75580000435, + 903.8778000103775, + 701.3925000210293, + 711.8037000182085, + 881.2329999927897, + 998.349400004372, + 1511.8709999951534, + 595.5998999997973, + 601.8930000136606, + 1292.2444999858271, + 875.7200000109151, + 611.4131000067573, + 708.5208999924362, + 2392.8032999974675, + 1498.7578000000212, + 704.595600022003, + 872.525000013411, + 899.7459000092931, + 712.9590999975335, + 598.9517999987584, + 702.9890000121668, + 692.4518999876454, + 595.100199978333, + 1001.7169000057038, + 594.699799985392, + 897.9230999830179, + 530.961100012064, + 615.8124000066891, + 869.4946000177879, + 692.184699990321, + 912.7879999869037, + 595.4629000043496, + 606.304499990074, + 893.7001999875065, + 598.8676999986637, + 799.6362000121735, + 1214.7488000045996, + 633.8687999814283, + 679.9093000008725, + 908.4030999802053, + 1699.8817999847233, + 695.6646999751683, + 620.8959000068717, + 687.5337000237778, + 612.2806000057608, + 994.0152999770362, + 610.4304000036791, + 595.6953999993857, + 701.5745000098832, + 551.1612999835052, + 592.8053999959957, + 589.21159998863, + 597.6616999832913, + 589.8082000203431, + 689.6629999973811, + 810.4381000157446, + 697.0158999902196, + 1003.5421999928076, + 910.363300004974, + 785.3630000026897, + 597.7741000242531, + 608.8890999963041, + 618.135099997744, + 895.2332999906503, + 594.6587999933399, + 616.0365999967325, + 614.3486000073608, + 606.2103000003844, + 587.2201999882236, + 591.4440999913495 + ], + "transform": [ + 994.7742000222206, + 893.974899983732, + 738.5940999956802, + 895.4892999900039, + 731.8196999840438, + 1072.4995999771636, + 1098.2706000213511, + 925.1986999879591, + 1094.8155999940354, + 1092.8985999780707, + 989.0982999932021, + 1098.763299989514, + 1456.283599982271, + 2303.6476999986917, + 792.334400000982, + 991.3875999918673, + 1692.819399992004, + 754.5410000020638, + 779.719699989073, + 796.5945999894757, + 894.1119999799412, + 768.0578999861609, + 785.9261999838054, + 824.9066999997012, + 1391.7804000084288, + 893.1827000051271, + 793.2029000076, + 1411.5581999940332, + 992.3610999830998, + 988.8515000056941, + 986.930700019002, + 1723.0510000081267, + 881.8393000110518, + 1081.6816000151448, + 1110.1149000169244, + 884.1768999991473, + 790.1848999899812, + 1169.422199978726, + 1091.2203000043519, + 792.2509000054561, + 917.3989999981131, + 786.826800002018, + 1197.3134000145365, + 865.4419999802485, + 777.8011000191327, + 1197.7360000018962, + 1090.5752000107896, + 983.6764000065159, + 771.1229000124149, + 803.8255000137724, + 798.5879999760073, + 1387.3359000135679, + 790.399100020295, + 1029.0773999877274, + 802.807899977779, + 1383.3063000056427, + 750.1702999870759, + 1058.8218999910168, + 731.3541000185069, + 914.805799984606, + 1112.9284999915399, + 1092.7407999988645, + 1087.9835999803618, + 814.0726999845356, + 778.1721999926958, + 894.8575000104029, + 1086.5412999992259, + 967.8502999886405, + 794.261800008826, + 791.7939999897499, + 821.8041000072844, + 993.2147999934386, + 801.95090000052, + 1287.5706999911927, + 788.5172000096645, + 828.9962999988347, + 1282.6870999997482, + 987.4934999970719, + 1187.8931999963243, + 1132.900900003733, + 819.752100011101, + 895.8447000186425, + 995.2962000097614, + 1100.9913999878336, + 775.9250000235625, + 794.8728000046685, + 789.0969000000041, + 795.8358000032604, + 780.0046000047587, + 990.8277000067756, + 796.286600001622, + 797.3495000042021, + 789.6955000178423, + 1104.33020000346, + 998.4551999950781, + 1080.8758000202943, + 799.7123999812175, + 787.9264999937732, + 788.4927999984939, + 1018.4689000016078 + ], + "position": [ + 993.2963000028394, + 601.9613000098616, + 841.4555999916047, + 889.6749999839813, + 1489.6904999914113, + 610.1966999995057, + 612.4800000106916, + 860.8714999863878, + 806.9852000044193, + 697.1040999924298, + 1305.4324999975506, + 603.3755999815185, + 560.2972999913618, + 792.1042000234593, + 908.6057000095025, + 989.6379999991041, + 708.5521999979392, + 605.9011000033934, + 621.0120000177994, + 597.7837000100408, + 596.0555000056047, + 809.865000017453, + 604.9682999728248, + 541.3897999969777, + 608.1972999963909, + 1014.208900014637, + 1801.9281000015326, + 606.6420999995898, + 809.9851000006311, + 618.2275000028312, + 1410.5079000000842, + 582.4878999846987, + 603.950699995039, + 696.6269999975339, + 832.1569000254385, + 795.4363999888301, + 591.9959000020754, + 623.4786999993958, + 1316.503100009868, + 724.3807000049856, + 797.5626999977976, + 613.256700016791, + 1010.8136000053491, + 695.8990999846719, + 811.911600001622, + 1816.6032999870367, + 1300.3674000210594, + 888.443300005747, + 600.8968999958597, + 810.397399996873, + 804.1873000038322, + 617.0912999950815, + 608.7525000039022, + 601.6749999835156, + 609.9080000130925, + 703.586500021629, + 561.9377000257373, + 1175.4459000076167, + 547.9125000128988, + 690.3843999898527, + 797.8447999921627, + 795.346700004302, + 1000.2348000125494, + 595.9455000120215, + 619.769399985671, + 794.5145000121556, + 593.8554999884218, + 757.6997999858577, + 723.09069999028, + 592.0303000020795, + 596.7145999893546, + 1293.2950000104029, + 793.3845999941695, + 610.9645999968052, + 1214.064400002826, + 573.9158999931533, + 1302.6936000096612, + 1618.3074000000488, + 604.5317999960389, + 531.5076000115369, + 913.3835999818984, + 600.782599998638, + 604.2292999918573, + 602.4501999781933, + 817.5860000192188, + 592.8654999879654, + 900.653400021838, + 625.2585000183899, + 603.2922000158578, + 596.2747999874409, + 580.060800013598, + 708.4670000185724, + 896.4135999849532, + 593.0002999957651, + 888.1813999905717, + 694.6513000002597, + 582.5428999960423, + 604.3522999971174, + 624.9406000133604, + 561.1065000121016 + ], + "create_cube": [ + 1121.9517000135966, + 806.8807999952696, + 924.9765000131447, + 822.4828999955207, + 705.3747000172734, + 897.6508000050671, + 600.6644000008237, + 885.9324999793898, + 590.5405000085011, + 681.4095000154339, + 697.3860000143759, + 809.422899998026, + 581.3142999832053, + 903.2088000094518, + 990.8703000110108, + 919.2464000079781, + 602.097800001502, + 804.9054000002798, + 1309.8275999946054, + 605.2223999868147, + 704.4539999915287, + 1003.9053000218701, + 999.7418000129983, + 742.3477999982424, + 601.6982000146527, + 791.1887000082061, + 611.690699995961, + 608.0246999918018, + 780.2607999765314, + 608.4813999768812, + 901.8706000060774, + 915.7171999977436, + 891.3968999986537, + 818.2755000016186, + 1482.7448999858461, + 599.9688000010792, + 608.290499978466, + 605.7504999917, + 603.1487000000197, + 600.3225999884307, + 617.0376999943983, + 802.1800999995321, + 704.6811000036541, + 806.1158000200521, + 606.2536000099499, + 609.6647000231314, + 812.6579999807291, + 830.1159999973606, + 996.0660999931861, + 1286.9345000071917, + 888.2122999930289, + 599.7366000083275, + 596.9533000024967, + 697.0788999751676, + 701.2336000043433, + 906.7527999868616, + 1228.3356999978423, + 829.09089999157, + 548.4321999829262, + 615.2606000250671, + 801.3193999940995, + 996.2529999902472, + 614.2392000183463, + 615.3888000117149, + 703.360600018641, + 613.8002999941818, + 614.4265999901108, + 862.3063999984879, + 592.4820999789517, + 819.8310000007041, + 601.4234999893233, + 882.1585000259802, + 801.5873999975156, + 593.6958999955095, + 904.8126999987289, + 721.4231999823824, + 887.2141000174452, + 803.3279999799561, + 599.3611000012606, + 555.1483000162989, + 602.5418999779504, + 597.843900002772, + 611.533999996027, + 605.7454000110738, + 700.0815999926999, + 593.6341999913566, + 594.8486000124831, + 580.2179999882355, + 597.4349999742117, + 600.5493999982718, + 610.2886000007857, + 597.413499985123, + 614.6991999994498, + 595.7304000039585, + 590.1028999942355, + 906.5530000079889, + 605.2610999904573, + 889.0040000260342, + 1376.1536999954842, + 809.2022999771871 + ], + "add_component": [ + 972.4719000223558, + 1077.5065000052564, + 930.6556000083219, + 992.7311999781523, + 801.9073000177741, + 790.0359999912325, + 792.9201000079047, + 922.14119998971, + 809.8023000056855, + 902.715200005332, + 809.4665999815334, + 881.6465999989305, + 793.33470002166, + 1798.9843000250403, + 920.8031000162009, + 784.6583000209648, + 786.8283000134397, + 2914.332699991064, + 769.7641999984626, + 994.0109000017401, + 1192.2603000130039, + 1398.6998999898788, + 798.3827999851201, + 1009.9099999933969, + 781.3313999795355, + 798.7079000158701, + 1081.7801999801304, + 957.8153000038583, + 1193.1444000219926, + 969.2950999888126, + 782.0391999848653, + 890.9838999970816, + 802.9110000061337, + 890.3305999992881, + 796.3217000069562, + 807.360399980098, + 1088.8665999809746, + 967.9480999766383, + 812.1773000166286, + 992.4909999826923, + 1084.257099981187, + 767.487400007667, + 889.9613000103272, + 1204.9659000185784, + 973.8145000010263, + 1097.1448999771383, + 979.2815999826416, + 970.1797000016086, + 1015.806600014912, + 999.5763000042643, + 800.4558999964502, + 911.3681000017095, + 896.340200008126, + 1199.0027999854647, + 898.8340999931097, + 786.46909998497, + 852.1438000025228, + 877.0764999790117, + 1100.5883000034373, + 791.4923999924213, + 1086.6965999884997, + 785.3000000177417, + 793.3766999922227, + 892.4694999877829, + 881.3430999871343, + 869.6235999814235, + 1000.2127999905497, + 722.3270999966189, + 777.1123000129592, + 1065.0337999977637, + 783.4261000098195, + 826.8430999887642, + 1385.4868999915197, + 787.7500000176951, + 906.5038999833632, + 904.027499986114, + 797.9251000215299, + 789.5056999986991, + 785.3401000029407, + 726.1574000003748, + 785.6326999899466, + 790.7863000000361, + 785.9829000080936, + 978.7423999805469, + 791.0236000025179, + 917.8856999787968, + 1003.2192000071518, + 977.7979000064079, + 883.8860999967437, + 792.5818999938201, + 807.620700012194, + 997.6697000092827, + 1088.5684000095353, + 803.02959997789, + 810.4540999920573, + 1192.6392000168562, + 796.0727000026964, + 1205.1792000129353, + 810.118399997009, + 1086.769399989862 + ], + "remove_component": [ + 1002.0370999991428, + 993.8217000162695, + 776.7312000214588, + 997.2038999840152, + 884.8778000101447, + 883.2053000223823, + 783.9127999905031, + 779.4922000030056, + 999.1118000179995, + 796.9272999907844, + 981.2044999853242, + 797.0003999944311, + 781.2085999757983, + 915.2061000058893, + 1089.6192000072915, + 875.3717000072356, + 788.9374000078533, + 1131.0899999807589, + 1097.965299995849, + 1104.8372999939602, + 813.6724999931175, + 798.4959000023082, + 794.2169999878388, + 1530.3887000191025, + 1094.0336000057869, + 995.0456999940798, + 1015.7554000033997, + 1603.5618000023533, + 908.9984000020195, + 1187.4085000017658, + 1092.7491000038572, + 1100.0256999977864, + 1089.4717000192031, + 1511.4843999908771, + 986.6409999958705, + 899.8856999969576, + 1212.815300008515, + 1924.1670000192244, + 779.9197999993339, + 1277.182999998331, + 791.2195000099018, + 907.0069000008516, + 898.9176999893971, + 797.9833999997936, + 2204.1289000189863, + 1063.260299997637, + 1088.0352000240237, + 1921.3834000111092, + 787.0628999953624, + 796.774499991443, + 788.2879999815486, + 866.9444000115618, + 780.2222000027541, + 788.441899989266, + 994.7611000097822, + 798.8981999806128, + 878.7413999962155, + 889.2569000017829, + 1086.4624000096228, + 1078.2477000029758, + 1268.133100005798, + 785.7010000152513, + 1043.2479999726638, + 1189.0193999861367, + 780.5922999978065, + 1000.9409000049345, + 800.9512000135146, + 865.0115999917034, + 889.7876999981236, + 809.6966999873985, + 1398.853799997596, + 789.565200015204, + 788.1750999949872, + 982.9392000101507, + 1275.964299973566, + 1274.9881999916397, + 890.811199991731, + 979.9485000257846, + 790.8722000138368, + 931.0077000118326, + 1095.7635999948252, + 790.6129000184592, + 807.9482000030112, + 1200.5262000020593, + 793.2566999807023, + 771.2329000059981, + 776.4380000007804, + 799.960700009251, + 1201.4189999899827, + 913.3271999889985, + 772.0634000143036, + 986.6402999905404, + 1119.2743999999948, + 1081.5572999999858, + 1089.8839999863412, + 803.7021000054665, + 774.3214000074659, + 814.4387000065763, + 790.3149999910966, + 1001.4116000093054 + ], + "delete_gameobject": [ + 610.2610999951139, + 702.7273999992758, + 806.4143999945372, + 812.4498999968637, + 699.2929999832995, + 700.735500024166, + 920.6881000136491, + 602.2727999952622, + 697.6694000186399, + 793.2474999979604, + 596.9544000108726, + 604.2345000023488, + 712.4447000096552, + 799.2155999818351, + 815.8004000142682, + 1097.6513999921735, + 1904.8468999972101, + 596.6214999789372, + 881.9023999967612, + 693.7340000004042, + 587.8069000027608, + 596.7484999855515, + 905.9707999986131, + 891.8407000019215, + 1099.6560000057798, + 588.1924999994226, + 574.5835999841802, + 581.6084000107367, + 599.4534000055864, + 613.6878000106663, + 783.0426000000443, + 675.9957999747712, + 701.945800014073, + 603.9241999969818, + 612.0717000158038, + 897.276800009422, + 801.0406999965198, + 587.0916999992914, + 690.9891999966931, + 607.9279000114184, + 1195.746900019003, + 920.0820999976713, + 981.1174999922514, + 896.3303999917116, + 597.642899985658, + 1085.962400014978, + 1002.740800002357, + 796.6213999898173, + 696.4046999928541, + 805.7165000063833, + 777.3771999927703, + 607.2588000097312, + 885.990100010531, + 611.0013999859802, + 900.2035000012256, + 1099.8016000085045, + 901.8470000009984, + 598.9129000226967, + 583.0283999966923, + 1113.5141999984626, + 600.9367000078782, + 802.488599991193, + 1088.510799978394, + 610.8907000161707, + 600.46039998997, + 606.9625000236556, + 602.2075999935623, + 544.7107000218239, + 807.3303999844939, + 594.9426000006497, + 606.3243999960832, + 791.183599998476, + 616.7538999870885, + 703.0303000065032, + 917.8530999924988, + 594.5940000237897, + 705.0583999953233, + 1307.5479999824893, + 1402.4920999945607, + 547.9979999945499, + 1501.486399996793, + 601.7900999868289, + 584.1788000252564, + 894.0075999998953, + 594.1596000047866, + 704.2883000103757, + 1118.7352999986615, + 595.7977999933064, + 605.0632999977097, + 780.1382999750786, + 914.7076999943238, + 704.3670999992173, + 1080.3412000241224, + 597.2982000093907, + 706.8075000133831, + 895.3497000038624, + 630.0234000082128, + 1299.190699995961, + 593.3277999865822, + 582.4731000175234 + ], + "scene_info": [ + 899.3580999958795, + 694.5449000049848, + 585.0236999976914, + 593.7695000029635, + 592.8591999982018, + 722.9509000026155, + 1176.8539999902714, + 778.6865999805741, + 703.151700028684, + 590.2245999895968, + 991.8010999972466, + 582.6571999932639, + 597.9651999950875, + 716.609499999322, + 891.6330999927595, + 597.3135999811348, + 600.2350999915507, + 983.6991000047419, + 595.9299000096507, + 993.0908000096679, + 590.6863999844063, + 591.6280999954324, + 697.2045000002254, + 602.3786000150722, + 891.9779999996535, + 907.2687000152655, + 1017.5191999878734, + 611.964599986095, + 604.12480001105, + 616.7448000051081, + 622.0141999947373, + 798.5511000151746, + 703.568400000222, + 587.6905999903101, + 1586.615799984429, + 1173.4147999959532, + 907.459200010635, + 583.0819000257179, + 709.4250999798533, + 583.728900004644, + 2002.0653999818023, + 1099.0352000226267, + 893.4324000147171, + 903.174700011732, + 623.0218000127934, + 1508.5163000039756, + 896.7165999929421, + 1592.1486000006553, + 685.7763000007253, + 602.1301000146195, + 610.3207000123803, + 597.5153000035789, + 598.1370999943465, + 686.5873000060674, + 787.6799000077881, + 797.3122999828774, + 587.5023999833502, + 698.795499978587, + 699.9097999942023, + 583.561000006739, + 609.0940999856684, + 589.3494000192732, + 599.0939999755938, + 588.7518000090495, + 594.6210999973118, + 1105.8556000061799, + 586.8971000018064, + 868.8045000017155, + 579.9125999910757, + 594.0892999933567, + 584.8858999961521, + 1784.4194000062998, + 590.1987999968696, + 1000.912600022275, + 902.2488999762572, + 617.3381000116933, + 1179.6627000148874, + 696.8845999799669, + 604.2700999823865, + 741.9005999981891, + 584.4709999801125, + 686.2249000114389, + 789.9271000060253, + 600.9527000132948, + 616.9784999801777, + 992.1210000175051, + 584.6208999864757, + 799.0337000228465, + 607.9530999995768, + 597.1774000208825, + 1287.2644000162836, + 596.1992000229657, + 596.2832999939565, + 593.1360000104178, + 886.8970999901649, + 691.6600000113249, + 875.7240000122692, + 804.9823000037577, + 579.5826000103261, + 702.7476000075694 + ], + "scene_save": [ + 996.7073000152595, + 899.002299993299, + 1347.744500002591, + 897.8242000157479, + 715.080099995248, + 691.3921000086702, + 719.1449000092689, + 1319.4696999853477, + 906.783499987796, + 898.8735000020824, + 727.9976999852806, + 831.4667999802623, + 807.711700006621, + 1310.8500000089407, + 809.9283000046853, + 732.7975999796763, + 725.0048000132665, + 995.5678000114858, + 822.8919999965001, + 721.2808000040241, + 909.0519000019412, + 718.2811000093352, + 1092.772200005129, + 1107.7240000013262, + 729.9673999950755, + 684.586000017589, + 830.2229000255466, + 1016.0824000195134, + 801.0818999900948, + 701.4185999869369, + 897.2527000005357, + 1021.6043000109494, + 1389.163699990604, + 892.7364999835845, + 826.2839999806602, + 920.9185000217985, + 796.9309999898542, + 712.4078999913763, + 704.1002000041772, + 1005.3155000205152, + 1011.7792999953963, + 993.5810000170022, + 715.3511999931652, + 1016.2476999976207, + 911.045999993803, + 898.8491000200156, + 814.5985000010114, + 819.4032000028528, + 1701.9459000148345, + 797.0736999996006, + 909.259900014149, + 696.62880001124, + 711.1197999911383, + 813.9995999808889, + 1009.5056999998633, + 813.594799983548, + 1027.1175000234507, + 1113.2768999959808, + 695.3781000047456, + 887.8925000026356, + 727.3889000061899, + 1011.4224000135437, + 711.3717999891378, + 923.3876999933273, + 721.8090000096709, + 682.4573999911081, + 922.2149999986868, + 856.7017000168562, + 807.5862999830861, + 817.4746000149753, + 817.2197999956552, + 717.7738000173122, + 704.3210999981966, + 855.0780000223313, + 716.8009000015445, + 809.7287000273354, + 806.3155000272673, + 709.0805000043474, + 696.4338000107091, + 910.3391999960877, + 805.921599996509, + 732.5622999924235, + 805.9621999855153, + 695.1700999925379, + 692.2990999883041, + 702.5993000133894, + 701.4544999983627, + 995.3339000057895, + 703.4054000105243, + 910.2674000023399, + 704.958499991335, + 716.4035000023432, + 690.9953000140376, + 907.8111000126228, + 700.0119000149425, + 788.8601000013296, + 919.2948999989312, + 1596.715799998492, + 719.9701000063214, + 716.7695999960415 + ], + "console": [ + 538.1819999893196, + 1033.2717999990564, + 535.6994000030681, + 848.8897000206634, + 714.1890999919269, + 711.6475999937393, + 700.2256999840029, + 557.2017000231426, + 1423.4979000175372, + 922.9436999885365, + 539.5805000152905, + 673.4396999818273, + 541.1718000250403, + 530.293999996502, + 839.2102000070736, + 540.768200007733, + 552.6199000014458, + 776.2138999823947, + 1341.6229999857023, + 540.0842999806628, + 553.1174999778159, + 545.3074999968521, + 537.9316000035033, + 1065.4184999875724, + 717.7380000066478, + 539.4623000174761, + 560.3456000098959, + 1146.3131000055, + 531.2852000060957, + 648.3435000118334, + 535.1899999950547, + 532.1054000232834, + 623.7581000023056, + 583.7255999795161, + 536.5015999996103, + 856.1744000180624, + 805.9652999800164, + 791.4096000022255, + 746.2061999831349, + 1216.9588999822736, + 825.6298000051174, + 570.8300999831408, + 547.9191000049468, + 1378.1672999903094, + 755.2136999729555, + 682.377599994652, + 1400.5059999763034, + 823.031899984926, + 689.3839999975171, + 532.3561999830417, + 534.2989999917336, + 571.2647000036668, + 528.3516000199597, + 750.3432999947108, + 618.1793000141624, + 817.453999974532, + 583.6062000016682, + 545.4152000020258, + 767.2554000164382, + 537.048500002129, + 558.8206999818794, + 826.2640000029933, + 716.34039998753, + 778.6296000122093, + 655.4245000006631, + 555.4299000068568, + 537.1645000122953, + 791.529799986165, + 647.3338999785483, + 729.2787999904249, + 628.7775000091642, + 732.4490000028163, + 536.533899983624, + 998.6223000159953, + 542.165799997747, + 537.0762000093237, + 567.8678000112996, + 773.6507999943569, + 612.3074000061024, + 552.4503999913577, + 831.4533999946434, + 537.8414999868255, + 542.0857999997679, + 536.1099999863654, + 733.6708000220824, + 544.0830000152346, + 543.57050001272, + 536.4628999959677, + 546.3734999939334, + 860.2109999919776, + 539.3235000083223, + 792.2815000056289, + 539.3997000064701, + 973.0871999927331, + 599.6248000010382, + 534.8056000075303, + 625.2232999831904, + 795.1311999931931, + 541.3717000046745, + 737.4844999867491 + ], + "screenshot": [ + 634.3149000022095, + 718.2983999955468, + 822.663900005864, + 1032.086099992739, + 946.2496000051033, + 843.1126999785192, + 757.0436999958474, + 807.8026000002865, + 656.32799998275, + 1859.2339000024367, + 720.115000003716, + 966.308700008085, + 1008.8307000114582, + 646.3742000050843, + 734.0631000115536, + 729.8439999867696, + 1002.7247000252828, + 795.5019999935757, + 925.6226000143215, + 919.2075000028126, + 1320.4069999919739, + 607.1059000096284, + 856.6452999948524, + 824.4972999964375, + 849.6300999831874, + 641.2806999869645, + 614.1414000012446, + 613.4177999920212, + 832.3765000095591, + 1610.5271000124048, + 1355.403399997158, + 740.0375000142958, + 760.0550999923144, + 887.0223999838345, + 828.0888000153936, + 926.5595999895595, + 1571.8316000129562, + 867.5948000163771, + 816.5857999993023, + 758.2382999826223, + 861.3645999867003, + 699.7769000008702, + 610.309400013648, + 682.9336000082549, + 810.7979000196792, + 1091.3222999952268, + 657.4887000024319, + 640.0875999825075, + 885.3372000157833, + 722.8324999741744, + 642.5350999925286, + 594.5089000160806, + 851.1924000049476, + 1017.7931000071112, + 761.9459000125062, + 1366.1029000068083, + 1801.2912000122014, + 618.2534999970812, + 705.6880000163801, + 934.0276999864727, + 1105.3530999924988, + 648.771799984388, + 969.4098000181839, + 692.6035000069533, + 1007.8074999910314, + 715.0028000178281, + 634.8248000140302, + 1137.6848999934737, + 645.5584999930579, + 1041.1654000054114, + 731.6468000062741, + 638.6346000072081, + 637.1618999983184, + 1117.0880000281613, + 601.4354999933857, + 619.6204999869224, + 619.3288999784272, + 1093.7927000049967, + 656.2182999914512, + 780.9187000093516, + 734.0232999995351, + 720.1683000021148, + 624.424799985718, + 746.1946000112221, + 625.6930999807082, + 627.9409999842755, + 626.6118000203278, + 649.6231000055559, + 619.6772000112105, + 625.2976999967359, + 627.9101000109222, + 668.2749000028707, + 633.8028000027407, + 604.5053999987431, + 664.1211000096519, + 642.6286000059918, + 623.4459999832325, + 689.9471000069752, + 739.7157000086736, + 609.6416000218596 + ], + "material_search": [ + 608.208999998169, + 715.9241999906953, + 610.4060000216123, + 697.7578999940306, + 808.4140999999363, + 906.2289999856148, + 811.5044000151101, + 622.0498000038788, + 623.6662000010256, + 608.0069000017829, + 606.6920000012033, + 603.2417000096757, + 618.7120999966282, + 1318.5595000104513, + 598.7781999865547, + 897.1331999928225, + 806.6173999977764, + 814.570399990771, + 999.078399996506, + 809.2896000016481, + 801.7507999902591, + 818.8529000035487, + 899.2999999900348, + 587.6044000033289, + 797.7334999886807, + 620.0660999747925, + 899.2638999770861, + 803.9535999996588, + 1722.3003999970388, + 907.4224999931175, + 603.0967000115197, + 793.9120999944862, + 607.0269999909215, + 604.2045000067446, + 1498.303100001067, + 594.2450000147801, + 607.1053999767173, + 603.5487999906763, + 1099.4759000022896, + 942.0519000268541, + 1490.1528999907896, + 792.4874000018463, + 915.1476000261027, + 596.6952000162564, + 902.6509000104852, + 699.9978999956511, + 733.1037999829277, + 697.8717999882065, + 721.485100017162, + 604.2231000028551, + 599.0035000140779, + 611.9872000126634, + 584.8636000009719, + 898.2242000056431, + 600.230800017016, + 699.9978999956511, + 815.5113999964669, + 802.0983999886084, + 801.1006999877281, + 910.5912999948487, + 610.48919998575, + 608.5848000075202, + 1418.6954000033438, + 700.0463999866042, + 903.4913000068627, + 814.3061000155285, + 806.1811000225134, + 591.489599988563, + 794.3873000040185, + 892.654199997196, + 715.5561000108719, + 698.31529998919, + 609.0622999763582, + 821.513100003358, + 711.7579999903683, + 903.0779000022449, + 912.7013999968767, + 1205.6107000098564, + 1018.2340999890584, + 1014.5779000013135, + 1521.0930000175722, + 584.9991999857593, + 608.1510999938473, + 1107.0015000004787, + 607.7619999996386, + 897.3865000007208, + 600.5073999986053, + 601.8452999996953, + 697.5289999973029, + 588.7534999928903, + 904.981300001964, + 1396.9213000091258, + 622.7572000061627, + 580.7158999959938, + 603.7424000096507, + 609.8028999986127, + 602.6919000141788, + 891.7339000036009, + 601.1725999996997, + 635.445299994899 + ], + "asset_copy": [ + 750.6895999831613, + 654.3161000008695, + 859.0132000099402, + 658.4037999855354, + 769.0219000214711, + 1576.5289000119083, + 867.4529000127222, + 849.1038999927696, + 642.6140000112355, + 681.744700006675, + 767.9398999898694, + 680.8970000129193, + 664.1221000172663, + 949.6509000018705, + 980.3842999972403, + 1064.02170000365, + 881.9561999989673, + 964.2529999837279, + 649.2863000021316, + 664.597800001502, + 871.9016999821179, + 957.0243000052869, + 645.6756000116002, + 863.7954000150785, + 766.5691000001971, + 753.8318999868352, + 956.4613000256941, + 860.4203000140842, + 843.0924999993294, + 855.9367999841925, + 652.2027000028174, + 874.2018999764696, + 851.5600999817252, + 865.3916000039317, + 1271.8600999796763, + 674.6149999962654, + 945.811199984746, + 675.3039000032004, + 662.1702999982517, + 926.3718000147492, + 1294.583800015971, + 1060.126800002763, + 1059.168799984036, + 856.8056999938563, + 1285.1376000035089, + 1265.6968999945093, + 1044.9378000048455, + 1278.053700021701, + 843.3543000137433, + 871.8969999754336, + 766.8783999979496, + 959.1655000112951, + 976.7606999957934, + 1265.001799998572, + 1356.5098000108264, + 648.7768999941181, + 650.2128999854904, + 967.3032000137027, + 765.8562999858987, + 666.8604000005871, + 654.7633000009228, + 766.6446000221185, + 668.4260999900289, + 770.7968000031542, + 664.5533999835607, + 1560.352000000421, + 1367.8686000057496, + 879.8690999974497, + 673.0416000063997, + 884.5382000145037, + 858.0128999892622, + 1061.931000003824, + 757.0145000063349, + 655.4105999821331, + 1562.4725999950897, + 771.1757000070065, + 662.5617000099737, + 671.152599999914, + 954.6602999907918, + 1465.3654999856371, + 745.0812000024598, + 658.838499977719, + 663.8378000061493, + 656.521500000963, + 970.344200002728, + 769.5791999867652, + 662.7275999926496, + 953.3447999856435, + 667.0419999863952, + 664.6431999979541, + 968.662300001597, + 651.4224999991711, + 843.4857000247575, + 664.7807999979705, + 871.9137000152841, + 665.9231999947224, + 689.1920999914873, + 678.9280000084545, + 655.4589000006672, + 667.7487000124529 + ], + "asset_move": [ + 1520.0544999970589, + 983.8464999920689, + 666.762499982724, + 777.3471999971662, + 1277.851599996211, + 684.0219000005163, + 669.7100000164937, + 754.7771999961697, + 681.5754999988712, + 657.5297999952454, + 994.1634999995586, + 865.9637999953702, + 668.2865000038873, + 773.114199982956, + 1105.0955999817234, + 675.5360999959521, + 652.0336999965366, + 968.5540999926161, + 883.8890999904834, + 667.5043000141159, + 963.0490000126883, + 898.6854999966454, + 789.2291999887675, + 1448.4041999967303, + 692.9278000025079, + 662.9405000130646, + 662.2657999978401, + 663.2873000053223, + 674.1105999972206, + 663.0540000041947, + 768.8770999957342, + 1779.362300003413, + 2125.8502999844495, + 655.0679999927524, + 669.5973000023514, + 663.089299981948, + 890.847800008487, + 957.8618999803439, + 690.2423000137787, + 665.2018000022508, + 682.4882999935653, + 681.9134999823291, + 660.5818999814801, + 791.9350000156555, + 957.6710999826901, + 680.6372000137344, + 984.9608999793418, + 873.3250999939628, + 673.0518999975175, + 663.8739999907557, + 666.5024000103585, + 781.428499991307, + 1121.0021000006236, + 660.2238999912515, + 857.0659999968484, + 894.329699978698, + 771.3460000231862, + 1069.4508999877144, + 671.3693999918178, + 759.487800009083, + 680.1112999964971, + 652.2092999948654, + 666.2574999791104, + 662.9775000037625, + 768.8922000234015, + 883.275300002424, + 777.9787000035867, + 668.4632999822497, + 664.382300019497, + 666.9715000025462, + 1200.3708999836817, + 657.7551000227686, + 653.0392999993637, + 653.104600001825, + 986.1139999993611, + 643.6466999875847, + 751.1058000090998, + 653.7194999982603, + 853.7979999964591, + 669.7140999895055, + 685.0183999922592, + 688.2373999978881, + 668.9960000221618, + 645.9895999869332, + 660.4321000049822, + 875.6930999807082, + 679.7527000016998, + 1682.7547999855597, + 672.7007000008598, + 658.540099975653, + 960.9932999883313, + 684.1391999914777, + 973.4601000091061, + 682.5539999990724, + 665.8762999868486, + 663.8505000155419, + 666.1255000217352, + 760.8882999920752, + 674.0024999890011, + 670.7297999819275 + ], + "asset_delete": [ + 583.6189000110608, + 1402.9772999929264, + 1183.97690000711, + 1192.2694999957457, + 634.0008999977726, + 653.3519999939017, + 657.4080000282265, + 965.6760999932885, + 854.9798000021838, + 640.4645000002347, + 1673.468299995875, + 1058.1945999874733, + 852.2064000135288, + 754.0225000120699, + 702.9515999893192, + 661.9701000163332, + 647.0976999844424, + 641.4347999962047, + 760.693899996113, + 740.9128000144847, + 660.5802999984007, + 838.4420000074897, + 1449.3899999943096, + 594.4670999888331, + 758.8717000035103, + 657.8983999788761, + 669.3047000153456, + 960.0529999879654, + 681.3409999886062, + 761.2257000000682, + 679.1308000101708, + 764.4203999952879, + 933.0140000092797, + 671.7576999799348, + 689.9297999916598, + 748.5717999807093, + 862.4958999862429, + 863.016899995273, + 656.5188000095077, + 758.3124000229873, + 950.8356000005733, + 662.8660999995191, + 672.6214000082109, + 926.0127999878023, + 1060.91749999905, + 844.5291999960318, + 965.0659000035375, + 673.3035999932326, + 861.2359999970067, + 684.141500008991, + 857.8732000023592, + 749.0661999909207, + 601.9517999957316, + 659.1554000042379, + 680.514999985462, + 1440.0457000010647, + 1478.990400006296, + 601.36479997891, + 657.1157000144012, + 652.5659999751952, + 852.7877000160515, + 968.0483000120148, + 934.9704000051133, + 645.6410000100732, + 776.3048999768216, + 655.9042999870144, + 953.9465999987442, + 668.922000011662, + 668.870399997104, + 846.3288999919314, + 792.2400000097696, + 660.4197999986354, + 1067.971899989061, + 779.0776999900118, + 661.1944000178482, + 872.031800012337, + 674.5479000092018, + 764.2712999950163, + 793.8464999897406, + 652.3714999784715, + 650.1819999830332, + 641.5377999946941, + 660.0828999944497, + 664.3229000037536, + 1071.2069000001065, + 677.0848000014666, + 661.6081999964081, + 673.7644000095315, + 663.2869000022765, + 664.4222000031732, + 682.7515999902971, + 647.3289999994449, + 665.5286999884993, + 662.2632999788038, + 870.1116000011098, + 647.136399988085, + 659.1666000022087, + 684.0764000080526, + 771.3447000132874, + 955.6980000052135 + ], + "import_settings": [ + 539.5012999942992, + 642.2049000102561, + 602.5634999969043, + 837.8584000165574, + 645.6074999878183, + 601.0403000109363, + 609.6813000040129, + 805.7436000090092, + 1130.9814999985974, + 717.0780000160448, + 596.5983000060078, + 1348.8434000173584, + 921.8048000184353, + 1524.3501999939326, + 721.5671000012662, + 604.0475000045262, + 622.6497999741696, + 902.0648000005167, + 800.4871000011917, + 1426.6638999979477, + 605.1475000276696, + 604.3517000216525, + 810.7668999873567, + 830.0755000091158, + 797.4399999948218, + 712.6547000079881, + 598.8048999861348, + 605.5381000041962, + 697.6775999937672, + 617.6616000011563, + 899.306000006618, + 625.3940000024159, + 601.8535000039265, + 986.1192000098526, + 781.3486999948509, + 913.8314000156242, + 601.1500000022352, + 910.6784999894444, + 599.5701999927405, + 1016.0878999740817, + 1321.808799984865, + 808.8316000066698, + 702.7291999838781, + 933.7872999894898, + 926.822200010065, + 711.2291000084952, + 596.9095999898855, + 804.8950000084005, + 797.5539999897592, + 603.7929999874905, + 1128.1242000113707, + 599.6259000094142, + 654.4534000277054, + 607.0543999958318, + 901.4106999966316, + 538.1051999866031, + 554.7541000123601, + 550.4178999981377, + 1121.0382000135724, + 622.958899999503, + 802.7087999798823, + 617.7927999815438, + 617.8222000016831, + 615.1453000202309, + 707.365199981723, + 619.8248000000603, + 931.6653999849223, + 607.0318999991287, + 899.6809000091162, + 1133.4399999759626, + 619.1400000243448, + 612.6960999972653, + 538.7825999932829, + 710.219300002791, + 598.6562000180129, + 611.7411999730393, + 612.150400003884, + 1833.3564999920782, + 700.436199986143, + 710.5760000122245, + 708.0469999928027, + 628.7924000062048, + 595.6483999907505, + 617.7131000149529, + 551.4249000116251, + 888.4507000038866, + 599.0315000235569, + 725.1252999994904, + 802.9137999983504, + 600.7575999828987, + 896.1013999942224, + 620.1459000003524, + 608.6596999957692, + 595.2820999955293, + 1111.666899989359, + 611.9616999931168, + 608.1535999837797, + 595.0680000241846, + 617.8108000021894, + 616.8097000045236 + ], + "material_modify": [ + 564.0371000044979, + 720.7459000055678, + 847.246899997117, + 793.4411999885924, + 823.1932999915443, + 811.5575000119861, + 642.1417999954429, + 846.3225000014063, + 628.1491999980062, + 850.7560999714769, + 978.4029999864288, + 565.9826000046451, + 613.6349999869708, + 639.2120000091381, + 622.5779999804217, + 626.9698000105564, + 641.1250999954063, + 760.6507000164129, + 945.7001000118908, + 625.2158999850508, + 632.627400016645, + 637.8956999978982, + 649.4014000054449, + 983.5191000020131, + 643.6293000006117, + 1155.3158000169788, + 839.4651999988127, + 637.2760999947786, + 1345.3829999780282, + 835.1271999999881, + 1236.6053000150714, + 853.9638000074774, + 659.6366000012495, + 960.8156000031158, + 948.1093999929726, + 936.4100999955554, + 826.7352000111714, + 747.4277000001166, + 765.607600013027, + 637.3149999999441, + 648.0343999864999, + 714.7291000001132, + 1543.369499995606, + 620.6911000190303, + 613.4722999995574, + 747.4692999967374, + 1683.5961999895517, + 632.6914000092074, + 1244.5449999941047, + 629.3975999869872, + 640.1780999731272, + 647.6911000208929, + 562.8273999900557, + 752.6532000047155, + 638.8322999991942, + 562.6346000062767, + 605.1092999987304, + 653.4708999970462, + 623.693400004413, + 740.8272000029683, + 1133.4624999726657, + 622.6633000187576, + 964.408799976809, + 635.5143999971915, + 1331.6494000027888, + 1041.6916999965906, + 713.5507000202779, + 631.9354000152089, + 833.3036999974865, + 630.8302999823354, + 651.9175999856088, + 828.324900008738, + 583.7125000252854, + 633.1540999817662, + 1033.8666000170633, + 737.0990999916103, + 810.7025999925099, + 631.0659000009764, + 940.6980999920052, + 640.574299992295, + 734.3101000005845, + 625.4381999897305, + 859.637899993686, + 646.0555999947246, + 578.3903000119608, + 636.6524999903049, + 838.8433000072837, + 629.0627999987919, + 628.430099983234, + 642.8881000028923, + 741.7438999982551, + 936.6866999771446, + 639.6961999998894, + 637.8895999805536, + 1231.2282999919262, + 636.2948000023607, + 1375.5616999987978, + 751.9529999990482, + 640.0536999863107, + 638.1388999870978 + ], + "time_settings": [ + 537.9902000131551, + 547.1441999834497, + 1035.364200011827, + 529.1296000068542, + 1653.0216000101063, + 1029.38669998548, + 629.4214999943506, + 611.8300999805797, + 623.0830000131391, + 1104.1878999967594, + 587.0566999947187, + 535.2040999860037, + 611.7927999875974, + 776.159800007008, + 540.4469999775756, + 613.0190000112634, + 909.141100011766, + 693.94860000466, + 598.775000020396, + 805.1470000064, + 819.5064000028651, + 901.6801999823656, + 552.9937999963295, + 541.5426999970805, + 608.7955000111833, + 595.7461000070907, + 708.3205000089947, + 624.4697000074666, + 807.4504999967758, + 623.1858999817632, + 619.8043999902438, + 895.7482000114396, + 816.8479000160005, + 814.4049000111409, + 622.6025999931153, + 807.4913000164088, + 926.4014000073075, + 706.58729999559, + 618.6949000111781, + 615.8109999960288, + 592.8815000224859, + 633.5485000163317, + 601.9720000040252, + 647.3458999826107, + 788.966399995843, + 703.0490000033751, + 593.2801999733783, + 918.7930999905802, + 615.5843999877106, + 817.054500017548, + 588.7889000005089, + 613.7414000113495, + 842.3821000033058, + 1197.132800007239, + 612.0716999867, + 544.9658000143245, + 562.0993000047747, + 554.5318000076804, + 613.8904000108596, + 604.6281000017188, + 609.3887999886647, + 614.9381999857724, + 907.3842999932822, + 804.3116999906488, + 606.8085999868345, + 602.5440999947023, + 614.5239000034053, + 621.6423999867402, + 1234.341300005326, + 596.5986999799497, + 836.5603999991436, + 609.2848999833222, + 549.1062999935821, + 812.8815999953076, + 618.4106000000611, + 897.5106000143569, + 727.632199996151, + 610.4779000161216, + 596.8566999945324, + 793.1908000027761, + 716.3173999870196, + 625.8963000145741, + 1007.1587999991607, + 622.7400999923702, + 666.0472999792546, + 830.031899997266, + 712.1272000076715, + 601.2580000096932, + 1038.7255999958143, + 716.7727000196464, + 1305.5580999935046, + 1206.4910000190139, + 600.8473999972921, + 627.7859000256285, + 605.7930999959353, + 610.7516999763902, + 1166.500499995891, + 1328.345600020839, + 598.5129000036977, + 619.0461999794934 + ], + "read_csharp": [ + 543.6951999727171, + 532.6700000150595, + 542.3259999952279, + 1374.4025999912992, + 765.451999992365, + 595.0807000044733, + 771.3784000079613, + 798.0659999884665, + 585.0280000013299, + 588.2870999921579, + 813.1598000181839, + 775.3751999989618, + 902.4732999969274, + 626.4520999975502, + 733.9809999975841, + 800.2451999927871, + 598.6673000152223, + 917.4294000258669, + 613.900399999693, + 712.7600000239909, + 897.7623000100721, + 600.6281999871135, + 525.3937000234146, + 566.7840999958571, + 909.4539000070654, + 706.0148000018671, + 915.6861999945249, + 1198.0629000172485, + 598.6581000033766, + 893.9822999818716, + 601.903200004017, + 902.6541000057478, + 885.4914999974426, + 894.5758000190835, + 686.1560999823269, + 703.0914000060875, + 605.9223999909591, + 603.9326000027359, + 881.2782999884803, + 579.7599999932572, + 807.458700001007, + 1494.6010999847203, + 605.6656000146177, + 566.791799996281, + 736.9370999804232, + 1522.8940999950282, + 801.8354999949224, + 622.1350000123493, + 601.324699993711, + 1302.497399999993, + 825.3796999924816, + 602.2356000030413, + 543.280500016408, + 913.9362999994773, + 796.1871000006795, + 692.3172999813687, + 1094.5469999860507, + 534.7867000091355, + 602.9477999836672, + 898.6417000123765, + 595.0365000171587, + 615.2924000052735, + 701.9098000018857, + 906.8093999812845, + 703.6360000201967, + 711.7892999958713, + 715.6952999939676, + 894.4460999919102, + 592.0772999816108, + 892.4872000061441, + 813.367399998242, + 920.5688999791164, + 554.7418000060134, + 694.9158000061288, + 598.9038999832701, + 910.2826999733225, + 1308.294599992223, + 600.0031000003219, + 620.0935000088066, + 712.2437999933027, + 787.2577999951318, + 586.2796000146773, + 608.798500004923, + 600.5310000036843, + 539.1870000166818, + 604.8817000119016, + 1304.4697000004817, + 610.45620002551, + 608.4480999852531, + 899.3594000057783, + 604.4399000238627, + 591.1018000042532, + 595.503499993356, + 597.5564999971539, + 607.2306999994908, + 705.8813000039663, + 599.4482999958564, + 578.301499976078, + 705.9045999776572, + 586.2899000057951 + ], + "play_until_ready": [ + 1705.9480999887455, + 1911.8404000182636, + 1153.117799985921, + 1125.8492000051774, + 1495.6642999895848, + 1255.016200011596, + 1853.1225000042468, + 1614.0771000063978, + 1435.692500002915, + 1248.2060999900568, + 1850.8969999966212, + 1616.5366000204813, + 1949.176299996907, + 1432.906500005629, + 1759.7871999896597, + 1165.9034000185784, + 2542.974599986337, + 1618.8832999905571, + 1134.7146999905817, + 1319.4474000192713, + 1440.0252999912482, + 1226.7955999996047, + 1111.7640000011306, + 1805.1375999930315, + 1928.5761000064667, + 1210.9993000049144, + 1157.210400007898, + 1525.970699993195, + 2114.39380000229, + 1419.0230999956839, + 2218.272700003581, + 1432.6417999982368, + 1532.3200999991968, + 2057.930800016038, + 1445.3144999861252, + 2034.2477000085637, + 1164.9417000007816, + 1619.321599981049, + 1559.595900005661, + 1441.1436000082176, + 1728.0432999832556, + 1637.529200001154, + 1429.6551999868825, + 1713.280299998587, + 2099.777900002664, + 1465.5587999732234, + 1731.8807000119705, + 1334.4930000021122, + 1410.4109999898355, + 1228.1818999908864, + 2232.3720000276808, + 1427.4619999923743, + 1201.648899994325, + 1241.934499994386, + 1637.2780999809038, + 1088.5283999959938, + 1454.402300005313, + 1917.703100014478, + 1451.5300000202842, + 1532.146899990039, + 1449.0259000158403, + 2096.2653999740724, + 1431.994799990207, + 1326.9444999750704, + 1712.7862999914214, + 1747.9590000002645, + 1614.9956000153907, + 1634.9535000044852, + 1464.6865999966394, + 1320.1826000004075, + 1074.8539000051096, + 1422.6161999977194, + 1120.378299994627, + 1729.8210999870207, + 1458.5957000090275, + 1419.9029000010341, + 1228.871600003913, + 1225.9942000091542, + 2424.7805000049993, + 1142.7996999991592, + 1353.4741000039503, + 1926.178699999582, + 1312.656699999934, + 1300.773199996911, + 1396.1841999844182, + 1128.7404000177048, + 1864.3201000231784, + 1344.1834000113886, + 1146.59760001814, + 1235.4249999916647, + 1235.6674000038765, + 1456.7906000011135, + 1242.5987000169698, + 1522.2018000204116, + 1186.4480999938678, + 1342.8120000171475, + 1243.651900003897, + 1266.12259997637, + 1384.5485000056215, + 1227.4882999772672 + ], + "stop_until_ready": [ + 1916.460400010692, + 1345.062100008363, + 1088.7899000081234, + 1431.450500007486, + 2350.344899983611, + 1853.048499993747, + 1729.745599994203, + 1985.0293999770656, + 1752.099300007103, + 1317.5493000017013, + 1570.0654999818653, + 1485.6774999934714, + 1369.2173000017647, + 2241.719399986323, + 1848.414700012654, + 1242.175599996699, + 1223.325200000545, + 1749.671199999284, + 1441.3326999929268, + 1232.3570000007749, + 1446.5441000065766, + 1342.6743000163697, + 1997.1369999984745, + 1715.008500003023, + 1280.089499981841, + 1758.6893000116106, + 1734.2704999900889, + 1449.08089999808, + 1229.036000004271, + 2158.0108999914955, + 1343.0013000033796, + 1452.060600015102, + 1192.1631000004709, + 1459.395100013353, + 1954.8354000144172, + 1249.6847999864258, + 1471.6062000079546, + 1871.403700002702, + 1945.4194999998435, + 1656.8000999977812, + 1241.5735999820754, + 2351.4475999982096, + 1558.9386000065133, + 1909.195499989437, + 1775.626899994677, + 1551.6711999953259, + 2169.9892999895383, + 1625.150100007886, + 1443.4840000176337, + 1145.086899981834, + 1375.175000022864, + 1534.3547000084072, + 1629.0469999948982, + 1330.1279000006616, + 1635.5754999967758, + 2040.9754999855068, + 1144.8165999900084, + 1139.4290999742225, + 1739.078900020104, + 1434.4270000001416, + 1920.4492999997456, + 1638.0260000005364, + 2063.3429999870714, + 1358.6083000118379, + 1262.1859999781009, + 1248.7869999895338, + 1839.941899990663, + 1167.8303999942727, + 1430.7148999942, + 1243.0275000224356, + 1399.3319000001065, + 1412.8692999947816, + 1955.225400015479, + 1452.240200014785, + 1145.0364000047557, + 1345.0056000147015, + 2238.7201999954414, + 1348.99949998362, + 1238.1664999993518, + 1219.49659998063, + 1540.7543999899644, + 1167.9620000068098, + 1256.4046999905258, + 1133.6532999994233, + 1426.4445999870077, + 1327.1540999994613, + 1139.1213999886531, + 1132.6802000112366, + 1565.9596000041347, + 1162.8092000028118, + 1432.6138999895193, + 1929.122900008224, + 1253.8932999887038, + 1216.0526000079699, + 1177.2490000003017, + 1230.1964000216685, + 1236.9926999963354, + 1847.590699995635, + 1581.2800000130665, + 1344.8530999885406 + ] + } + }, + "details": { + "official_shell_pid": 57316, + "discarded_focus_cycles": 0, + "operations": [ + { + "name": "editor_state", + "unity_cli": { + "tool": "get_editor_state", + "params": {} + }, + "official": { + "tool": "editor_status", + "params": {} + } + }, + { + "name": "hierarchy", + "unity_cli": { + "tool": "get_hierarchy", + "params": {} + }, + "official": { + "tool": "get_scene_hierarchy", + "params": {} + } + }, + { + "name": "find_gameobject", + "unity_cli": { + "tool": "find_gameobject", + "params": { + "name": "Perf394Target", + "exactMatch": true + } + }, + "official": { + "tool": "find_gameobjects", + "params": { + "name": "Perf394Target" + } + } + }, + { + "name": "transform", + "unity_cli": { + "tool": "get_component_values", + "params": { + "gameObjectName": "Perf394Target", + "componentType": "Transform" + } + }, + "official": { + "tool": "get_component_properties", + "params": { + "target": { + "hierarchyPath": "/Perf394Target" + }, + "type": "Transform" + } + } + }, + { + "name": "position", + "unity_cli": { + "tool": "modify_gameobject", + "params": { + "path": "/Perf394Target", + "position": { + "x": 1, + "y": 2, + "z": 3 + } + } + }, + "official": { + "tool": "set_transform", + "params": { + "target": { + "hierarchyPath": "/Perf394Target" + }, + "position": [ + 1, + 2, + 3 + ] + } + } + }, + { + "name": "create_cube", + "unity_cli": { + "tool": "create_gameobject", + "params": { + "name": "Perf394Cube", + "primitiveType": "cube" + } + }, + "official": { + "tool": "create_gameobject", + "params": { + "name": "Perf394Cube", + "primitive": "Cube" + } + } + }, + { + "name": "add_component", + "unity_cli": { + "tool": "add_component", + "params": { + "gameObjectPath": "/Perf394Cube", + "componentType": "Rigidbody" + } + }, + "official": { + "tool": "add_component", + "params": { + "target": { + "hierarchyPath": "/Perf394Cube" + }, + "type": "Rigidbody" + } + } + }, + { + "name": "remove_component", + "unity_cli": { + "tool": "remove_component", + "params": { + "gameObjectPath": "/Perf394Cube", + "componentType": "Rigidbody" + } + }, + "official": { + "tool": "remove_component", + "params": { + "target": { + "hierarchyPath": "/Perf394Cube" + }, + "type": "Rigidbody" + } + } + }, + { + "name": "delete_gameobject", + "unity_cli": { + "tool": "delete_gameobject", + "params": { + "path": "/Perf394Cube" + } + }, + "official": { + "tool": "delete_gameobject", + "params": { + "target": { + "hierarchyPath": "/Perf394Cube" + } + } + } + }, + { + "name": "scene_info", + "unity_cli": { + "tool": "get_scene_info", + "params": {} + }, + "official": { + "tool": "list_open_scenes", + "params": {} + } + }, + { + "name": "scene_save", + "unity_cli": { + "tool": "save_scene", + "params": {} + }, + "official": { + "tool": "save_scene", + "params": {} + } + }, + { + "name": "console", + "unity_cli": { + "tool": "read_console", + "params": { + "count": 20 + } + }, + "official": { + "tool": "console", + "params": { + "tail": 20, + "level": "log" + } + } + }, + { + "name": "screenshot", + "unity_cli": { + "tool": "capture_screenshot", + "params": { + "captureMode": "game", + "width": 1280, + "height": 720, + "includeUI": false, + "encodeAsBase64": false, + "osFallback": false + } + }, + "official": { + "tool": "screenshot", + "params": { + "view": "game", + "width": 1280, + "height": 720 + } + } + }, + { + "name": "material_search", + "unity_cli": { + "tool": "manage_asset_database", + "params": { + "action": "find_assets", + "filter": "t:Material", + "searchInFolders": [ + "Assets/Scenes/Generated/E2E/Performance" + ] + } + }, + "official": { + "tool": "find_assets", + "params": { + "type": "Material", + "search_in": "Assets/Scenes/Generated/E2E/Performance" + } + } + }, + { + "name": "asset_copy", + "unity_cli": { + "tool": "manage_asset_database", + "params": { + "action": "copy_asset", + "fromPath": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat", + "toPath": "Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat" + } + }, + "official": { + "tool": "copy_asset", + "params": { + "asset": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat", + "destination": "Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat" + } + } + }, + { + "name": "asset_move", + "unity_cli": { + "tool": "manage_asset_database", + "params": { + "action": "move_asset", + "fromPath": "Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat", + "toPath": "Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat" + } + }, + "official": { + "tool": "move_asset", + "params": { + "asset": "Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat", + "destination": "Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat" + } + } + }, + { + "name": "asset_delete", + "unity_cli": { + "tool": "manage_asset_database", + "params": { + "action": "delete_asset", + "assetPath": "Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat" + } + }, + "official": { + "tool": "delete_asset", + "params": { + "asset": "Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat", + "confirm": true + } + } + }, + { + "name": "import_settings", + "unity_cli": { + "tool": "manage_asset_import_settings", + "params": { + "action": "get", + "assetPath": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat" + } + }, + "official": { + "tool": "get_import_settings", + "params": { + "asset": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat" + } + } + }, + { + "name": "material_modify", + "unity_cli": { + "tool": "modify_material", + "params": { + "materialPath": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat", + "properties": { + "_Color": [ + 0.2, + 0.4, + 0.8, + 1 + ] + } + } + }, + "official": { + "tool": "set_material_properties", + "params": { + "material": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat", + "properties": { + "_Color": [ + 0.2, + 0.4, + 0.8, + 1 + ] + } + } + } + }, + { + "name": "time_settings", + "unity_cli": { + "tool": "get_project_settings", + "params": { + "includeTime": true, + "includePlayer": false + } + }, + "official": { + "tool": "get_time_settings", + "params": {} + } + }, + { + "name": "read_csharp", + "unity_cli": { + "tool": "read", + "params": { + "path": "Assets/HotReloadProbe.cs", + "maxLines": 50 + } + }, + "official": { + "tool": "read_text_file", + "params": { + "path": "Assets/HotReloadProbe.cs" + } + } + }, + { + "name": "play_until_ready", + "unity_cli": { + "tool": "play_game", + "params": {} + }, + "official": { + "tool": "editor_play", + "params": {} + } + }, + { + "name": "stop_until_ready", + "unity_cli": { + "tool": "stop_game", + "params": {} + }, + "official": { + "tool": "editor_stop", + "params": {} + } + } + ] + }, + "results": { + "unity-cli": { + "editor_state": { + "n": 100, + "p50_ms": 201.96, + "p95_ms": 706.68, + "mean_ms": 259.85, + "min_ms": 36.12, + "max_ms": 1820.37 + }, + "hierarchy": { + "n": 100, + "p50_ms": 103.11, + "p95_ms": 899.01, + "mean_ms": 290.41, + "min_ms": 36.34, + "max_ms": 1398.22 + }, + "find_gameobject": { + "n": 100, + "p50_ms": 106.43, + "p95_ms": 707.95, + "mean_ms": 254.84, + "min_ms": 36.49, + "max_ms": 1507.42 + }, + "transform": { + "n": 100, + "p50_ms": 107.25, + "p95_ms": 701.11, + "mean_ms": 245.0, + "min_ms": 39.15, + "max_ms": 1203.65 + }, + "position": { + "n": 100, + "p50_ms": 103.13, + "p95_ms": 1102.66, + "mean_ms": 263.24, + "min_ms": 35.42, + "max_ms": 1300.12 + }, + "create_cube": { + "n": 100, + "p50_ms": 103.87, + "p95_ms": 902.3, + "mean_ms": 249.64, + "min_ms": 36.3, + "max_ms": 1401.41 + }, + "add_component": { + "n": 100, + "p50_ms": 102.21, + "p95_ms": 702.83, + "mean_ms": 245.54, + "min_ms": 37.19, + "max_ms": 1198.0 + }, + "remove_component": { + "n": 100, + "p50_ms": 102.97, + "p95_ms": 903.02, + "mean_ms": 273.51, + "min_ms": 35.58, + "max_ms": 1198.9 + }, + "delete_gameobject": { + "n": 100, + "p50_ms": 101.15, + "p95_ms": 602.33, + "mean_ms": 218.97, + "min_ms": 36.69, + "max_ms": 906.18 + }, + "scene_info": { + "n": 100, + "p50_ms": 100.75, + "p95_ms": 598.8, + "mean_ms": 202.4, + "min_ms": 35.37, + "max_ms": 1392.77 + }, + "scene_save": { + "n": 100, + "p50_ms": 193.74, + "p95_ms": 506.45, + "mean_ms": 294.34, + "min_ms": 124.36, + "max_ms": 1108.48 + }, + "console": { + "n": 100, + "p50_ms": 219.77, + "p95_ms": 423.74, + "mean_ms": 235.08, + "min_ms": 38.3, + "max_ms": 820.61 + }, + "screenshot": { + "n": 100, + "p50_ms": 206.83, + "p95_ms": 831.21, + "mean_ms": 375.57, + "min_ms": 124.11, + "max_ms": 1699.84 + }, + "material_search": { + "n": 100, + "p50_ms": 200.25, + "p95_ms": 563.19, + "mean_ms": 265.63, + "min_ms": 40.41, + "max_ms": 1602.8 + }, + "asset_copy": { + "n": 100, + "p50_ms": 162.34, + "p95_ms": 959.58, + "mean_ms": 304.38, + "min_ms": 94.28, + "max_ms": 1557.0 + }, + "asset_move": { + "n": 100, + "p50_ms": 263.8, + "p95_ms": 667.39, + "mean_ms": 305.59, + "min_ms": 87.02, + "max_ms": 1251.69 + }, + "asset_delete": { + "n": 100, + "p50_ms": 335.01, + "p95_ms": 662.07, + "mean_ms": 330.62, + "min_ms": 81.57, + "max_ms": 1450.5 + }, + "import_settings": { + "n": 100, + "p50_ms": 118.93, + "p95_ms": 914.9, + "mean_ms": 303.97, + "min_ms": 35.58, + "max_ms": 2713.06 + }, + "material_modify": { + "n": 100, + "p50_ms": 139.28, + "p95_ms": 932.2, + "mean_ms": 305.86, + "min_ms": 58.64, + "max_ms": 1718.34 + }, + "time_settings": { + "n": 100, + "p50_ms": 117.84, + "p95_ms": 914.9, + "mean_ms": 283.46, + "min_ms": 35.78, + "max_ms": 1533.42 + }, + "read_csharp": { + "n": 100, + "p50_ms": 37.44, + "p95_ms": 580.05, + "mean_ms": 208.51, + "min_ms": 31.68, + "max_ms": 1170.52 + }, + "play_until_ready": { + "n": 100, + "p50_ms": 822.01, + "p95_ms": 1466.44, + "mean_ms": 949.0, + "min_ms": 753.2, + "max_ms": 1962.39 + }, + "stop_until_ready": { + "n": 100, + "p50_ms": 737.03, + "p95_ms": 1428.65, + "mean_ms": 820.75, + "min_ms": 564.24, + "max_ms": 2275.12 + } + }, + "official": { + "editor_state": { + "n": 100, + "p50_ms": 705.11, + "p95_ms": 1094.77, + "mean_ms": 751.96, + "min_ms": 532.77, + "max_ms": 1472.75 + }, + "hierarchy": { + "n": 100, + "p50_ms": 691.88, + "p95_ms": 1272.59, + "mean_ms": 774.0, + "min_ms": 550.03, + "max_ms": 1816.48 + }, + "find_gameobject": { + "n": 100, + "p50_ms": 692.45, + "p95_ms": 1292.24, + "mean_ms": 797.85, + "min_ms": 530.96, + "max_ms": 2392.8 + }, + "transform": { + "n": 100, + "p50_ms": 895.84, + "p95_ms": 1391.78, + "mean_ms": 977.21, + "min_ms": 731.35, + "max_ms": 2303.65 + }, + "position": { + "n": 100, + "p50_ms": 694.65, + "p95_ms": 1316.5, + "mean_ms": 785.53, + "min_ms": 531.51, + "max_ms": 1816.6 + }, + "create_cube": { + "n": 100, + "p50_ms": 701.23, + "p95_ms": 1121.95, + "mean_ms": 756.86, + "min_ms": 548.43, + "max_ms": 1482.74 + }, + "add_component": { + "n": 100, + "p50_ms": 890.33, + "p95_ms": 1204.97, + "mean_ms": 944.28, + "min_ms": 722.33, + "max_ms": 2914.33 + }, + "remove_component": { + "n": 100, + "p50_ms": 909.0, + "p95_ms": 1511.48, + "mean_ms": 992.02, + "min_ms": 771.23, + "max_ms": 2204.13 + }, + "delete_gameobject": { + "n": 100, + "p50_ms": 702.73, + "p95_ms": 1195.75, + "mean_ms": 781.43, + "min_ms": 544.71, + "max_ms": 1904.85 + }, + "scene_info": { + "n": 100, + "p50_ms": 686.22, + "p95_ms": 1287.26, + "mean_ms": 776.22, + "min_ms": 579.58, + "max_ms": 2002.07 + }, + "scene_save": { + "n": 100, + "p50_ms": 813.59, + "p95_ms": 1310.85, + "mean_ms": 861.25, + "min_ms": 682.46, + "max_ms": 1701.95 + }, + "console": { + "n": 100, + "p50_ms": 618.18, + "p95_ms": 1146.31, + "mean_ms": 695.6, + "min_ms": 528.35, + "max_ms": 1423.5 + }, + "screenshot": { + "n": 100, + "p50_ms": 734.02, + "p95_ms": 1355.4, + "mean_ms": 819.6, + "min_ms": 594.51, + "max_ms": 1859.23 + }, + "material_search": { + "n": 100, + "p50_ms": 715.92, + "p95_ms": 1396.92, + "mean_ms": 793.89, + "min_ms": 580.72, + "max_ms": 1722.3 + }, + "asset_copy": { + "n": 100, + "p50_ms": 843.09, + "p95_ms": 1356.51, + "mean_ms": 863.13, + "min_ms": 642.61, + "max_ms": 1576.53 + }, + "asset_move": { + "n": 100, + "p50_ms": 682.49, + "p95_ms": 1277.85, + "mean_ms": 809.49, + "min_ms": 643.65, + "max_ms": 2125.85 + }, + "asset_delete": { + "n": 100, + "p50_ms": 684.14, + "p95_ms": 1192.27, + "mean_ms": 795.63, + "min_ms": 583.62, + "max_ms": 1673.47 + }, + "import_settings": { + "n": 100, + "p50_ms": 642.2, + "p95_ms": 1133.44, + "mean_ms": 756.03, + "min_ms": 538.11, + "max_ms": 1833.36 + }, + "material_modify": { + "n": 100, + "p50_ms": 653.47, + "p95_ms": 1244.54, + "mean_ms": 780.64, + "min_ms": 562.63, + "max_ms": 1683.6 + }, + "time_settings": { + "n": 100, + "p50_ms": 623.08, + "p95_ms": 1197.13, + "mean_ms": 733.17, + "min_ms": 529.13, + "max_ms": 1653.02 + }, + "read_csharp": { + "n": 100, + "p50_ms": 694.92, + "p95_ms": 1302.5, + "mean_ms": 746.98, + "min_ms": 525.39, + "max_ms": 1522.89 + }, + "play_until_ready": { + "n": 100, + "p50_ms": 1435.69, + "p95_ms": 2099.78, + "mean_ms": 1507.64, + "min_ms": 1074.85, + "max_ms": 2542.97 + }, + "stop_until_ready": { + "n": 100, + "p50_ms": 1441.33, + "p95_ms": 2158.01, + "mean_ms": 1526.86, + "min_ms": 1088.79, + "max_ms": 2351.45 + } + } + }, + "finished_at": "2026-10-04T01:30:32.840294+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/official-windows-resident-frontmost.json b/docs/verification/issue-386/resume/official-windows-resident-frontmost.json index 5a8202b3..7ea68731 100644 --- a/docs/verification/issue-386/resume/official-windows-resident-frontmost.json +++ b/docs/verification/issue-386/resume/official-windows-resident-frontmost.json @@ -1,9 +1,9 @@ { "mode": "resident", "focus": "frontmost", - "started_at": "2026-10-03T23:42:59.193309+00:00", + "started_at": "2026-10-04T00:00:36.400701+00:00", "conditions": { - "started_at": "2026-10-03T23:33:26.503448+00:00", + "started_at": "2026-10-04T00:00:25.043499+00:00", "os": "Windows-11-10.0.26300-SP0", "arch": "AMD64", "logical_cpus": 32, @@ -16,8 +16,8 @@ "pipeline_version": "0.8.0-exp.1", "unity_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", "official_cli_sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", - "benchmark_sha256": "857569c8c542221f43a27423ecfa8fce3d11a690ed979985ebc670a56912f372", - "windows_adapter_sha256": "1d72ca848808f1fcce45a46b133691c7c6119f908e67e9519f72759a19d5af7b", + "benchmark_sha256": "8b4a77c97260fec724a5d1187c1561a7a0f25d9c3734fe8eada1c0a3ca4bc1e6", + "windows_adapter_sha256": "c47d896f41e81c6db8ba63ced94e927388b55cc81796b54578b3135685929c8a", "windows_adapter": "Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.", "background_condition": "Owned Editor minimized, because Windows refused activation of the existing GWT background window. This differs from macOS visible-background measurements.", "host_contention": "Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.", @@ -39,9 +39,5474 @@ "unityRemoteCompression": "", "unityRemoteResolution": "" }, - "unityd_pid": 52020 + "unityd_pid": 56288 }, - "status": "FAIL", - "error": "Invalid official NDJSON response: {'id': '15', 'exitCode': 6, 'envelope': {'success': False, 'command': 'unity command find_assets', 'data': None, 'errors': [{'code': 'COMMAND_FAILED', 'message': 'Pipeline server returned 400 Bad Request: Parameter Validation Failed. Illegal characters in path.'}], 'warnings': []}}", - "finished_at": "2026-10-03T23:43:15.759312+00:00" + "status": "PASS", + "samples_ms": { + "unity-cli": { + "editor_state": [ + 41.870899993227795, + 414.5974999992177, + 303.7406999792438, + 235.111699992558, + 341.67039999738336, + 210.3310000093188, + 645.070799975656, + 34.11390000837855, + 218.5532000148669, + 692.228800005978, + 70.38509999983944, + 344.71669999766164, + 368.15789999673143, + 158.3845000131987, + 42.02750002150424, + 105.06389997317456, + 57.44939998839982, + 33.94009999465197, + 308.98279999382794, + 271.8653999909293, + 401.8985999864526, + 675.3657000081148, + 449.05819999985397, + 259.9427000095602, + 242.54010000731796, + 1160.0046000094153, + 40.070700022624806, + 215.27459999197163, + 42.14430000865832, + 304.3216000078246, + 927.3754000023473, + 237.5389999942854, + 272.49139998457395, + 400.5980000074487, + 287.02619997784495, + 187.9921999934595, + 109.39019999932498, + 37.47539999312721, + 41.19560000253841, + 294.34790002414957, + 94.03060001204722, + 36.27419998520054, + 48.6525000014808, + 414.91059999680147, + 39.11129999323748, + 438.198799995007, + 426.2561000068672, + 357.4425000115298, + 417.64499997952953, + 328.1507999927271, + 64.39240000327118, + 318.1615999783389, + 300.4252999962773, + 262.59830000344664, + 281.6244999994524, + 33.446600020397455, + 41.515399992931634, + 207.6836999913212, + 231.79809999419376, + 104.13249998237006, + 223.44160001375712, + 37.46039999532513, + 250.97640001331456, + 197.05509999766946, + 1246.8755999871064, + 183.09199999202974, + 43.117099994560704, + 863.6865000007674, + 700.7428999932017, + 567.4403000157326, + 39.17110001202673, + 34.72840000176802, + 41.2740999890957, + 99.04639999149367, + 279.27299999282695, + 275.01469998969696, + 37.938699999358505, + 35.63890000805259, + 151.4813999820035, + 331.7735999880824, + 70.57029998395592, + 34.15059999679215, + 141.03450000402518, + 151.70700001181103, + 47.12060000747442, + 37.938800000119954, + 715.67179998965, + 35.772800008999184, + 177.9130999930203, + 606.9908999779727, + 1030.7083999796305, + 38.26949998619966, + 40.10090001975186, + 267.5229999877047, + 309.85960000543855, + 47.50350001268089, + 329.9047999898903, + 669.5058999757748, + 122.39369997405447, + 276.5275999845471 + ], + "hierarchy": [ + 39.515000011306256, + 579.8937999934424, + 348.0917999986559, + 338.707599992631, + 334.68580001499504, + 611.7119999835268, + 828.9419999928214, + 41.0756999917794, + 36.09040001174435, + 34.810899989679456, + 38.076700002420694, + 340.40610000374727, + 39.08269997918978, + 313.22159999399446, + 37.60569999576546, + 40.881299995817244, + 37.27109997998923, + 38.01220000605099, + 328.7737999926321, + 37.51260001445189, + 324.80619999114424, + 585.6596999801695, + 42.59269998874515, + 39.70160000608303, + 307.99699999624863, + 881.6889000008814, + 37.58950001792982, + 315.71870000334457, + 35.913499974412844, + 41.05790000176057, + 559.9666000052821, + 35.83439998328686, + 350.8166999963578, + 588.663100003032, + 35.581400006776676, + 43.16390000167303, + 39.84360001049936, + 310.16409999574535, + 36.51390000595711, + 35.06510000443086, + 35.478299978422, + 317.2931000008248, + 307.7126999851316, + 861.0879000043496, + 326.94769999943674, + 913.335300021572, + 569.9660000100266, + 582.7127999800723, + 1425.056100008078, + 37.17299998970702, + 35.85020001628436, + 35.61910000280477, + 39.40779998083599, + 38.955199997872114, + 40.72779999114573, + 321.12760000745766, + 39.62970001157373, + 326.1190000048373, + 313.9303000061773, + 329.09519999520853, + 35.38399998797104, + 37.16030000941828, + 40.04320001695305, + 42.561200010823086, + 36.02939998381771, + 39.063099975464866, + 40.663299994776025, + 36.32159999688156, + 40.8830999804195, + 40.68059998098761, + 37.867599981836975, + 36.113399983150885, + 35.369499993976206, + 36.160599993309006, + 322.74400000460446, + 41.231000010157004, + 36.2604999972973, + 36.31560000940226, + 39.41810000105761, + 36.7289999849163, + 38.52189998724498, + 37.9428000014741, + 590.1367999904323, + 336.7106000077911, + 38.78850000910461, + 36.53649997431785, + 37.95110000646673, + 35.7357999891974, + 38.6313000053633, + 1172.6027999829967, + 41.9572000100743, + 320.0490999734029, + 37.243800004944205, + 299.68860000371933, + 40.24659999413416, + 68.43450001906604, + 35.49670000211336, + 303.9885000034701, + 36.74519999185577, + 344.7236999927554 + ], + "find_gameobject": [ + 37.886899983277544, + 38.732700020773336, + 328.01759999711066, + 35.49439998460002, + 296.6399000142701, + 1169.4147000089288, + 38.059999991673976, + 35.135000012815, + 35.26330000022426, + 34.967899991897866, + 36.932699993485585, + 1558.0541999952402, + 38.192199979675934, + 573.1814999890048, + 37.125199974980205, + 37.40200001630001, + 38.778899994213134, + 313.1682999955956, + 318.42100000358187, + 313.693299976876, + 319.79259999934584, + 36.35410001152195, + 38.431900000432506, + 328.02410001750104, + 562.6106999989133, + 37.448099988978356, + 37.82950001186691, + 592.3000999900978, + 37.076500011608005, + 314.67270001303405, + 34.34830001788214, + 36.96779999881983, + 598.6518999852706, + 34.80399999534711, + 35.0633000198286, + 36.926899978425354, + 39.63620000286028, + 35.296799993375316, + 35.08999999030493, + 326.15989999612793, + 307.83259999589063, + 34.84430001117289, + 323.4969000041019, + 37.09210001397878, + 305.7662000064738, + 613.9419999963138, + 569.2071000230499, + 546.0933999856934, + 37.66729999915697, + 39.16919999755919, + 37.80739998910576, + 38.65169998607598, + 318.1526999978814, + 320.64650001120754, + 39.026300015393645, + 36.50849999394268, + 35.78389997710474, + 888.605699990876, + 284.346899978118, + 301.657099975273, + 35.8921000151895, + 34.6074000117369, + 39.174400008050725, + 34.673500020289794, + 52.27830001967959, + 35.43749998789281, + 46.054800011916086, + 36.102899990510195, + 36.47369999089278, + 34.82030000304803, + 34.72029999829829, + 37.97810000833124, + 38.13949998584576, + 36.39569997903891, + 862.069299997529, + 37.497000012081116, + 35.79809999791905, + 35.35239998018369, + 37.294100009603426, + 35.817099997075275, + 34.54910000436939, + 35.42699999525212, + 899.4540999992751, + 332.1969000098761, + 37.497300014365464, + 35.66480000154115, + 36.5307999891229, + 35.89589998591691, + 38.432900008047, + 1671.6810000070836, + 38.13189998618327, + 34.28930000518449, + 36.18379999534227, + 307.58849999983795, + 360.7186000153888, + 50.981199980014935, + 312.83320000511594, + 33.79049999057315, + 38.205899996683, + 356.0767000017222 + ], + "transform": [ + 40.07270000874996, + 38.20350000751205, + 321.28480001119897, + 333.7552000011783, + 596.10760002397, + 39.08970000338741, + 39.54310002154671, + 40.051400021184236, + 39.16430001845583, + 36.5610999870114, + 38.97950000828132, + 602.4519999918994, + 42.592599987983704, + 610.609099996509, + 40.81189999124035, + 40.15450002043508, + 358.5597999917809, + 40.71270002168603, + 291.58280001138337, + 39.30669999681413, + 297.27140002069063, + 38.48190000280738, + 40.55609999340959, + 351.6356000036467, + 40.2472999994643, + 36.267399991629645, + 323.1740999908652, + 564.8399000056088, + 320.7506000180729, + 326.3376999821048, + 37.23000001627952, + 42.60769998654723, + 1156.4983999996912, + 40.85180000402033, + 41.082599986111745, + 39.119699998991564, + 40.38379999110475, + 37.72560000652447, + 40.78010001103394, + 353.14049999578856, + 37.562399986200035, + 42.09849998005666, + 329.5211999793537, + 40.44060001615435, + 312.9711999790743, + 39.134600025136024, + 38.56449999148026, + 37.17190001043491, + 46.80219999863766, + 37.98240001196973, + 327.56659999722615, + 41.02020000573248, + 330.81480002147146, + 39.37919999589212, + 42.07419999875128, + 318.09240000438876, + 40.78840001602657, + 37.321100011467934, + 327.77050000731833, + 924.2165999894496, + 42.82019997481257, + 38.57969999080524, + 40.75029998784885, + 38.89029999845661, + 37.88409999106079, + 39.258900011191145, + 41.577700001653284, + 37.10109999519773, + 38.529699988430366, + 39.98610001872294, + 38.18070000852458, + 38.55540000949986, + 38.814400002593175, + 41.974499996285886, + 1094.802500010701, + 310.8240999863483, + 38.24749999330379, + 39.08789998968132, + 40.217500005383044, + 328.9972000056878, + 41.19749998790212, + 324.6355000010226, + 40.054400014923885, + 318.73450000421144, + 341.8481000117026, + 37.32910001417622, + 36.163799988571554, + 36.731300002429634, + 41.24010002124123, + 37.50700000091456, + 38.12569999718107, + 334.98020001570694, + 332.78619998600334, + 316.525999980513, + 325.0590999959968, + 43.767499999376014, + 340.0516999827232, + 42.38710002391599, + 39.26540000247769, + 642.0820000057574 + ], + "position": [ + 36.698399984743446, + 36.309000017354265, + 591.3062999898102, + 38.65329999825917, + 862.5418999872636, + 35.52760000457056, + 36.309099989011884, + 319.13259997963905, + 36.77189999143593, + 37.83290000865236, + 35.67529999418184, + 591.2406999850646, + 42.548099998384714, + 560.9172999975272, + 45.46929997741245, + 39.723900001263246, + 37.03700000187382, + 41.04810001445003, + 556.7994000157341, + 281.1683999898378, + 841.1450000130571, + 38.057400000980124, + 34.07839999999851, + 334.25489999353886, + 36.76000001723878, + 36.888400005409494, + 40.2786000049673, + 40.20970000419766, + 36.683599988464266, + 318.3001999859698, + 36.37220000382513, + 38.605599984293804, + 37.34629999962635, + 36.50499999639578, + 37.375699990661815, + 41.125699994154274, + 39.67180001200177, + 36.064600019017234, + 329.4615999911912, + 327.8373000212014, + 322.866200003773, + 290.6636999978218, + 305.7975999836344, + 34.6533999836538, + 598.9335000049323, + 35.174100019503385, + 36.25639999518171, + 35.09779999149032, + 37.978699983796105, + 37.365299998782575, + 35.697200015420094, + 307.8710999980103, + 596.9620999821927, + 39.61759997764602, + 37.91700000874698, + 874.3407000147272, + 38.44440000830218, + 35.28609999921173, + 313.3281999907922, + 608.5784000169951, + 36.91369999432936, + 302.664899994852, + 38.33969999686815, + 37.741800013463944, + 40.6735000142362, + 347.50809997785836, + 39.208400005009025, + 36.158000002615154, + 37.57529999711551, + 43.41810001642443, + 38.28469998552464, + 34.66479998314753, + 37.111100013135, + 335.485100018559, + 589.1995999845676, + 34.20160000678152, + 36.44860000349581, + 289.9990000005346, + 36.79280000505969, + 37.30550000909716, + 36.92900002351962, + 35.13619999284856, + 35.75260000070557, + 560.4364999744575, + 36.59709999919869, + 35.80250000231899, + 35.566800012020394, + 36.65660001570359, + 35.94669999438338, + 37.80269998242147, + 39.404099981766194, + 1190.9095000009984, + 38.552099984372035, + 326.1410999984946, + 326.8174000259023, + 349.97870001825504, + 327.9954000026919, + 36.704500002088025, + 38.13510001054965, + 332.76190000469796 + ], + "create_cube": [ + 37.55680000176653, + 36.960899975383654, + 572.7349999942817, + 329.96360000106506, + 36.82880001724698, + 37.732800003141165, + 36.69489998719655, + 41.19560000253841, + 295.7668000017293, + 33.80460001062602, + 38.737399998353794, + 1221.477400016738, + 319.6381999878213, + 1179.7187999763992, + 37.59920000447892, + 36.36560001177713, + 320.9721999883186, + 39.67840000404976, + 35.43349998653866, + 313.97370001650415, + 589.344500011066, + 39.12189998663962, + 36.103099992033094, + 898.571500001708, + 34.29650000180118, + 36.71519999625161, + 36.99240001151338, + 41.20490001514554, + 33.47130000474863, + 312.33690000954084, + 34.747500001685694, + 38.41180002200417, + 38.33199999644421, + 38.40810002293438, + 39.71280000405386, + 39.33899998082779, + 40.48650001641363, + 37.81639999942854, + 34.21519999392331, + 627.5565000250936, + 314.0723000105936, + 587.6298999937717, + 301.49410001467913, + 36.84860002249479, + 1136.5763999929186, + 36.906099994666874, + 35.93469999032095, + 36.243899987312034, + 36.40729998005554, + 303.4077000047546, + 310.84210000699386, + 37.26660000393167, + 591.3092000118922, + 305.30710000311956, + 42.918299994198605, + 39.691399986622855, + 302.4227000132669, + 34.19410000788048, + 277.50100000412203, + 41.05100000742823, + 38.62940001999959, + 46.86040000524372, + 39.0594000054989, + 37.66800000448711, + 323.27389999409206, + 42.09200001787394, + 40.514099993743, + 36.826199997449294, + 39.371599996229634, + 36.322299973107874, + 36.88729999703355, + 363.29189999378286, + 315.27349998941645, + 39.9875000002794, + 38.535700005013496, + 327.62900000670925, + 37.72490000119433, + 40.37380000227131, + 36.84169999905862, + 37.89790000882931, + 36.37159999925643, + 40.17220000969246, + 42.54160000709817, + 1432.581700006267, + 37.72600000957027, + 37.488500005565584, + 36.75010000006296, + 37.82840000349097, + 324.6229000214953, + 39.38679999555461, + 41.883999976562336, + 282.5903000193648, + 40.07640000781976, + 891.9233000196982, + 954.3236000172328, + 51.038899982813746, + 334.9289000034332, + 38.811399979749694, + 378.0935000104364, + 328.55919998837635 + ], + "add_component": [ + 48.40959998546168, + 54.748900001868606, + 53.48130001220852, + 583.9697000046726, + 50.828500010538846, + 53.33049999899231, + 55.46279999543913, + 58.80970001453534, + 51.19790000026114, + 50.45270000118762, + 297.9291999945417, + 55.10409999988042, + 52.49669999466278, + 878.837999975076, + 64.72239998402074, + 53.84559999220073, + 324.0691999963019, + 53.65310001070611, + 49.15700000128709, + 48.11329999938607, + 50.69329999969341, + 58.78260001190938, + 48.9755000162404, + 332.53030001651496, + 47.619499993743375, + 49.330800015013665, + 49.94389999774285, + 56.03700000210665, + 47.529199975542724, + 304.35079999733716, + 48.85160000412725, + 49.68100000405684, + 53.3661000081338, + 47.92949999682605, + 49.46069998550229, + 327.107299992349, + 320.3395000018645, + 50.348599994322285, + 49.77290000533685, + 49.979900009930134, + 561.9261999963783, + 1121.364699996775, + 325.0537000130862, + 50.34529999829829, + 908.1306000007316, + 49.79099999764003, + 46.917200001189485, + 48.561599978711456, + 50.184099993202835, + 51.85200000414625, + 51.23120002099313, + 329.23719999962486, + 52.76309998589568, + 309.9942000117153, + 51.79679999127984, + 58.56380000477657, + 50.55059998994693, + 47.764599992660806, + 902.2018999967258, + 55.96299999160692, + 49.311299982946366, + 42.28329999023117, + 49.641799996607006, + 49.22450002050027, + 50.72299999301322, + 53.224500006763265, + 49.914499977603555, + 48.20660001132637, + 48.79939998500049, + 53.79850001190789, + 49.638900003628805, + 56.10390001675114, + 49.47719999472611, + 321.18179998360574, + 53.72329999227077, + 51.01919997832738, + 49.09280000720173, + 47.47690001386218, + 48.872999992454425, + 304.2511999956332, + 51.54600000241771, + 49.255099991569296, + 48.52119999122806, + 64.2029000155162, + 48.221000004559755, + 53.19419997977093, + 57.97210001037456, + 50.20840000361204, + 51.90459999721497, + 52.82939999597147, + 49.113100016256794, + 280.97449999768287, + 296.9343999866396, + 1177.7949999959674, + 66.80159998359159, + 66.71039998764172, + 897.8495999763254, + 51.62070001824759, + 55.852599994977936, + 587.4634000065271 + ], + "remove_component": [ + 42.20249998616055, + 48.00410001189448, + 41.56189999775961, + 594.6005999867339, + 45.80829999758862, + 54.23420001170598, + 332.427799992729, + 328.6140999989584, + 299.43280000588857, + 41.99639998842031, + 39.855799986980855, + 53.06239999481477, + 52.457100013270974, + 43.894899979932234, + 43.67179999826476, + 45.15630000969395, + 581.2745000002906, + 69.718799990369, + 44.25400000764057, + 304.5951999956742, + 39.77499998291023, + 42.49839999829419, + 44.06769998604432, + 48.924700007773936, + 41.41659999731928, + 41.13259998848662, + 311.21250000433065, + 48.01890000817366, + 48.991299991030246, + 564.6597000013571, + 40.37559998687357, + 45.9848000027705, + 45.97399997874163, + 44.011599995428696, + 43.78040001029149, + 41.88499998417683, + 46.9149999844376, + 43.30250000930391, + 301.6069000004791, + 52.0128000061959, + 592.2122999909334, + 38.4071999869775, + 276.583800005028, + 41.548000008333474, + 51.24280002200976, + 46.29019999993034, + 42.37559999455698, + 47.14740000781603, + 44.82280000229366, + 43.23640000075102, + 307.6615000027232, + 38.507500023115426, + 46.822500007692724, + 612.6014000037685, + 329.3765000125859, + 44.26719999173656, + 44.68549997545779, + 46.2822999979835, + 62.844600004609674, + 42.14109998429194, + 313.60890000360087, + 38.780300004873425, + 51.82779999449849, + 45.85470000165515, + 45.01600001822226, + 44.50990000623278, + 319.60909999907017, + 43.025099992519245, + 39.90999999223277, + 42.41670001647435, + 48.167800006922334, + 50.37910002283752, + 43.82710001664236, + 334.5837999950163, + 43.616100010694936, + 304.68909998307936, + 45.475499995518476, + 42.474100016988814, + 327.3157000076026, + 36.98500001337379, + 302.5869999837596, + 291.5237999986857, + 44.186599989188835, + 53.411200002301484, + 331.0324999911245, + 324.80869998107664, + 46.814900008030236, + 41.24349998892285, + 44.04790000990033, + 49.22149999765679, + 44.90340000484139, + 40.626500005600974, + 38.17600000184029, + 837.4936000036541, + 51.0824000230059, + 354.588899994269, + 1192.2685999888927, + 50.7406999822706, + 47.51199999009259, + 927.8035000024829 + ], + "delete_gameobject": [ + 36.50479999487288, + 36.6554000065662, + 38.93660000176169, + 38.32429999602027, + 39.64060000726022, + 39.57340001943521, + 36.21359998942353, + 40.94889998668805, + 317.453800002113, + 39.4903999986127, + 41.639900009613484, + 38.13239998999052, + 305.000199994538, + 39.94899999815971, + 42.87939998903312, + 282.17030002269894, + 42.80250001465902, + 40.7532999815885, + 43.650200008414686, + 303.8521000125911, + 38.504700001794845, + 324.22939999378286, + 40.43870000168681, + 51.37449997710064, + 40.64039999502711, + 40.869300020858645, + 34.554499987279996, + 39.799700025469065, + 301.1813999910373, + 578.1389999901876, + 328.87769999797456, + 314.87299999571405, + 41.46399997989647, + 38.70430000824854, + 39.47010001866147, + 42.99149999860674, + 40.934699994977564, + 39.9221999978181, + 44.5385999919381, + 39.04020000481978, + 37.865999998757616, + 37.90680001839064, + 320.9068000141997, + 38.895800011232495, + 42.09850000916049, + 40.94109998550266, + 38.01600000588223, + 48.24259999440983, + 41.33720000390895, + 317.75289998040535, + 323.2253000023775, + 37.541500001680106, + 37.37020000698976, + 811.2898000108544, + 41.804200009210035, + 37.59160000481643, + 38.34130000905134, + 38.71710001840256, + 41.469399991910905, + 37.36630000639707, + 37.02619997784495, + 302.01519999536686, + 37.69100000499748, + 40.43480000109412, + 39.488300011726096, + 328.3804999955464, + 48.32799997529946, + 293.9386999933049, + 39.12649999256246, + 36.48479998810217, + 297.51850001048297, + 314.9167000083253, + 37.74639999028295, + 316.2674000195693, + 46.245900011854246, + 332.2623999847565, + 310.4221999819856, + 318.5158000269439, + 35.82810002262704, + 338.74579999246635, + 38.855799997691065, + 35.19900000537746, + 39.780399994924664, + 40.961300022900105, + 38.28490001615137, + 39.070800004992634, + 309.9800999916624, + 37.61340002529323, + 325.93169997562654, + 39.55180000048131, + 40.96620000200346, + 37.46339998906478, + 38.338900019880384, + 39.22850001254119, + 43.79000002518296, + 43.13700000056997, + 43.31639999873005, + 327.59420000365935, + 43.4123000013642, + 602.2783000080381 + ], + "scene_info": [ + 36.20919998502359, + 36.498700006632134, + 37.67669998342171, + 35.08999999030493, + 37.23590000299737, + 36.33690002607182, + 35.06120000383817, + 35.212699993280694, + 319.9536000029184, + 315.3634000045713, + 40.777500020340085, + 34.64240001630969, + 37.61659999145195, + 38.799600006313995, + 349.9365999887232, + 36.60009999293834, + 35.31589999329299, + 38.242599985096604, + 39.43900001468137, + 548.8862999773119, + 34.84169999137521, + 38.033599994378164, + 38.51110002142377, + 48.223899997537956, + 35.1743999926839, + 35.987500014016405, + 326.41200002399273, + 40.08320000139065, + 320.81360000302084, + 36.526599986245856, + 37.04329999163747, + 37.461800005985424, + 36.054299998795614, + 35.82850002567284, + 35.830300010275096, + 38.258900021901354, + 38.41090001515113, + 36.3567000022158, + 581.3395000004675, + 41.174400015734136, + 35.142799984896556, + 36.95380000863224, + 278.5141000058502, + 297.4546999903396, + 40.22969998186454, + 38.108999986434355, + 36.1581000033766, + 36.44259998691268, + 312.212399992859, + 38.017300015781075, + 315.6681000255048, + 296.4270999946166, + 37.6168999937363, + 36.7545000044629, + 37.78390001389198, + 35.2024000021629, + 297.36070000217296, + 37.93179997592233, + 38.553399994270876, + 35.31750000547618, + 37.47260000091046, + 34.46980001172051, + 334.25610000267625, + 44.283099996391684, + 324.62969998596236, + 37.80920000281185, + 37.178800004767254, + 36.97069999179803, + 38.431900000432506, + 35.75899999123067, + 40.607100003398955, + 35.83670000080019, + 36.28610001760535, + 302.2911000007298, + 38.38240000186488, + 887.1838999912143, + 35.99709999980405, + 39.65029999380931, + 35.15389998210594, + 331.95699998759665, + 35.46820001793094, + 36.99960000813007, + 34.313400014070794, + 37.57499999483116, + 36.79129999363795, + 35.52760000457056, + 38.37819999898784, + 35.73649999452755, + 36.25659999670461, + 34.341299993684515, + 36.19679997791536, + 45.903899997938424, + 330.5199999886099, + 36.938600009307265, + 45.884599996497855, + 48.22629998670891, + 38.61089999554679, + 41.276600008131936, + 377.5235000066459, + 37.646799988579005 + ], + "scene_save": [ + 125.06640001083724, + 130.85549999959767, + 128.68180000805296, + 127.56619998253882, + 131.44530000863597, + 131.36389999999665, + 126.45939999492839, + 402.2368000005372, + 971.4472999912687, + 126.63729998166673, + 128.47460000193678, + 132.93409999459982, + 423.5200000111945, + 129.31030002073385, + 127.1032000076957, + 127.94229999417439, + 124.97949998942204, + 420.23009998956695, + 125.03620001371019, + 659.6465999900829, + 126.15070000174455, + 128.99260001722723, + 125.79259998165071, + 187.0037000044249, + 129.70900000073016, + 144.32650001253933, + 127.83710000803694, + 130.6285000173375, + 698.2169999973848, + 124.53120001009665, + 134.98770000296645, + 126.51249999180436, + 395.33729999675415, + 123.66410001413897, + 127.59379998897202, + 131.9233999820426, + 148.45839998451993, + 398.23240000987425, + 698.8112999824807, + 129.57089999690652, + 135.42819998110645, + 127.69049999769777, + 373.2714999932796, + 127.24520001211204, + 145.2172999852337, + 132.03019998036325, + 126.45020001218654, + 125.04100002115592, + 133.2639000029303, + 125.7016999879852, + 689.2747999809217, + 124.64630001340993, + 124.93940000422299, + 132.66730000032112, + 131.63550000172108, + 125.50079997163266, + 126.47109999670647, + 125.1271000073757, + 130.1779999921564, + 130.05629999679513, + 128.8263000024017, + 127.20149999950081, + 131.91709999227896, + 406.1738000018522, + 128.96130001172423, + 424.4294000091031, + 134.94380001793616, + 126.59960001474246, + 122.29289999231696, + 131.6633000096772, + 136.8922000110615, + 125.42710002162494, + 129.73519999650307, + 397.8184000006877, + 411.48470001644455, + 647.3336000053678, + 138.77059999504127, + 129.62819999665953, + 123.9140999969095, + 137.79239999712445, + 419.1190999990795, + 398.4173000208102, + 402.53190000657924, + 132.60209999862127, + 405.9214000008069, + 139.03099999879487, + 130.5374999938067, + 127.19169998308644, + 407.57599999778904, + 135.21869998658076, + 455.6270999892149, + 154.24550001625903, + 126.52260001050308, + 130.1042000122834, + 131.46870001219213, + 458.0558000016026, + 135.32820000546053, + 132.59290001587942, + 139.08699998864904, + 135.7354000210762 + ], + "console": [ + 38.78540001460351, + 233.99009997956455, + 38.63249998539686, + 41.4984000090044, + 39.419300010195, + 37.541600002441555, + 297.1436000079848, + 265.2055000071414, + 40.12499999953434, + 314.5348999823909, + 223.09290000703186, + 43.03450000588782, + 263.800100015942, + 272.5170999765396, + 40.2194999915082, + 39.427599986083806, + 41.53809999115765, + 41.389399993931875, + 231.58160000457428, + 191.74829998519272, + 311.1736999999266, + 41.85040001175366, + 273.6942000046838, + 47.62130000744946, + 39.60439999355003, + 271.3530999899376, + 226.4611999853514, + 241.7360999970697, + 194.52740001725033, + 42.24020001129247, + 40.59119999874383, + 40.15469999285415, + 39.07599998638034, + 237.62410000199452, + 278.1097000115551, + 303.04649999015965, + 217.19149997807108, + 40.296099992701784, + 37.876499991398305, + 40.41950000100769, + 36.51740000350401, + 40.018899977440014, + 36.755000008270144, + 38.90370001317933, + 40.739100018981844, + 342.5221999932546, + 295.77600001357496, + 239.04119999497198, + 37.65479999128729, + 232.54490000545047, + 796.6768000042066, + 218.9238999853842, + 260.2949000138324, + 37.72910000407137, + 306.8435000022873, + 39.817200013203546, + 269.92590000736527, + 218.00100000109524, + 309.0948000026401, + 39.328299986664206, + 297.5815999961924, + 213.13789999112487, + 39.14070001337677, + 40.09340002085082, + 44.3000000086613, + 297.1733000013046, + 229.3599999975413, + 41.14109999500215, + 39.38420000486076, + 227.11949999211356, + 39.39630000968464, + 261.8769000109751, + 235.69649999262765, + 790.8317999972496, + 41.225099994335324, + 40.78170002321713, + 39.267599990125746, + 239.90230000345036, + 284.8995999956969, + 49.55130000598729, + 41.691699996590614, + 238.5884000104852, + 38.88489998644218, + 236.53250001370907, + 289.08030001912266, + 40.755399997578934, + 38.62399997888133, + 211.71860001049936, + 281.72560001257807, + 301.2888999946881, + 37.39680000580847, + 52.29510000208393, + 254.70569997560233, + 37.39539999514818, + 264.6361999795772, + 323.92029999755323, + 319.23429999733344, + 342.80389998457395, + 309.1372999770101, + 42.44089999701828 + ], + "screenshot": [ + 375.46629999997094, + 90.45340001466684, + 372.7182000002358, + 95.22680001100525, + 378.77660000231117, + 352.15019999304786, + 96.06860001804307, + 380.53579998086207, + 97.13539999211207, + 95.45629998319782, + 96.89850002177991, + 96.5215000032913, + 366.2430999975186, + 98.11809999519028, + 91.75540000433102, + 96.0561000101734, + 94.6125999907963, + 94.86159999505617, + 91.1437000031583, + 93.02509998087771, + 95.36480001406744, + 94.07950000604615, + 103.41099998913705, + 102.25540000828914, + 371.35899998247623, + 91.36429999489337, + 366.13580002449453, + 98.30290000536479, + 90.81239998340607, + 92.5606999953743, + 388.31529999151826, + 364.8652999836486, + 94.76330000325106, + 91.68539999518543, + 94.04610001365654, + 97.01879997737706, + 95.91189998900518, + 95.52209998946637, + 93.59000000404194, + 97.67810002085753, + 93.73779999441467, + 92.56740001728758, + 95.05910001462325, + 97.40699999383651, + 93.0027999856975, + 93.76150000025518, + 92.51429999130778, + 99.28609998314641, + 93.06489999289624, + 97.59109999868087, + 648.0173000018112, + 362.40250000264496, + 92.9898000031244, + 95.94379999907687, + 97.22440000041388, + 381.62590001593344, + 355.0443999993149, + 93.69660000083968, + 95.47429997473955, + 96.30929998820648, + 93.1198000034783, + 91.96759999031201, + 94.88000001874752, + 92.07890002289787, + 340.28720000060275, + 695.9296000131872, + 100.39260002668016, + 382.15930000296794, + 380.5008000053931, + 91.31859999615699, + 108.73149998951703, + 93.99380002287216, + 90.94600001117215, + 629.7910000139382, + 390.34660000470467, + 92.45360002387315, + 377.2997999913059, + 378.99040000047535, + 95.66789999371395, + 98.38300000410527, + 92.02129999175668, + 595.8465999865439, + 92.83559999312274, + 91.61689999746159, + 411.6284000047017, + 99.39849999500439, + 96.58690000651404, + 91.56760000041686, + 404.13229999830946, + 101.5283000015188, + 101.90459998557344, + 93.80069997860119, + 362.8043000062462, + 352.06319999997504, + 98.84059999603778, + 84.05660002608784, + 95.6047999789007, + 94.67200000653975, + 96.03859999333508, + 100.50430000410415 + ], + "material_search": [ + 40.57549999561161, + 39.938900008564815, + 39.91019999375567, + 39.17340000043623, + 45.33130000345409, + 38.534399995114654, + 301.34049998014234, + 262.437500001397, + 39.91929997573607, + 279.17900000466034, + 44.47760002221912, + 288.14540000166744, + 244.40120000508614, + 44.558599998708814, + 40.24589998880401, + 40.8315000240691, + 39.297499984968454, + 257.0881000137888, + 41.8727999785915, + 37.23750001518056, + 39.44630001205951, + 263.06470000417903, + 41.4357999979984, + 395.3738999844063, + 41.41850001178682, + 44.1012000082992, + 534.867900016252, + 42.905000009341165, + 38.12709997873753, + 42.444299993803725, + 41.696000000229105, + 313.5447000095155, + 38.5977000114508, + 40.00339997583069, + 42.919900006381795, + 40.01789999892935, + 319.9274999788031, + 295.25009999633767, + 39.10349999205209, + 277.3862999747507, + 39.01030000997707, + 320.60370000544935, + 39.40589999547228, + 313.678800011985, + 304.8416000092402, + 39.52000002027489, + 43.157000007340685, + 40.29239999363199, + 288.30879999441095, + 290.55040000821464, + 42.07709999172948, + 800.2530999947339, + 42.26580000249669, + 274.9031000130344, + 315.3471000259742, + 38.94279999076389, + 586.8780999735463, + 40.847099997336045, + 43.32309999153949, + 275.90409998083487, + 300.2118999720551, + 279.0986000036355, + 40.987899992614985, + 41.690000012749806, + 42.64510000939481, + 845.3479000017978, + 292.63779998291284, + 43.8752000045497, + 42.37529999227263, + 38.882399996509776, + 41.492999996989965, + 284.9500000011176, + 39.49370002374053, + 40.93920000013895, + 60.20039998111315, + 38.967100001173094, + 40.65999999875203, + 548.9902999834158, + 309.67600000440143, + 40.61360002378933, + 339.41880002385005, + 805.4647000099067, + 316.86669998453, + 40.712299989536405, + 329.1789999930188, + 362.403400009498, + 309.2912999854889, + 48.945000016829, + 860.0042999896687, + 39.97179999714717, + 39.48889998719096, + 40.27480000513606, + 284.06780000659637, + 54.676300002029166, + 72.32559999101795, + 327.0884999947157, + 43.825200002174824, + 42.64530001091771, + 347.83519999473356, + 43.35139997419901 + ], + "asset_copy": [ + 94.01229998911731, + 100.44969999580644, + 105.03229999449104, + 97.42850001202896, + 101.67199998977594, + 97.43949997937307, + 93.95080001559108, + 367.20469998545013, + 96.18479997152463, + 350.1633999985643, + 116.73089998657815, + 109.78969998541288, + 930.5650000169408, + 381.93350000074133, + 97.16520001529716, + 367.9247999971267, + 95.4251000075601, + 105.33160000341013, + 100.81259999424219, + 96.02909997920506, + 94.93570000631735, + 103.25819998979568, + 98.35660000680946, + 111.72889999579638, + 98.21219998411834, + 95.73900001123548, + 622.9656999930739, + 97.43980001076125, + 95.71090000099503, + 93.84340001270175, + 96.11620000214316, + 106.09880002448335, + 97.44189999764785, + 98.41530001722276, + 103.4745000069961, + 103.6374999966938, + 99.19520001858473, + 93.13689998816699, + 95.39299999596551, + 111.60750000271946, + 100.89569998672232, + 97.06979998736642, + 93.72970002004877, + 97.56610001204535, + 104.19059998821467, + 99.4840000057593, + 101.42099999939092, + 99.40879998612218, + 99.85640001832508, + 99.05059999437071, + 102.78240000479855, + 97.81589999329299, + 99.1910999873653, + 100.33120002481155, + 391.4777000027243, + 115.39719998836517, + 362.590500008082, + 106.45350001868792, + 96.93940001307055, + 96.88209998421371, + 374.0640999749303, + 366.7383000138216, + 374.63239999487996, + 378.23740000021644, + 383.80740000866354, + 108.55189998983406, + 98.33210002398118, + 337.9633000004105, + 97.38980000838637, + 105.17260001506656, + 376.01100001484156, + 391.4461999956984, + 372.89440000313334, + 98.45520000089891, + 400.1026999903843, + 96.53509999043308, + 360.0262000109069, + 624.8748000070918, + 408.95429998636246, + 100.4432000045199, + 98.27799999038689, + 361.41710000811145, + 97.50859998166561, + 99.09930001595058, + 655.8224000036716, + 103.84880000492558, + 97.72980000707321, + 106.61070002242923, + 650.6231000239495, + 97.4856999819167, + 376.5012999938335, + 100.28499999316409, + 368.79889998817816, + 94.77250001509674, + 111.4938999817241, + 394.0631999867037, + 106.26790000242181, + 95.41799998260103, + 101.99230001308024, + 99.82949998811819 + ], + "asset_move": [ + 89.2036999866832, + 92.32240001438186, + 93.62450000480749, + 88.4422000090126, + 87.29149997816421, + 89.68360000289977, + 299.61440002080053, + 295.66060000797734, + 324.9044000112917, + 600.4698000033386, + 366.45560001488775, + 90.68900000420399, + 1113.7559000053443, + 94.09870000672527, + 394.78080000844784, + 91.73109999392182, + 88.26429999317043, + 590.6715999881271, + 89.35629998450167, + 88.49219998228364, + 89.86549999099225, + 379.3571999995038, + 372.65460001071915, + 108.0997999815736, + 372.21069997758605, + 346.47839999524876, + 114.31319999974221, + 331.4417999936268, + 90.42729999055155, + 344.9278000043705, + 338.3036000013817, + 313.621500012232, + 315.7477999920957, + 371.66969999088906, + 356.38189999735914, + 380.06930000847206, + 304.1769999836106, + 343.13490000204183, + 86.25789999496192, + 85.703899996588, + 111.6735000105109, + 90.12460001395084, + 310.5824000085704, + 89.7918000118807, + 92.58320002118126, + 87.6212999864947, + 90.94950000871904, + 335.4622999904677, + 380.4451999894809, + 343.8638999941759, + 87.80829998431727, + 86.21000000857748, + 372.77159999939613, + 96.60039999289438, + 332.1614000014961, + 91.2959000270348, + 556.3496999966446, + 89.7668999969028, + 88.3021000190638, + 89.0427999838721, + 591.918899997836, + 866.6172999946866, + 87.67599999555387, + 87.30250000371598, + 327.49160000821576, + 90.44170001288876, + 334.2337000067346, + 370.21090000052936, + 90.72589999414049, + 369.13360000471584, + 89.31229999870993, + 593.5245000000577, + 353.03379999822937, + 88.87080001295544, + 347.24760000244714, + 357.842699973844, + 89.80019998853095, + 90.28069998021238, + 907.0800999761559, + 91.36120000039227, + 342.75650000199676, + 85.9780999890063, + 362.6384999952279, + 351.9981999997981, + 90.1515000150539, + 425.2429000043776, + 89.04409999377094, + 87.07470001536421, + 97.88119999575429, + 87.48930000001565, + 93.77189999213442, + 289.69429997960106, + 311.2287000112701, + 87.82469999277964, + 374.2281000013463, + 639.8443999933079, + 402.8686000092421, + 89.51339998748153, + 398.51900000940077, + 320.76930001494475 + ], + "asset_delete": [ + 84.24679999006912, + 384.07749999896623, + 340.0588000076823, + 371.94010001257993, + 331.48299998720177, + 82.96299999346957, + 328.0289999966044, + 1146.7624999932013, + 83.42660000198521, + 1138.8433999964036, + 351.9310000119731, + 85.11029998771846, + 575.2232999948319, + 352.2131000063382, + 83.97039998089895, + 84.50990001438186, + 84.33040001546033, + 575.3312000015285, + 282.4409999884665, + 83.64739999524318, + 327.43160001700744, + 81.82220000890084, + 86.01369999814779, + 445.6525999994483, + 81.89550001407042, + 85.52910000435077, + 85.10180001030676, + 84.02379998005927, + 82.67219999106601, + 94.2485999839846, + 81.42450000741519, + 313.0382999952417, + 82.20409997738898, + 84.43879999686033, + 82.04920002026483, + 81.11050000297837, + 341.01689999806695, + 594.0162999904715, + 295.21899999235757, + 82.13580001029186, + 333.28849999816157, + 83.99330000975169, + 85.46350002870895, + 82.53020001575351, + 95.83629999542609, + 86.4401999861002, + 336.69969998300076, + 86.68790000956506, + 82.4688000138849, + 359.9467000167351, + 83.79939998849295, + 82.83109997864813, + 84.81239998945966, + 377.2785000037402, + 591.9770000036806, + 84.04740001424216, + 1140.207400021609, + 326.8015999929048, + 319.8395000072196, + 88.53099998668768, + 891.7608000047039, + 290.4735000047367, + 82.8689000045415, + 85.88400000007823, + 333.40389997465536, + 91.95719999843277, + 86.35489997686818, + 346.79029998369515, + 79.67949999147095, + 88.67430000100285, + 82.94480000040494, + 580.5130999942776, + 343.86789999553, + 373.28230001730844, + 350.78719997545704, + 81.57749997917563, + 347.3674999841023, + 82.38799998071045, + 923.2098999782465, + 376.1653999972623, + 362.7451999927871, + 97.82589998212643, + 351.94930000579916, + 89.08619999419898, + 87.62890001526102, + 82.0743000076618, + 289.7133999795187, + 84.65440000873059, + 86.09509997768328, + 299.42910000681877, + 84.59519999451004, + 82.07669999683276, + 549.2752999998629, + 325.88160000159405, + 411.2279999826569, + 625.8572000078857, + 83.46650001476519, + 85.1771000016015, + 384.7492999921087, + 86.5825000219047 + ], + "import_settings": [ + 306.47930002305657, + 327.69450001069345, + 36.16629997850396, + 35.76559998327866, + 39.632200001506135, + 255.28149999445304, + 274.23489998909645, + 54.226200008997694, + 35.6900000188034, + 270.06840001558885, + 601.1574000003748, + 275.1015000103507, + 44.921600027009845, + 38.47930001211353, + 38.541799993254244, + 310.89210000936873, + 276.3845999725163, + 1073.0720999999903, + 37.48749999795109, + 259.3973999901209, + 40.17190000740811, + 293.96490001818165, + 36.865900008706376, + 41.59740000613965, + 39.550799992866814, + 305.57579998276196, + 36.148899991530925, + 318.3605000085663, + 310.09939999785274, + 38.52019997430034, + 278.32739998120815, + 835.7946999894921, + 36.39610001118854, + 39.09120001480915, + 295.1484000077471, + 292.7704000030644, + 281.83500000159256, + 555.6537999946158, + 37.451100011821836, + 304.3090999999549, + 36.61829998600297, + 37.26949999690987, + 38.76029999810271, + 37.66040000482462, + 38.46079998766072, + 339.90689998609014, + 35.79749999335036, + 315.7131999905687, + 283.16700001596473, + 284.78739998536184, + 37.205200002063066, + 37.774299999000505, + 35.14799999538809, + 38.67629999876954, + 530.1795999985188, + 314.96590000460856, + 513.0836999742314, + 36.49750002659857, + 39.61489998619072, + 36.8192000023555, + 548.1975000002421, + 35.80470001907088, + 325.1450000097975, + 248.28129998059012, + 578.6435999907553, + 286.57890000613406, + 261.0018000123091, + 610.2238000021316, + 37.27319999597967, + 274.17450002394617, + 324.51450001099147, + 37.14790000231005, + 295.2753000135999, + 43.964299984509125, + 556.3800999952946, + 36.83289999025874, + 314.38149997848086, + 37.78670000610873, + 37.208399997325614, + 35.972800018498674, + 575.0077000120655, + 38.208499987376854, + 561.8407000147272, + 335.0792000128422, + 37.49080002307892, + 277.89060000213794, + 36.985899991123006, + 352.7083999942988, + 38.48650000873022, + 37.16450001229532, + 38.214500003959984, + 38.979000004474074, + 270.70210000965744, + 39.580099983140826, + 42.404200008604676, + 288.27299998374656, + 325.42670000111684, + 344.0357999934349, + 590.2645000023767, + 37.99429998616688 + ], + "material_modify": [ + 62.346499995328486, + 61.68389998492785, + 63.790999993216246, + 62.85989997559227, + 62.44660000083968, + 63.005999982124195, + 314.5780000195373, + 66.49369999649934, + 62.74419999681413, + 58.79420001292601, + 336.6542000148911, + 61.96529997396283, + 85.59699999750592, + 63.05749999592081, + 61.71459998586215, + 72.39590000244789, + 60.92910000006668, + 63.87780001387, + 75.08949999464676, + 65.6244000128936, + 61.23039999511093, + 62.92659998871386, + 62.27460000081919, + 69.08089999342337, + 333.39780001551844, + 60.57440000586212, + 315.9532999852672, + 76.64529999601655, + 61.014800012344494, + 61.3084000069648, + 340.53069999208674, + 64.66649999492802, + 315.8490000059828, + 61.428099987097085, + 59.758300019893795, + 73.50650001899339, + 331.0211999923922, + 61.06470001395792, + 61.16769998334348, + 60.48919999739155, + 60.981999995419756, + 78.02929999888875, + 59.5988999994006, + 322.35729999956675, + 384.3487999984063, + 60.44949998613447, + 58.569899993017316, + 59.64389999280684, + 338.7702999752946, + 608.6052000173368, + 327.3478999908548, + 61.20920000830665, + 62.103500007651746, + 59.45229998906143, + 620.1980000187177, + 59.77680001524277, + 63.0951999919489, + 62.98350001452491, + 57.31110001215711, + 64.9078999995254, + 61.31869999808259, + 60.251500020967796, + 65.78909998643212, + 59.06109997886233, + 942.1556999732275, + 60.96370000159368, + 62.83739997888915, + 639.9489999748766, + 345.1463999808766, + 347.77130000293255, + 72.19579999218695, + 68.6643999943044, + 1164.0103999816347, + 62.3327000066638, + 603.9804999891203, + 61.58919999143109, + 62.337600014870986, + 66.42759998794645, + 65.25689997943118, + 69.9787000194192, + 590.6538999988697, + 63.646099995821714, + 62.27580000995658, + 58.92960002529435, + 61.81499999365769, + 67.86970002576709, + 342.0560999948066, + 61.6654000186827, + 351.73339999164455, + 61.53679999988526, + 337.3014999961015, + 59.964400017634034, + 647.0305000257213, + 65.66680001560599, + 399.03110000886954, + 613.1648999871686, + 61.137599986977875, + 60.245900007430464, + 1244.1977999988012, + 65.478999982588 + ], + "time_settings": [ + 38.28159999102354, + 324.86570000764914, + 318.82769998628646, + 38.886899972567335, + 36.10529997968115, + 38.765300007071346, + 540.1905999751762, + 39.22589999274351, + 39.81399998883717, + 35.820000019157305, + 931.5254999964964, + 37.35920001054183, + 50.455299991881475, + 293.80590000073425, + 307.8379000071436, + 36.59860001062043, + 36.33520001312718, + 40.29499998432584, + 37.14039997430518, + 37.93630001018755, + 35.928299999795854, + 312.2544000216294, + 39.067500008968636, + 342.8289000003133, + 33.86629998567514, + 39.71610000007786, + 38.42660001828335, + 36.993400019127876, + 37.427700008265674, + 37.094100000103936, + 295.65839999122545, + 39.68330001225695, + 34.20130000449717, + 318.5829999856651, + 41.91560001345351, + 290.53660001954995, + 298.71859998092987, + 39.09809998003766, + 35.35950000514276, + 36.93919998477213, + 47.59089997969568, + 300.94079999253154, + 299.94120000628754, + 36.90050001023337, + 36.79519999423064, + 36.349000001791865, + 314.65089999255724, + 37.35389999928884, + 851.1580000049435, + 37.72759999264963, + 39.107799995690584, + 35.36730000632815, + 280.7413999980781, + 38.05959998862818, + 40.4432000068482, + 35.72300000814721, + 42.22140001365915, + 36.239400011254475, + 281.67699999175966, + 36.67370000039227, + 36.19740001158789, + 35.96429998287931, + 308.7707000086084, + 333.2769999979064, + 581.1278999899514, + 36.997799994423985, + 339.5684999995865, + 600.7520999992266, + 42.966000008163974, + 306.0217000020202, + 36.19440001784824, + 42.111100017791614, + 40.64500000094995, + 37.34089998761192, + 38.65220001898706, + 35.88989999843761, + 858.4068000200205, + 36.42119999858551, + 39.8200000054203, + 346.09359997557476, + 35.078999993856996, + 36.46030000527389, + 41.52659999090247, + 55.252900026971474, + 39.67709999415092, + 315.478999982588, + 333.39370001340285, + 34.70230000675656, + 36.70080000301823, + 37.231800000881776, + 35.42950001428835, + 34.679200005484745, + 529.8215000075288, + 40.749199979472905, + 345.3540000191424, + 1148.6052999971434, + 35.122100001899526, + 36.502999981166795, + 37.732900003902614, + 51.39430001145229 + ], + "read_csharp": [ + 33.510400011437014, + 298.32870000973344, + 32.07789998850785, + 31.48830001009628, + 31.950000004144385, + 36.10719999414869, + 1120.630200020969, + 30.382900004042313, + 307.5654999993276, + 32.295100012561306, + 645.4327999963425, + 31.795999995665625, + 34.809700009645894, + 34.56400000141002, + 36.01659997366369, + 34.03070001513697, + 33.413900004234165, + 33.09740000986494, + 32.47930001816712, + 34.22060000593774, + 33.82770001189783, + 33.053799998015165, + 37.49319998314604, + 35.55739999865182, + 33.4529000101611, + 34.22170001431368, + 33.7534999998752, + 316.62209998467006, + 32.661100005498156, + 31.775099982041866, + 871.957499999553, + 38.9347999880556, + 32.533999998122454, + 30.351299996254966, + 293.07970000081696, + 585.2115000016056, + 299.6356000076048, + 37.13169999537058, + 35.87719998904504, + 32.441800023661926, + 30.5950999900233, + 31.52399999089539, + 33.16150000318885, + 31.99060002225451, + 33.49179998622276, + 31.674700003350154, + 30.779099994106218, + 316.74029998248443, + 306.01909998222254, + 32.2796999826096, + 32.31799998320639, + 32.902600010856986, + 31.13320001284592, + 289.45819998625666, + 36.53169999597594, + 35.90680001070723, + 30.60389999882318, + 31.031099992105737, + 40.873599995393306, + 32.64749998925254, + 37.05889999400824, + 33.32439999212511, + 31.705700006568804, + 304.0739000134636, + 32.852300006197765, + 32.97339999699034, + 328.65049998508766, + 288.8896999938879, + 80.33680001972243, + 309.3640000151936, + 318.98730000830255, + 306.3192999979947, + 66.82590002310462, + 33.20309999980964, + 34.9114999989979, + 32.40009999717586, + 592.4911000183783, + 33.433199976570904, + 35.908799996832386, + 35.4415999900084, + 32.49769998365082, + 33.34649998578243, + 29.569199978141114, + 327.99260001047514, + 30.64839998842217, + 32.96820001560263, + 596.2721999967471, + 35.231700021540746, + 33.24590000556782, + 33.72289999970235, + 31.957699975464493, + 30.42460000142455, + 31.464200001209974, + 305.69710000418127, + 614.8668999958318, + 599.3605999974534, + 32.49260000302456, + 31.09900001436472, + 32.09609998157248, + 34.22050000517629 + ], + "play_until_ready": [ + 776.1259000108112, + 1056.1597000050824, + 798.2197999954224, + 768.9478000102099, + 790.1528000074904, + 778.5156999889296, + 770.869700005278, + 783.2177000236697, + 768.8572999904864, + 765.8959999971557, + 1078.4048000059556, + 1058.1110999919474, + 1060.9829000022728, + 786.5181000088342, + 781.2352000037208, + 778.9756999991369, + 786.3647000049241, + 778.7737000035122, + 1043.9920999924652, + 1050.632600003155, + 1017.8690000029746, + 1035.7866999984253, + 1078.111999988323, + 798.6061999981757, + 763.5284000134561, + 1055.9554000210483, + 799.8087999876589, + 772.5963999982923, + 768.5589999891818, + 768.3637000154704, + 1627.604200009955, + 772.8662000154145, + 1047.2135999880265, + 778.3001000061631, + 1036.0304999921937, + 1650.4163999925368, + 1312.1219000022393, + 771.2619999947492, + 792.229699989548, + 769.1625999868847, + 766.7821999930311, + 780.2572000073269, + 762.1469000005163, + 784.6652000152972, + 781.3241000112612, + 770.2653000014834, + 776.3721999945119, + 798.3030999894254, + 807.1965999843087, + 786.1398999812081, + 770.1664000051096, + 772.0153999980539, + 772.8325000207406, + 771.1963999900036, + 796.5591999818571, + 785.379799985094, + 789.3266000028234, + 775.3191000083461, + 1036.6214999812655, + 1095.3041999891866, + 780.4219000099692, + 765.8930999750737, + 1078.9205000037327, + 1515.7237999956124, + 786.1293000169098, + 796.8871000048239, + 879.7678999835625, + 1646.6183999727946, + 1052.8291999944486, + 1341.2113999947906, + 771.8804999894928, + 772.4179999786429, + 770.994199992856, + 784.6160999906715, + 795.8273000258487, + 768.986799987033, + 775.0047000008635, + 1060.5851000000257, + 790.0372000003699, + 784.3509999802336, + 781.1594000086188, + 1029.6912000048906, + 785.3311999933794, + 1058.9227000018582, + 779.4146999949589, + 778.9217999961693, + 1403.3910999714863, + 788.1508999853395, + 789.3767000059597, + 783.3173999970313, + 782.5945999938995, + 771.8787999765482, + 784.4427000090946, + 772.9196000145748, + 2425.4110000038054, + 820.1107000058983, + 1045.9907999902498, + 772.6112000236753, + 797.1764999965671, + 777.4846999964211 + ], + "stop_until_ready": [ + 666.0737000056542, + 881.3310999830719, + 619.6244999882765, + 576.1473999882583, + 657.8888999938499, + 705.6300000112969, + 570.6181999994442, + 599.3947999959346, + 788.6318999808282, + 657.4725000245962, + 920.0701000227127, + 625.2200999879278, + 771.2505999952555, + 591.7769000225235, + 883.2258000038564, + 570.6454000028316, + 582.3070000042208, + 850.4972000082489, + 724.7526999854017, + 1207.176800002344, + 624.2176000087056, + 1395.457400009036, + 811.9503000052646, + 825.2270999946631, + 1555.0643999886233, + 683.7703000055626, + 649.9949999852106, + 578.0854999902658, + 742.1820999879856, + 728.033499995945, + 982.0122000237461, + 576.5786999836564, + 575.7588999986183, + 660.5035999964457, + 1037.8680999856442, + 870.3122999868356, + 575.653300009435, + 588.8772000034805, + 832.1194000018295, + 790.7101000018883, + 700.3718000196386, + 583.9492999948561, + 868.3906999940518, + 568.3272999885958, + 893.3086000033654, + 803.1402000051457, + 571.4417000126559, + 855.6565000035334, + 620.7436000113375, + 835.9147000010125, + 572.2964000015054, + 776.2062000110745, + 592.1367999981157, + 689.242499996908, + 613.7567999830935, + 572.7493999875151, + 774.9099999782629, + 665.6693000113592, + 848.47479997552, + 589.8377999837976, + 819.2133000120521, + 591.8059999821708, + 1034.0367000026163, + 590.8826000231784, + 874.627099983627, + 731.281599990325, + 1488.533700001426, + 581.6255999961868, + 924.2403999960516, + 1160.0200000102632, + 1206.5791000204626, + 883.4061000088695, + 797.0650999923237, + 837.5149999919813, + 660.7805999810807, + 596.1411999887787, + 634.5429999928456, + 576.5906999877188, + 584.2359000234865, + 602.2082999988925, + 570.7630999968387, + 574.3063999980222, + 730.255100002978, + 758.7235999817494, + 586.9180999870878, + 1164.4037000078242, + 1347.627899987856, + 597.5784999900497, + 672.1106999902986, + 619.2284999997355, + 583.4699000115506, + 725.5108999961521, + 848.5106999869458, + 706.8412000080571, + 1878.9602000033483, + 629.4358000159264, + 647.0384999993257, + 660.3433999989647, + 582.4753000051714, + 598.5055000055581 + ] + }, + "official": { + "editor_state": [ + 849.948699993547, + 794.7263999958523, + 721.1353000020608, + 807.639399979962, + 764.2949000000954, + 789.20639998978, + 731.6922000027262, + 771.4471000072081, + 554.8866000026464, + 556.8094000045676, + 889.1331999911927, + 653.353400004562, + 590.825399995083, + 947.0201999938581, + 595.1984999992419, + 618.9355999813415, + 542.6065000065137, + 541.7978000186849, + 1004.8364000103902, + 1118.5356999922078, + 1172.31989998254, + 529.2124999978114, + 1570.941000012681, + 550.1691999961622, + 545.8092000044417, + 729.3399999907706, + 580.3908999951091, + 889.9442999972962, + 987.8942999930587, + 758.7005999812391, + 816.1590000090655, + 834.7418000048492, + 538.1852999853436, + 1171.826100006001, + 964.9606999882963, + 794.4766000146046, + 732.3604999983218, + 717.3097000049893, + 590.6844999990426, + 752.1385000145528, + 740.1917999959551, + 718.4760999807622, + 790.3661000018474, + 638.6378000024706, + 672.7382999961264, + 765.7809999946039, + 712.2359999921173, + 560.7547999825329, + 898.4380000038072, + 542.8519000124652, + 879.3056999857072, + 840.0116999982856, + 750.5997999978717, + 1097.3953999928199, + 1443.035600008443, + 546.2743999960367, + 772.6282000076026, + 739.143899991177, + 767.1429000038188, + 851.6374000173528, + 752.985200000694, + 544.5360000012442, + 549.1862999915611, + 542.7027000114322, + 818.4225999866612, + 748.5956000164151, + 620.473100017989, + 640.2986000175588, + 620.7020999863744, + 564.3539000011515, + 647.819999983767, + 839.2021000036038, + 532.4072000221349, + 543.834699987201, + 744.1572000097949, + 775.3219000005629, + 917.1645000169519, + 539.1839999938384, + 545.0101000024006, + 684.3510000035167, + 777.5822000112385, + 573.1465999851935, + 549.108699982753, + 552.8073000023142, + 875.4773999971803, + 782.3419000196736, + 772.0921000000089, + 555.7076999975834, + 611.2726000137627, + 766.9380999868736, + 538.1285000185017, + 1048.1641000078525, + 651.8521000107285, + 1275.5186000140384, + 671.4848999981768, + 561.0493999847677, + 689.7042999917176, + 735.6801999849267, + 967.5021000148263, + 809.2223999847192 + ], + "hierarchy": [ + 1050.577300018631, + 774.3120000232011, + 670.5628999916371, + 629.0565999806859, + 1446.6705000086222, + 691.2689000018872, + 1210.8156000031158, + 541.39669999131, + 825.9652999986429, + 540.0687000073958, + 689.8191999935079, + 1151.760100008687, + 777.8413000050932, + 903.5683999827597, + 558.7993999943137, + 570.6432999868412, + 537.562200013781, + 781.6473999992013, + 1719.7590999712702, + 544.4539000163786, + 550.6487999809906, + 649.8270999873057, + 830.8065999881364, + 820.9757000149693, + 552.9750999994576, + 657.8470999957062, + 532.6216000248678, + 878.9043000142556, + 959.876200009603, + 879.8218999872915, + 880.7548000186216, + 796.3569999847095, + 670.6521000014618, + 558.7997999973595, + 1401.618600008078, + 962.0593000145163, + 849.1322000045329, + 691.4848999876995, + 563.7561000185087, + 694.4235999835655, + 577.9051000135951, + 973.443099996075, + 932.0885999768507, + 880.1071000052616, + 530.9845999872778, + 1178.2122000004165, + 719.8497999925166, + 572.1488000126556, + 655.3904000029434, + 538.1317000137642, + 816.9160000106785, + 665.5550999857951, + 860.3135999874212, + 1457.1122000052128, + 538.1278000131715, + 803.054299991345, + 598.6880999989808, + 650.9327000239864, + 636.28430000972, + 747.3622999968939, + 589.6817999891937, + 803.2654999988154, + 820.4296999901999, + 533.4577000176068, + 741.5757000271697, + 1774.2298000084702, + 758.1227000046056, + 550.4140999983065, + 770.7208999781869, + 658.5433000000194, + 920.2310999971814, + 1200.4941999912262, + 547.4112000083551, + 729.7178999870084, + 922.794599988265, + 801.2321999995038, + 1182.2907999739982, + 785.4397000046447, + 535.7652999809943, + 1231.3772999914363, + 1889.918500004569, + 541.2645999749657, + 542.2621999750845, + 610.2616999996826, + 603.6946999956854, + 737.3192999802995, + 767.3020999936853, + 741.7973999981768, + 554.2436999967322, + 918.7160999863409, + 804.8973999975715, + 754.9286000139546, + 594.1497999883723, + 1212.5889000017196, + 914.1316000022925, + 547.2647999995388, + 770.7564000156708, + 1508.7793999991845, + 595.807200006675, + 587.7431999833789 + ], + "find_gameobject": [ + 548.2817000010982, + 652.7319999877363, + 1173.586399992928, + 577.926900004968, + 543.710199999623, + 867.138800007524, + 533.6146000190638, + 655.3099000011571, + 681.6019999969285, + 653.6705999751575, + 813.2053000153974, + 592.1954999794252, + 688.4460000146646, + 792.5889999896754, + 550.0054000003729, + 574.1027999902144, + 711.1975000007078, + 679.3973000021651, + 812.546500004828, + 546.1354999861214, + 807.8851999889594, + 646.6883000102825, + 543.6592999903951, + 620.8278999838512, + 549.9703999958001, + 986.5406999888364, + 724.8016000085045, + 810.8417999756057, + 903.3949000004213, + 717.8416999813635, + 553.1073000165634, + 684.6015999908559, + 860.7097000058275, + 548.018499976024, + 535.9684999857564, + 722.839699999895, + 852.1881999913603, + 535.249600012321, + 594.6003000135534, + 888.4410999889951, + 806.7270000174176, + 1131.0366000107024, + 672.62159998063, + 765.3817000100389, + 827.8303999977652, + 527.7859000198077, + 896.1700999934692, + 735.4297999991104, + 583.0340000102296, + 750.4428999964148, + 743.2011000055354, + 845.2860999968834, + 600.294700008817, + 849.8816000064835, + 544.1937000141479, + 739.3261999823153, + 1693.841300002532, + 883.2825999998022, + 726.3759000052232, + 664.0230999910273, + 715.4805999889504, + 1207.1046000055503, + 668.5710999881849, + 715.6294000160415, + 1213.3863000199199, + 1154.7445000032894, + 909.0498999867123, + 558.6951000150293, + 580.3919000027236, + 712.4029999831691, + 855.5250999925192, + 744.7759000060614, + 778.1285000091884, + 903.8270000019111, + 592.5379999971483, + 1233.0708999943454, + 561.9752999919001, + 740.315200004261, + 746.3914999971166, + 623.6395000014454, + 688.355699996464, + 653.273400006583, + 2252.906099980464, + 546.7514999909326, + 670.9589999809396, + 543.9421999908518, + 929.9401000025682, + 889.6293000143487, + 545.4156000050716, + 551.0210000211373, + 668.9587000000756, + 1371.7578999930993, + 1016.1123999860138, + 553.9600999909453, + 1209.852400003001, + 817.2953999892343, + 600.5147999967448, + 537.8698999993503, + 533.039900008589, + 532.4661999766249 + ], + "transform": [ + 730.5274000100326, + 898.2036999950651, + 896.978599979775, + 1387.4762000050396, + 731.6066999919713, + 981.4435000007506, + 1007.9749000142328, + 1652.0594999892637, + 758.5052000067662, + 848.9786999998614, + 929.9848999944516, + 965.9302999789361, + 732.46040000231, + 959.7341000044253, + 867.9211999988183, + 714.5453999983147, + 818.6389000038616, + 1079.0264000243042, + 759.130999998888, + 720.1967999862973, + 941.3644000014756, + 728.2459999842104, + 795.0445000024047, + 1014.4340999831911, + 915.9777000022586, + 981.9052000239026, + 897.2906999988481, + 849.2612999980338, + 750.52540001343, + 912.6316999900155, + 727.8533999924548, + 1079.8998999816831, + 1001.1753000144381, + 975.3482000087388, + 739.3031999818049, + 732.7476000064053, + 948.9162000245415, + 729.1472000069916, + 844.231299997773, + 1030.8571999776177, + 1100.5408000200987, + 728.2859999977518, + 850.1393999904394, + 800.5615000147372, + 837.6054000109434, + 977.9641999921296, + 1065.8370000019204, + 986.8398999969941, + 731.7522000230383, + 1059.24679999589, + 1100.9648999897763, + 1071.0248000104912, + 758.3728000172414, + 729.2228000005707, + 993.8953000237234, + 1348.2189999776892, + 726.6720999905374, + 918.4232999978121, + 1654.1146999807097, + 731.3914000114892, + 809.020499989856, + 1048.3564999885857, + 807.6356999808922, + 740.4841000097804, + 785.2803000132553, + 762.9478000162635, + 776.9250999845099, + 1121.3954999984708, + 987.3474999913014, + 725.9557999786921, + 1595.385599997826, + 765.7408000086434, + 898.6134000006132, + 1631.0022000106983, + 730.2000999916345, + 2171.7729999800213, + 737.7636000164784, + 1078.8674000068568, + 1669.2462000064552, + 844.2192999937106, + 842.8114999842364, + 1084.5861000125296, + 1098.529899987625, + 743.0281999986619, + 736.5016000112519, + 1004.0891999960877, + 738.015600014478, + 1074.5838999864645, + 728.2688999839593, + 851.6024999844376, + 1454.359299998032, + 740.2005999756511, + 786.8492999987211, + 745.9671999968123, + 824.3786000239197, + 921.6832000238355, + 980.9920999978203, + 727.0487000059802, + 912.8143999841996, + 734.4890999956988 + ], + "position": [ + 553.8321000058204, + 541.8114000058267, + 543.8771999906749, + 569.5726999838371, + 553.722500015283, + 761.3651000137907, + 732.2218999906909, + 543.8537000154611, + 712.156599998707, + 972.532499989029, + 983.4454999945592, + 999.1095000004862, + 683.1297999888193, + 1008.8996000122279, + 728.7803000072017, + 545.9808000014164, + 542.9753999924287, + 543.0889000126626, + 677.0583000034094, + 547.7843999979086, + 1097.08999999566, + 557.7789999952074, + 584.225400001742, + 539.2658000055235, + 845.3871999809053, + 532.5964000076056, + 698.355000000447, + 550.5230000126176, + 566.0937000066042, + 820.382600009907, + 542.3465000058059, + 905.5274999991525, + 555.5929999973159, + 547.3880999779794, + 551.7446000012569, + 790.1676000037696, + 551.1086999904364, + 537.6518000266515, + 994.0100999956485, + 838.549799984321, + 763.6333999980707, + 536.8517999886535, + 804.3903000070713, + 540.0684000051115, + 1006.0193999961484, + 1664.5390000194311, + 546.1155000084545, + 758.4337999869604, + 1069.8750000155997, + 1261.4952999865636, + 969.7345999884419, + 580.6069999816827, + 778.0590000038501, + 574.9929999874439, + 692.4685999983922, + 533.5101000091527, + 668.6524999968242, + 541.1051999835763, + 557.8016999934334, + 566.2636000197381, + 638.4928000043146, + 529.3765000242274, + 557.1368999953847, + 583.2732999988366, + 548.3800999936648, + 754.1758000152186, + 558.3524999965448, + 542.8019999817479, + 1635.4250999866053, + 530.6052999803796, + 762.9773000080604, + 756.3701999897603, + 531.3518999901135, + 716.3427000050433, + 548.289800004568, + 548.860999988392, + 592.8109000087716, + 552.039700007299, + 594.3461999995634, + 544.274999992922, + 638.1250999984331, + 563.3384000102524, + 554.2477999988478, + 1671.0510999837425, + 571.2178999965545, + 538.0099999892991, + 536.2642999971285, + 552.4587999971118, + 652.8640999749769, + 708.8651999947615, + 558.3214000216685, + 577.2689000004902, + 560.5427999980748, + 699.9878000060562, + 545.9588000085205, + 1012.5043999869376, + 550.3656000073534, + 794.5586999994703, + 836.4551000122447, + 554.2740999953821 + ], + "create_cube": [ + 681.0668999969494, + 601.0893000056967, + 601.7714000190608, + 753.4476000000723, + 794.1862999869045, + 936.9287000154145, + 1018.9156999986153, + 557.8867999720387, + 734.3666999950074, + 630.888200015761, + 543.4626000060234, + 703.7849000189453, + 551.5889000089373, + 773.358400008874, + 546.1606000026222, + 651.5273999830242, + 544.3187000055332, + 681.1073000135366, + 996.3935999840032, + 835.1295000175014, + 576.4675000100397, + 725.1987000054214, + 960.5340999842156, + 617.5921999965794, + 591.351199982455, + 823.9518000045791, + 759.4766999827698, + 1005.8344999852125, + 703.7893999950029, + 783.8973000179976, + 554.4100999832153, + 589.0213999955449, + 541.3594999990892, + 630.9869999822695, + 546.5272000001278, + 677.7236000052653, + 725.3183999855537, + 1186.841499991715, + 638.904299994465, + 796.7161999840755, + 543.5931000101846, + 551.9047999987379, + 837.8241999889724, + 749.1981000057422, + 547.8530999971554, + 746.8496000219602, + 551.3801999913994, + 551.6574000066612, + 1187.272800016217, + 747.936200001277, + 631.0000999947079, + 601.3492999773007, + 550.1149999909103, + 628.1058999884408, + 792.1689999930095, + 632.8863000089768, + 538.0428000062238, + 723.6695000028703, + 752.8470999968704, + 549.2283000203315, + 561.109399975976, + 562.9052000003867, + 601.8700000131503, + 1207.3787999979686, + 826.4029000129085, + 537.5789999961853, + 608.6316999862902, + 557.4082999955863, + 1954.5146999880672, + 542.5495999807026, + 760.0823999964632, + 666.2243999890052, + 554.6189000015147, + 549.5111999916844, + 661.2826000200585, + 544.6150999923702, + 558.2075999991503, + 556.207000016002, + 639.285999990534, + 548.5751999949571, + 721.9686000025831, + 535.3238999960013, + 545.4092000145465, + 1425.8201999764424, + 644.2083999863826, + 740.8135999867227, + 541.1284000147134, + 536.419299984118, + 694.4511999899987, + 792.1312999969814, + 588.2136000145692, + 542.7102000103332, + 545.2308999956585, + 1291.1631999886595, + 553.3246000122745, + 849.9721999978647, + 540.8865000063088, + 817.7759999816772, + 738.5932999895886, + 585.083099984331 + ], + "add_component": [ + 1260.3723999927752, + 723.0771000031382, + 748.2688000018243, + 751.3178000226617, + 798.5438999894541, + 916.9285999960266, + 1365.3038000047673, + 732.756099983817, + 1101.601499976823, + 1004.030900017824, + 738.467999995919, + 732.6598000072408, + 839.3926999997348, + 773.2746000110637, + 746.1437000019941, + 822.1446000097785, + 1053.6983000056352, + 805.1277000049595, + 966.416199982632, + 839.0493000042625, + 830.4176999954507, + 1762.6479000027757, + 1128.867999999784, + 724.6608000132255, + 1019.4475000025705, + 840.5877999903169, + 1309.9003999959677, + 1104.0639999846462, + 1055.522699985886, + 1095.8774000173435, + 885.0864999985788, + 950.823399994988, + 828.820499998983, + 751.7124000005424, + 1019.0232000022661, + 1659.532699995907, + 829.0937999845482, + 737.3309999820776, + 729.6123999985866, + 2513.514499994926, + 746.1209000030067, + 745.9913000056986, + 841.1269999924116, + 1398.6396999971475, + 976.6423999972176, + 777.4602999852505, + 722.1500000159722, + 1017.8637999924831, + 843.1556999858003, + 846.5224000101443, + 787.8870000131428, + 718.7844999716617, + 927.3713000002317, + 969.0272999869194, + 1353.0125000106636, + 714.7151000099257, + 959.1687000065576, + 1101.1651000007987, + 908.3833000040613, + 728.9501000195742, + 726.5274999954272, + 1011.8940999964252, + 732.5496000121348, + 736.5185999951791, + 720.2114000101574, + 1107.7187999908347, + 1017.7138000144623, + 968.8145999971312, + 739.1600999981165, + 978.4678999858443, + 734.1593999881297, + 1071.5758000151254, + 724.2628999811132, + 725.2435999980662, + 844.3273000011686, + 772.3910000058822, + 728.4650999936275, + 726.993999996921, + 944.1957999952137, + 964.7248999972362, + 769.7851000120863, + 737.0839999930467, + 908.5825000074692, + 797.2386999754235, + 885.216800001217, + 814.8270999954548, + 736.4564999879804, + 742.4863000051118, + 1101.9363999948837, + 976.9635999982711, + 957.102299988037, + 739.4071000162512, + 743.0098000040743, + 754.6621000219602, + 989.0137999900617, + 760.0863999978174, + 935.2779999899212, + 795.1821000024211, + 1131.3010999874678, + 734.8965000128374 + ], + "remove_component": [ + 745.0596999842674, + 846.1352000012994, + 993.4893999889027, + 854.5456000138074, + 2001.5022000006866, + 742.5385000242386, + 730.2834000147413, + 732.9284999868833, + 751.8114999984391, + 1266.3334000098985, + 874.1077000158839, + 770.3729000058956, + 914.5353999920189, + 853.6040000035428, + 865.4749999986961, + 904.6219000010751, + 786.8934000143781, + 996.6948000073899, + 725.4525999887846, + 739.8374000040349, + 844.9051000061445, + 738.3574999985285, + 746.7538999917451, + 1826.6246999846771, + 800.7314999995288, + 720.1635999954306, + 829.1904000216164, + 722.2236999950837, + 757.5490000017453, + 1971.3040000060573, + 2349.9595999892335, + 1008.1209999916609, + 1186.5370000014082, + 727.1265999879688, + 1475.9115999913774, + 741.0726000089198, + 769.5009000017308, + 741.8233000207692, + 726.2134000193328, + 733.0623999878298, + 871.2999999988824, + 916.0768000001553, + 734.9565000040457, + 1016.738800011808, + 921.9389000209048, + 916.1123000085354, + 751.2398000108078, + 784.2378999921493, + 968.5460999899078, + 766.5543000039179, + 955.7772999978624, + 897.2194000089075, + 730.177299992647, + 923.4746000147425, + 740.207199996803, + 787.3017999809235, + 1807.2819999943022, + 899.7489000030328, + 955.6876999849919, + 929.7008000139613, + 742.0220000203699, + 787.0080000138842, + 947.1464999951422, + 741.7279999936, + 785.9438000014052, + 1039.362000010442, + 954.504099994665, + 911.9261000014376, + 1006.5427999943495, + 1804.6735000098124, + 1420.9979000152089, + 1128.0968000064604, + 716.603299981216, + 729.4815999921411, + 895.15900000697, + 740.9271999786142, + 887.9797999979928, + 1035.4790999845136, + 1199.727700004587, + 1226.5025999804493, + 887.0127000263892, + 837.174899992533, + 741.8945000099484, + 1009.0633000072557, + 1167.4569999740925, + 1011.5470000018831, + 1311.1556000076234, + 823.1402999954298, + 735.9135999868158, + 1163.5764999955427, + 1811.9032999966294, + 751.7873000178952, + 933.3341999736149, + 759.7917000239249, + 1904.0703999926336, + 868.5568000073545, + 721.6072999872267, + 730.7297000079416, + 982.7877999923658, + 718.1673999875784 + ], + "delete_gameobject": [ + 701.1334999988321, + 896.1819999967702, + 703.6509999888949, + 550.7984999858309, + 551.6726000059862, + 547.4021999980323, + 738.9589000085834, + 785.299799987115, + 538.1901999935508, + 749.8045999964233, + 826.0056000144687, + 809.3454000190832, + 1846.3176999939606, + 633.2677000027616, + 987.7335999917705, + 599.5606000069529, + 965.616899979068, + 553.9130000106525, + 545.6262999796309, + 539.6944000094663, + 800.6323000008706, + 543.2657000201289, + 555.2050999831408, + 739.4666000036523, + 1643.1845000188332, + 552.6142999879085, + 796.9586999970488, + 555.8997000043746, + 767.8268000017852, + 599.1685999906622, + 691.1047000030521, + 714.565100002801, + 687.691500002984, + 551.8848999927286, + 548.3744999801274, + 541.8835000018589, + 532.0095999923069, + 662.1184000105131, + 1006.1718000215478, + 536.428400024306, + 993.2758999930229, + 722.1124000207055, + 776.6613999847323, + 542.3879000009038, + 584.5025000162423, + 665.4912999947555, + 1585.0789000105578, + 538.5110000206623, + 612.6202000014018, + 544.5389999949839, + 1297.3504000110552, + 1287.6911999774165, + 1090.9337000048254, + 812.5227999989875, + 567.4042000027839, + 1063.5223000135738, + 572.5949000043329, + 1252.0396999898367, + 653.7140999862459, + 795.8722999901511, + 1648.9090000104625, + 606.6928000072949, + 538.6989999969956, + 550.856499990914, + 547.5590999994893, + 741.0199999867473, + 636.6940000152681, + 544.240199989872, + 545.9802000259515, + 551.5067999949679, + 1286.2583999813069, + 553.1198999960907, + 584.744599997066, + 762.0346999901813, + 1105.0401999964379, + 1966.602900007274, + 535.1309000106994, + 723.032299982151, + 584.0361999871675, + 554.1339000046719, + 593.1717999919783, + 543.8560000038706, + 543.5834999952931, + 877.329600014491, + 535.8097999996971, + 536.6623000008985, + 805.0659000000451, + 583.5636999981944, + 543.9990000159014, + 681.3740000070538, + 577.2569999971893, + 731.170100014424, + 1333.8635000109207, + 548.0855999921914, + 543.2706999999937, + 818.960300006438, + 618.5807999863755, + 544.6296000154689, + 843.2306000031531, + 551.2583999952767 + ], + "scene_info": [ + 682.2050999908242, + 593.4522999741603, + 552.7206999831833, + 874.6867000008933, + 560.6209999823477, + 536.9653000088874, + 797.768599994015, + 535.4504999995697, + 593.9575000084005, + 552.9118999838829, + 1438.6273999989498, + 1153.3289999933913, + 600.5105999938678, + 923.7145000079181, + 908.1817999831401, + 614.9075999855995, + 835.9499000071082, + 1155.4868000093848, + 810.1071999990381, + 789.3815999850631, + 534.5155999821145, + 552.2254999959841, + 852.2035999922082, + 626.4239000156522, + 799.1916000028141, + 535.7015999907162, + 971.6081999940798, + 832.4933999974746, + 774.3590000027325, + 576.3981000054628, + 568.4669000038411, + 763.8411999796517, + 777.543300006073, + 927.8554000193253, + 560.5393000005279, + 539.3279999843799, + 553.402699995786, + 711.7138999747112, + 847.5722000002861, + 555.7532999955583, + 790.2107000118122, + 1162.3914000228979, + 558.2294999912847, + 749.0194000129122, + 536.0877999919467, + 1164.282199984882, + 543.6803000047803, + 1224.2674000153784, + 899.6946999977808, + 601.6958999971393, + 538.2358000206295, + 551.7570000083651, + 560.1688000024296, + 1297.7463999995962, + 667.3966000089422, + 540.9828000119887, + 544.376400008332, + 598.1574000034016, + 696.8796000001021, + 546.2729999853764, + 555.53549999604, + 880.3982000099495, + 550.0757999834605, + 678.4531000012066, + 664.7815999749582, + 602.5956000084989, + 546.0689999745227, + 552.5507999991532, + 591.3678999932017, + 671.9578999909572, + 829.8769000102766, + 556.8050000001676, + 701.343499997165, + 593.9574000076391, + 823.8784999994095, + 543.1193999829702, + 550.7479000079911, + 1165.0831000006292, + 717.8070000081789, + 542.6711000036448, + 603.8084999890998, + 958.7112999870442, + 753.3169999951497, + 1186.4823000214528, + 547.2048999799881, + 904.1555000003427, + 541.374899999937, + 597.2198999952525, + 692.3614999977872, + 731.3387999893166, + 662.524499988649, + 809.924899978796, + 544.5166999998037, + 558.6872999847401, + 593.0641000159085, + 936.778899980709, + 1008.0438999866601, + 528.3791999972891, + 835.1979000144638, + 535.0469000113662 + ], + "scene_save": [ + 646.4404999860562, + 635.8284000016283, + 661.0638999845833, + 640.8171000075527, + 921.677100006491, + 642.4103000026662, + 731.0270000016317, + 650.7503000029828, + 642.7547999774106, + 645.9209999884479, + 841.5556999971159, + 896.9091000035405, + 628.3373000042047, + 840.7716999936383, + 653.0660999997053, + 684.9612999940291, + 817.6181000017095, + 851.0158999997657, + 1040.5214999918826, + 647.8541000105906, + 629.1873999871314, + 644.1073999740183, + 1118.060200009495, + 917.9541999765206, + 722.9700000025332, + 850.105400022585, + 659.924499981571, + 1058.8725999987219, + 859.8313000111375, + 681.1075999867171, + 668.2599000050686, + 1586.4801999996416, + 707.9919000098016, + 1572.923300002003, + 639.3386999843642, + 834.3188999861013, + 825.5616000096779, + 747.3142000089865, + 634.6104999829549, + 877.3286000068765, + 872.0418000011705, + 643.9164000039455, + 1375.6916999991518, + 787.4640999943949, + 763.4885000006761, + 819.5690999855287, + 912.7950000111014, + 854.4194999849424, + 950.3007000021171, + 658.3208999945782, + 719.7291000047699, + 660.5276999762282, + 648.7462999939453, + 665.7236999890301, + 640.1647999882698, + 638.1801000097767, + 640.8531999913976, + 651.1267999885604, + 653.6290999792982, + 746.0208999982569, + 785.5189999972936, + 632.8164000005927, + 649.4105999881867, + 867.7698000101373, + 646.58369999961, + 942.6935000228696, + 944.125099980738, + 650.0137000111863, + 844.7021000029054, + 1220.7405999943148, + 660.323200019775, + 879.5558999991044, + 734.5948999864049, + 652.3651999887079, + 741.7905000038445, + 680.8561999932863, + 818.4735999966506, + 706.9578999944497, + 640.5338000040501, + 777.3091999988537, + 640.6917000131216, + 955.9442999889143, + 896.1641999776475, + 1011.187099997187, + 738.727399992058, + 679.8182999773417, + 644.6599000191782, + 819.6540000208188, + 655.194399994798, + 650.6182999874, + 966.2954999948852, + 1067.556499998318, + 892.9491000017151, + 876.1949999898206, + 764.7945999924559, + 648.1793000129983, + 1322.9425000026822, + 648.0095000006258, + 802.5609999895096, + 655.8231000090018 + ], + "console": [ + 878.8335999997798, + 544.4022000010591, + 549.9015999957919, + 552.0763999957126, + 553.2633999828249, + 654.6709000249393, + 566.9008999830112, + 539.8568999953568, + 647.7355000097305, + 537.4379000277258, + 547.6250000065193, + 555.2980000211392, + 538.4752999816556, + 545.914599992102, + 629.0659999940544, + 883.4832000138704, + 549.7665000148118, + 566.7251999839209, + 542.9474000120535, + 614.1736000136007, + 665.1161000190768, + 749.7381999855861, + 804.2377999809105, + 569.241699995473, + 526.8982000125106, + 597.2422999911942, + 678.7798999866936, + 1057.6248000143096, + 539.0008999966085, + 828.3578999980818, + 790.9564999863505, + 704.7050000110175, + 842.3263000149745, + 643.1448000075761, + 729.195299994899, + 530.0132999836933, + 566.917000018293, + 1897.8484999970533, + 642.0046999992337, + 575.1177999773063, + 547.851500014076, + 524.2871000082232, + 582.6134000089951, + 589.5886000071187, + 553.8249000092037, + 541.021200013347, + 1117.9745999979787, + 810.1989999995567, + 620.6057000090368, + 538.8090000196826, + 741.0237999865785, + 541.1044999782462, + 567.8895000019111, + 547.9303999745753, + 759.6683999872766, + 766.0537000047043, + 540.0734999857377, + 764.5779000013135, + 600.0410999986343, + 828.8538999913726, + 563.5193000198342, + 651.2500999961048, + 644.543500005966, + 629.78370001656, + 803.4325999906287, + 608.5142999945674, + 842.1901999972761, + 537.4235999770463, + 779.6542000141926, + 764.8561999958474, + 688.7135999859311, + 585.2188000280876, + 708.1500999920536, + 539.2202999792062, + 554.1697000153363, + 763.654200010933, + 1417.1644000161905, + 640.1604000129737, + 538.0229000002146, + 544.0806999977212, + 549.7190999740269, + 841.2239000026602, + 827.1825999836437, + 756.1808000027668, + 844.5682000019588, + 734.149099997012, + 597.4882000009529, + 529.4629999843892, + 704.2493000044487, + 764.8680999991484, + 873.5732999921311, + 547.8664999827743, + 534.7407000081148, + 1139.8110000009183, + 756.1724999977741, + 552.8234000084922, + 545.4046000086237, + 553.759300004458, + 548.3135000104085, + 767.728700011503 + ], + "screenshot": [ + 585.7669000106398, + 783.8432000135072, + 835.8427000057418, + 596.1582000018097, + 928.0180000059772, + 725.8557000022847, + 651.7537999898195, + 587.9699000215624, + 1003.9685000083409, + 818.0680999939796, + 884.8537000012584, + 887.4417999759316, + 831.5045000053942, + 679.7457000066061, + 885.5116000049748, + 670.4961000068579, + 586.7657999915536, + 608.4954999969341, + 722.6425999833737, + 664.777400001185, + 820.5545999808237, + 1340.6722999934573, + 631.6273999982513, + 620.9578000125475, + 788.9481000020169, + 662.3613999981899, + 587.5432999746408, + 967.6849000097718, + 662.4212999886367, + 1333.5681000025943, + 1820.822399982717, + 590.7888999790885, + 1004.3862999882549, + 666.3667999964673, + 1036.4010000193957, + 591.6182000073604, + 697.5883000122849, + 582.7340999967419, + 696.9859999953769, + 920.7855999993626, + 593.7504000030458, + 596.1905000149272, + 662.3477000102866, + 659.5152000081725, + 845.2055999950971, + 601.550599996699, + 688.0041999975219, + 1262.8552000096533, + 715.6925000017509, + 870.1135000155773, + 1010.8125999977347, + 584.8742999951355, + 584.2650999838952, + 614.2165000201203, + 1212.6144999929238, + 975.7241999905091, + 600.5348999751732, + 1029.0832999744453, + 584.8770999873523, + 663.2709999976214, + 592.6484999945387, + 792.8537999978289, + 588.518499978818, + 583.2287000084762, + 725.483099988196, + 949.7593000123743, + 598.2782000210136, + 579.1115000029095, + 748.7527999910526, + 597.774699999718, + 640.0828000041656, + 644.3713000044227, + 584.9255000066478, + 791.7543000075966, + 837.3762000119314, + 600.0433999870438, + 605.9214000124484, + 601.0429000016302, + 798.4271000023, + 783.6737000034191, + 943.0223999952432, + 596.3820999895688, + 591.2518999830354, + 710.8528999960981, + 949.341799976537, + 710.4281000210904, + 841.7197999951895, + 602.6293000031728, + 709.7522999974899, + 1005.8579000178725, + 974.2059000127483, + 832.0647999935318, + 1092.5332000188064, + 621.9719999935478, + 703.7700999935623, + 606.0410000209231, + 891.9825999764726, + 593.71449999162, + 608.8771000213455, + 748.0339000176173 + ], + "material_search": [ + 775.7461000001058, + 592.4690999963786, + 555.7724999962375, + 789.2133000132162, + 789.2251999874134, + 835.0195999955758, + 687.3590000031982, + 672.4890999903437, + 1428.0893999966793, + 754.4191000051796, + 723.0263999954332, + 683.1285000080243, + 666.0026999888942, + 742.0894999813754, + 850.8775000227615, + 806.7008000216447, + 544.129999994766, + 678.9344000280835, + 666.1644999985583, + 541.6499999992084, + 637.3116000031587, + 1439.6140000026207, + 809.5478000177536, + 554.3605000129901, + 633.2304000097793, + 1435.7323999865912, + 793.9698999980465, + 565.2843000134453, + 776.6739000217058, + 549.1069999989122, + 578.1395999947563, + 634.608099993784, + 895.8433000079822, + 761.2613999808673, + 569.1185999894515, + 561.9865999906324, + 637.9727000021376, + 596.0597000084817, + 1376.5546999929938, + 541.0714999889024, + 729.8990999988746, + 547.5996000168379, + 748.2424000045285, + 548.9840999944136, + 879.2561000154819, + 859.4631000014488, + 542.5425000139512, + 542.4035000032745, + 813.0952999927104, + 700.6205999932718, + 556.5543999837246, + 545.4695000080392, + 718.3936999936122, + 560.741399996914, + 765.7325000036508, + 810.1583999814466, + 551.15929999738, + 841.6511999967042, + 541.3830000034068, + 553.6321999970824, + 567.6330999995116, + 797.4296000029426, + 741.7978000012226, + 722.7053000242449, + 624.6197999862488, + 555.1566000212915, + 546.5564000187442, + 739.1568000020925, + 610.0791999779176, + 563.8212999911048, + 800.4671999951825, + 773.2550000073388, + 544.0535999950953, + 664.3980999942869, + 670.5614999809768, + 601.0911999910604, + 549.0758999949321, + 733.7668999971356, + 1402.7813999855425, + 882.6287999982014, + 556.6532000084408, + 644.6892999811098, + 548.0456000077538, + 571.8536000058521, + 555.0035999913234, + 557.7142999973148, + 805.286899994826, + 741.5034000005107, + 724.2291999864392, + 1105.4730999749154, + 884.3123000115156, + 548.1665999977849, + 556.0980000009295, + 779.56350002205, + 1168.8887999916915, + 674.036900018109, + 1200.971100013703, + 786.121400014963, + 640.0682000094093, + 671.343900001375 + ], + "asset_copy": [ + 822.118500014767, + 929.5513999823015, + 601.03010002058, + 1505.7557999971323, + 628.4563999797683, + 791.9009999895934, + 996.8610999931116, + 1803.0127999954857, + 769.2643999762367, + 706.8051999958698, + 704.3335000053048, + 660.3705000015907, + 952.1615999983624, + 778.9737000130117, + 1274.8168999969494, + 805.7226999953855, + 622.9949000116903, + 595.6001000013202, + 669.9363999941852, + 594.5425000099931, + 720.1446999970358, + 967.7538999821991, + 1031.965100002708, + 613.9860000112094, + 668.7779000203591, + 642.7978000137955, + 773.6461000167765, + 840.262999990955, + 1052.2629999904893, + 616.2152000179049, + 885.3926000010688, + 762.9237999790348, + 1176.3876999903005, + 991.4286000130232, + 666.4329000050202, + 776.2765999941621, + 862.5018000020646, + 595.0753000215627, + 697.7216999803204, + 602.1766999911051, + 978.445599990664, + 674.5011000020895, + 1283.729199989466, + 585.969700012356, + 653.8296999933664, + 1207.4743999983184, + 891.4312999986578, + 752.5086999812629, + 773.7505000259262, + 1007.8442000085488, + 800.3298999974504, + 723.9907000039238, + 749.9422999972012, + 588.8279000064358, + 745.963200024562, + 620.7300999958534, + 850.4921999992803, + 638.3784000063315, + 883.8623999909032, + 602.0834000082687, + 672.3519999941345, + 1015.0422999868169, + 1285.0552999880165, + 1257.288199994946, + 641.4347999962047, + 621.4041000057478, + 618.7313999980688, + 707.0684999926016, + 940.2514999965206, + 600.5171000142582, + 902.4960999959148, + 791.3870000047609, + 614.8010000179056, + 991.7665999964811, + 978.4995000227354, + 1504.335199977504, + 598.7125000101514, + 712.5559000123758, + 713.6813999968581, + 1201.7408999963664, + 693.6264999967534, + 1840.747400012333, + 826.9493000116199, + 613.1290999765042, + 616.6343000077177, + 743.0310000199825, + 1008.3046000218019, + 1077.5414000090677, + 782.059199991636, + 835.1950999931432, + 803.0288000009023, + 602.6315999915823, + 807.9446000047028, + 732.7490999887232, + 994.1092999943066, + 790.213300002506, + 616.3817000051495, + 890.5115000088699, + 1279.8100000072736, + 613.2409000128973 + ], + "asset_move": [ + 870.7744999846909, + 1127.318999991985, + 685.291599977063, + 603.8341000094078, + 598.4455999860074, + 591.6826000029687, + 909.137800015742, + 1120.8624000137206, + 687.4274000001606, + 1158.1800999992993, + 609.5239999995101, + 588.3743999875151, + 1407.869499991648, + 602.6462000154424, + 591.913200012641, + 595.8421000104863, + 679.2122999904677, + 668.0206000164617, + 659.8153999948408, + 806.473200005712, + 1117.6611999981105, + 611.2858999986202, + 928.6878999846522, + 783.9221000031102, + 791.1160000076052, + 593.713200010825, + 1191.1211000115145, + 1006.289699987974, + 642.1931999793742, + 586.1778999969829, + 709.1261000023223, + 903.1979999854229, + 587.6917999994475, + 876.7524999857415, + 692.1589999983553, + 597.769000014523, + 768.8815000001341, + 868.1427999981679, + 581.200299988268, + 594.7485999786295, + 855.949699995108, + 817.676400009077, + 994.185399991693, + 745.9392999880947, + 879.1920999938156, + 605.967800016515, + 949.5554000022821, + 593.5170000011567, + 591.9919000007212, + 851.153700001305, + 614.6984999941196, + 886.2794999731705, + 1432.2549999924377, + 848.2630999933463, + 810.5564000143204, + 602.9257999907713, + 903.88980001444, + 774.2666999984067, + 978.3577999914996, + 603.8967000204138, + 583.5611000075005, + 593.5623000259511, + 795.9934999817051, + 591.9370999909006, + 883.1559999962337, + 896.2283000000753, + 692.784600018058, + 919.0281000046525, + 844.0293000021484, + 722.3949999897741, + 1281.8591999821365, + 592.8925000189338, + 765.0847999902908, + 882.6849999895785, + 753.9530000067316, + 863.9357999782078, + 604.2261999973562, + 889.4683999824338, + 717.1885000134353, + 599.3446999927983, + 631.0793999873567, + 685.4029000096489, + 1481.7879000038374, + 590.3645000071265, + 790.2804000186734, + 1201.1959000083152, + 616.367500013439, + 624.8286000045482, + 1189.083600009326, + 630.2312999905553, + 597.0167000195943, + 783.8935000181664, + 836.0889999894425, + 683.947999990778, + 623.4104000031948, + 880.0580999813974, + 861.9634000060614, + 650.2509000129066, + 963.0248000030406, + 646.4054000098258 + ], + "asset_delete": [ + 696.1257999937516, + 1150.5938000045717, + 898.6761999840382, + 606.474000000162, + 650.5525999818929, + 875.2378999779467, + 596.3301000010688, + 594.7087999957148, + 811.1338999879081, + 651.2425999972038, + 664.3013000139035, + 753.8629999908153, + 646.383200015407, + 776.9742000091355, + 786.1631000123452, + 573.5609999974258, + 829.191400000127, + 614.0652000030968, + 909.6483000030275, + 734.9953000084497, + 893.5643000004347, + 586.2149999884423, + 775.4899999999907, + 713.9599999936763, + 591.6576999879908, + 805.860099993879, + 1435.3728000132833, + 887.5819999957457, + 607.0816999999806, + 733.2650999887846, + 722.7804000140168, + 586.0639999737032, + 590.9188000077847, + 751.2526999926195, + 2212.986500002444, + 755.244700005278, + 943.2393999886699, + 902.2197999875061, + 581.1573999817483, + 593.221299990546, + 838.5357999941334, + 893.5154000064358, + 586.0529000055976, + 960.7263000216335, + 585.367200023029, + 592.0095999899786, + 1127.3789999831934, + 591.4977999927942, + 592.7872000029311, + 781.4828999980818, + 893.1324000004679, + 679.1728000098374, + 608.0081999825779, + 593.8317000109237, + 1037.0423000131268, + 597.3287000088021, + 596.4494999789167, + 941.8052000110038, + 589.812999998685, + 1086.9558000122197, + 579.3552999966778, + 772.1794999961276, + 582.0203999755904, + 589.5141000219155, + 1191.8276000069454, + 713.6066999810282, + 615.0020000059158, + 592.7238000149373, + 604.662500001723, + 743.8428000023123, + 782.3501999955624, + 965.1153000013437, + 901.4229999738745, + 890.4058999905828, + 780.3210999991279, + 857.3161999811418, + 1312.3553000041284, + 593.2508999831043, + 797.133300016867, + 698.5656000033487, + 591.437600000063, + 595.8466999873053, + 585.0539999955799, + 681.4590999856591, + 973.6612999986392, + 591.8992999941111, + 825.8540999959223, + 683.750099997269, + 594.5184000011068, + 727.8934000059962, + 875.8270000107586, + 841.1474000022281, + 786.268600000767, + 892.4533999816049, + 939.7979999775998, + 865.3782000183128, + 586.9642000179738, + 863.6136999994051, + 675.5152000114322, + 638.4147999924608 + ], + "import_settings": [ + 545.1917999889702, + 802.2437999898102, + 572.5775999890175, + 692.3321000067517, + 918.1628999940585, + 938.7074000260327, + 541.8632999935653, + 532.4744999816176, + 1373.5160999931395, + 541.029600019101, + 535.2160999900661, + 546.7988000018522, + 529.1220999788493, + 684.350000025006, + 699.8927000095136, + 1154.657600010978, + 1192.0811000163667, + 808.405199990375, + 890.1700999995228, + 833.1980000075419, + 547.0082000247203, + 528.7378999928478, + 670.2956999943126, + 895.7647999923211, + 769.6146999951452, + 781.8023000145331, + 812.3101000091992, + 634.1642999905162, + 802.2977999935392, + 855.136099999072, + 929.0727000043262, + 716.4177000231575, + 587.6121000037529, + 545.6819999963045, + 1083.4361000161152, + 672.5731000187807, + 545.9328999859281, + 537.917399982689, + 730.7714000053238, + 749.9318000045605, + 560.6165999779478, + 583.1032999849413, + 529.3635000125505, + 842.1356999897398, + 559.246599994367, + 690.3800000145566, + 591.4844000071753, + 747.239799995441, + 657.860300008906, + 540.4782999830786, + 690.3346999897622, + 847.4462000012863, + 819.4517999945674, + 663.7440999911632, + 758.7773999839555, + 547.4931999924593, + 536.27390001202, + 865.9047999826726, + 775.2117000054568, + 550.5452000070363, + 701.3395999965724, + 697.8719000180718, + 1165.8877999871038, + 661.6359000036027, + 548.892299993895, + 900.47950000735, + 872.8139000013471, + 550.4427000123542, + 774.621799995657, + 820.4719999921508, + 830.1428000268061, + 584.7094999917317, + 549.7652000049129, + 611.9347999920137, + 598.9503000164405, + 643.1737999955658, + 1051.3027000124566, + 538.7544000113849, + 1140.5786000250373, + 652.8177000000142, + 801.4742000086699, + 795.7204999984242, + 549.6110999956727, + 581.7583999887574, + 540.8404000045266, + 645.8887999760918, + 642.8570999996737, + 611.0610000032466, + 547.772799996892, + 555.163300014101, + 677.555600006599, + 1136.8454000039492, + 674.1760000004433, + 793.2109999819659, + 986.8536999856587, + 691.737799992552, + 535.3619999950752, + 795.2656999987084, + 888.9543999976013, + 630.6965999829117 + ], + "material_modify": [ + 573.1580999854486, + 792.9915000277106, + 596.909300016705, + 1494.452699989779, + 558.6438999744132, + 807.4541999958456, + 771.4343999978155, + 566.4905000012368, + 562.0939000218641, + 548.9882999972906, + 825.1445000059903, + 718.1772999756504, + 608.0620999855455, + 605.8551000023726, + 1513.74590001069, + 551.9783000054304, + 857.9181999957655, + 917.325400019763, + 562.3070000146981, + 851.0517999820877, + 795.7490000117105, + 575.3542000020389, + 574.2544999811798, + 566.3237000117078, + 667.5604000047315, + 917.9459000006318, + 581.3262999872677, + 596.2110999971628, + 738.8873000163585, + 614.7190000046976, + 686.6610000142828, + 637.4451000010595, + 835.648799984483, + 579.0755999914836, + 868.805899983272, + 636.0185999947134, + 640.8784000086598, + 707.7211000141688, + 690.526399994269, + 941.5528999816161, + 569.7799999907147, + 568.8241999887396, + 582.368100003805, + 634.6202999993693, + 652.967300004093, + 626.9353999814484, + 607.2918999998365, + 795.6061000004411, + 676.4931999787223, + 853.9393999963067, + 1576.9549999968149, + 633.3309999899939, + 842.5417999969795, + 933.8951000245288, + 733.3613999944646, + 781.7368999822065, + 644.4094000034966, + 563.2479999912903, + 666.8505000125151, + 753.5650999925565, + 1219.394599989755, + 796.6502000053879, + 574.9572000058834, + 566.6885999962687, + 670.5134999938309, + 924.9471000221092, + 546.6169000137597, + 844.1831000091042, + 846.8853000085801, + 657.4355000047944, + 854.6272999956273, + 565.3889000241179, + 574.6896000055131, + 582.600800000364, + 968.5549999994691, + 564.5459000079427, + 620.7914000260644, + 687.9446000093594, + 608.4513000096194, + 582.862200011732, + 676.6316999855917, + 829.4447000080254, + 855.0785999977961, + 845.6682999967597, + 651.5591000206769, + 797.5830000068527, + 1281.9728000031319, + 701.9766999874264, + 645.4442999965977, + 710.8767000027001, + 967.5787000160199, + 547.092499997234, + 651.8279000010807, + 653.7131000077352, + 1771.4797999942675, + 1022.4052999983542, + 796.9970000267494, + 939.972599997418, + 885.2636000083294, + 615.2060000167694 + ], + "time_settings": [ + 532.6948000001721, + 637.3549999843817, + 572.5793000019621, + 548.4812000067905, + 528.3443999942392, + 545.8195999963209, + 724.6720000111964, + 831.3446999818552, + 543.2362999999896, + 820.1014999940526, + 661.5344999881927, + 892.3912000027485, + 522.107099997811, + 720.8696999878157, + 690.5942999874242, + 527.0225999993272, + 546.1614000087138, + 545.5169999913778, + 533.775699994294, + 801.7503999872133, + 793.8303999835625, + 783.8919000059832, + 541.3877000100911, + 533.6037999950349, + 825.898099981714, + 616.5817999863066, + 545.2493000193499, + 819.061199988937, + 614.8437000229023, + 714.8589999997057, + 534.2132000077982, + 534.8727999953553, + 535.5304999975488, + 545.0852999929339, + 538.2072999782395, + 1751.5967999934219, + 579.3723000097089, + 528.7063000141643, + 873.1741999799851, + 874.6978999988642, + 542.7694000245538, + 690.6526999955531, + 700.7423000177369, + 818.5364000091795, + 564.9977999855764, + 675.5223000072874, + 773.5950000060257, + 891.4649000216741, + 1140.7944999809843, + 870.3730000124779, + 553.2199000008404, + 546.3301999843679, + 881.6261000174563, + 530.062400008319, + 546.6147999977693, + 933.0570999882184, + 530.3608999820426, + 542.648000002373, + 540.7925999897998, + 681.0873999784235, + 538.1628000177443, + 870.7705999840982, + 751.2909999932162, + 1034.5755000016652, + 836.3315000024159, + 768.0035999801476, + 563.7145999935456, + 623.2667999865953, + 665.9784000075888, + 531.2314000038896, + 953.0935000220779, + 763.8810000207741, + 558.8931999809574, + 805.159299983643, + 787.6077000109944, + 900.4580000182614, + 748.1490000209305, + 551.3158999965526, + 543.5593999864068, + 779.1426999901887, + 548.3342999941669, + 967.5533999979962, + 774.6706000179984, + 1510.3321000060532, + 539.7051000036299, + 592.2458000131883, + 1451.3333999784663, + 776.7257000086829, + 694.8417000239715, + 900.7915999973193, + 555.5246000003535, + 536.067400011234, + 552.9206999926828, + 782.4499999987893, + 1158.4746000007726, + 1194.490299996687, + 696.3033999782056, + 539.9503000080585, + 722.1543999912683, + 719.4713000208139 + ], + "read_csharp": [ + 540.8406000060495, + 950.6618999876082, + 692.4594999873079, + 555.9422000078484, + 549.0502000029664, + 542.8105999890249, + 868.2162000040989, + 661.1139999877196, + 629.3369999912102, + 1273.4977999934927, + 556.872499990277, + 598.4230000176467, + 783.5773999977391, + 548.1946999789216, + 630.6247000175063, + 811.4283999893814, + 590.2499000076205, + 606.5602999879047, + 766.7604000016581, + 546.5068999910727, + 2094.029700005194, + 981.8681000033394, + 548.8415000145324, + 657.4543000024278, + 541.1346000037156, + 545.9634999861009, + 685.8502999821212, + 708.8863000099082, + 556.5216999966651, + 681.5713999967556, + 798.8588000007439, + 815.5928000051063, + 780.3771000180859, + 641.7212999949697, + 539.282900019316, + 558.4131999930833, + 801.2604000105057, + 764.9144000024535, + 546.2969999935012, + 624.1807000187691, + 682.0226000272669, + 920.9528999926988, + 1480.2965999988373, + 781.2573999981396, + 603.8526000047568, + 636.9153999839909, + 1189.9990999954753, + 711.262099997839, + 1109.8311000096146, + 672.5537000165787, + 530.5065999855287, + 805.2061999915168, + 706.7762000078801, + 623.9041999797337, + 697.8639999870211, + 543.3907999831717, + 764.7678999928758, + 656.6015999997035, + 688.9809999847785, + 656.5028000040911, + 829.5128000027034, + 544.8719999985769, + 581.2258000078145, + 858.1987000070512, + 655.0779999815859, + 692.369399999734, + 527.2931999934372, + 828.6611000075936, + 542.0171999721788, + 538.8914000068326, + 650.7282999809831, + 1218.4204999939539, + 546.3463999913074, + 1478.82569997455, + 760.131499991985, + 1462.976200011326, + 618.8069999916479, + 670.6286999979056, + 542.480300005991, + 737.4194000149146, + 837.9917000129353, + 535.2193000144325, + 674.1791999957059, + 889.5738999999594, + 542.5600000016857, + 800.222300022142, + 536.7021999845747, + 952.2088999801781, + 557.8709999972489, + 594.1412000101991, + 536.8792999943253, + 541.0161000036169, + 556.5251000225544, + 1245.1212000160012, + 793.6111000017263, + 563.6801999935415, + 1181.248399981996, + 555.4078999848571, + 655.9885000169743, + 677.2036999755073 + ], + "play_until_ready": [ + 1139.074700011406, + 2092.5883000018075, + 1584.3199000228196, + 1140.9246000112034, + 2701.1799000028986, + 1900.1964000053704, + 1360.3705000132322, + 1386.148299992783, + 1086.7105000070296, + 1142.6039999932982, + 1487.6037999929395, + 1194.9569999997038, + 1236.473199998727, + 1948.6815000127535, + 1109.7463000041898, + 1988.7098000035621, + 2111.916800000472, + 1566.776400024537, + 1977.6595000002999, + 1463.3998000063002, + 1119.4409999880008, + 2054.356699984055, + 1103.950300021097, + 1111.257000011392, + 1092.3945999820717, + 1293.724299990572, + 1488.721000001533, + 2533.746000000974, + 1703.9536999945994, + 1519.69069999177, + 1407.9996999935247, + 2037.3575999983586, + 1860.660700011067, + 1820.6596999953035, + 1083.2998999976553, + 1358.6594999942463, + 1666.3934999960475, + 1635.4793999926187, + 1678.4608000016306, + 1984.8585999861825, + 1511.97449999745, + 1083.925300015835, + 1278.2444000185933, + 1163.1796999718063, + 1074.0731000259984, + 1815.4316000000108, + 1100.4288999829441, + 1138.073500012979, + 1402.575300016906, + 1101.7607999965549, + 1404.0001000103075, + 1349.222799995914, + 1102.1529999852646, + 1158.8859999901615, + 1370.3320999920834, + 1503.276699979324, + 2040.9462999959942, + 1353.59059998882, + 1769.5459999958985, + 1220.571799989557, + 1276.975400018273, + 1381.9693999830633, + 1382.9173000121955, + 1188.2276000105776, + 1536.5774999954738, + 1716.136600007303, + 1548.3464999997523, + 2143.5466000111774, + 1221.9705000170507, + 1394.4328999787103, + 1185.1773000089452, + 1115.2985999942757, + 1579.8076000064611, + 1081.4293999865185, + 1432.055199984461, + 1473.5769999970216, + 1372.7790999982972, + 1528.5825000028126, + 1275.7348000013735, + 1162.4703999841586, + 1291.6710999852512, + 1077.4740999913774, + 1081.6038999764714, + 1112.543299997924, + 1548.2946000120137, + 1531.9680999964476, + 1090.5377000162844, + 1155.1445000222884, + 1924.5447000139393, + 1095.1355999859516, + 1289.968700002646, + 1936.6979000042193, + 2199.8904999927618, + 1320.2087999961805, + 1153.7225999927614, + 1110.2382999961264, + 1321.5262000157963, + 1572.7306000189856, + 2023.8087000034284, + 1084.4191999931354 + ], + "stop_until_ready": [ + 1674.8637999990024, + 1122.6185999985319, + 1263.5947999951895, + 1397.8052999882493, + 1206.672600004822, + 1132.9588000080548, + 1501.5477999986615, + 1083.9925999753177, + 2392.99399999436, + 2444.052000006195, + 1519.8491000046488, + 1544.4753999763634, + 1269.7051000141073, + 1390.9950999950524, + 1963.7266999925487, + 1152.931799995713, + 1407.5596000184305, + 1366.6416999767534, + 1092.9048999969382, + 1369.7937999968417, + 1629.3047000071965, + 1351.0392000025604, + 1544.5819000015035, + 1461.0991000081412, + 1139.3514999945182, + 1391.2322000251152, + 1232.6950000133365, + 1363.4711999911815, + 1897.6919999986421, + 1132.0367999724112, + 2159.8048000014387, + 1255.6085000105668, + 1449.6202000009362, + 1278.7196999997832, + 1543.7051999906544, + 1266.9027000083588, + 1520.1249000092503, + 1819.859000010183, + 1401.528899994446, + 1146.6243999893777, + 1213.8398000097368, + 1080.3345999738667, + 1491.5877000021283, + 1338.8757000211626, + 1171.3799000135623, + 1117.4681999837048, + 1356.7886000091676, + 1872.429999988526, + 1337.9192000138573, + 2143.834499991499, + 2630.343400000129, + 1697.2714000148699, + 1233.7044999876525, + 1366.8276999960653, + 1083.8651999947615, + 1177.4955000146292, + 1079.504099994665, + 1890.639299992472, + 1210.8038000005763, + 1466.4274000097066, + 1317.3333999875467, + 1402.9812999942806, + 1872.0934999873862, + 2525.4806999873836, + 1343.8341000000946, + 1347.766299993964, + 1533.4868999780156, + 1411.1532999959309, + 1234.2049999861047, + 1397.0714999886695, + 1836.7847999907099, + 1109.7188999992795, + 1214.1844000143465, + 1151.1428999947384, + 1308.4219000011217, + 1129.7676999820396, + 1531.4635999966413, + 1179.660200024955, + 2300.941599998623, + 1343.3866999985185, + 1805.2405999915209, + 2487.8479999897536, + 1276.4403000182938, + 1763.092199980747, + 2116.104600019753, + 1110.6390000204556, + 1278.2934000133537, + 1593.7137999862898, + 1333.104999997886, + 1105.6476999947336, + 1283.5908999841195, + 1223.1151000014506, + 1617.173400009051, + 1345.1492000021972, + 1126.866600010544, + 1252.81969999196, + 1532.839999999851, + 1351.7906999913976, + 1392.6620999991428, + 1661.9418000045698 + ] + } + }, + "details": { + "official_shell_pid": 34664, + "discarded_focus_cycles": 0, + "operations": [ + { + "name": "editor_state", + "unity_cli": { + "tool": "get_editor_state", + "params": {} + }, + "official": { + "tool": "editor_status", + "params": {} + } + }, + { + "name": "hierarchy", + "unity_cli": { + "tool": "get_hierarchy", + "params": {} + }, + "official": { + "tool": "get_scene_hierarchy", + "params": {} + } + }, + { + "name": "find_gameobject", + "unity_cli": { + "tool": "find_gameobject", + "params": { + "name": "Perf394Target", + "exactMatch": true + } + }, + "official": { + "tool": "find_gameobjects", + "params": { + "name": "Perf394Target" + } + } + }, + { + "name": "transform", + "unity_cli": { + "tool": "get_component_values", + "params": { + "gameObjectName": "Perf394Target", + "componentType": "Transform" + } + }, + "official": { + "tool": "get_component_properties", + "params": { + "target": { + "hierarchyPath": "/Perf394Target" + }, + "type": "Transform" + } + } + }, + { + "name": "position", + "unity_cli": { + "tool": "modify_gameobject", + "params": { + "path": "/Perf394Target", + "position": { + "x": 1, + "y": 2, + "z": 3 + } + } + }, + "official": { + "tool": "set_transform", + "params": { + "target": { + "hierarchyPath": "/Perf394Target" + }, + "position": [ + 1, + 2, + 3 + ] + } + } + }, + { + "name": "create_cube", + "unity_cli": { + "tool": "create_gameobject", + "params": { + "name": "Perf394Cube", + "primitiveType": "cube" + } + }, + "official": { + "tool": "create_gameobject", + "params": { + "name": "Perf394Cube", + "primitive": "Cube" + } + } + }, + { + "name": "add_component", + "unity_cli": { + "tool": "add_component", + "params": { + "gameObjectPath": "/Perf394Cube", + "componentType": "Rigidbody" + } + }, + "official": { + "tool": "add_component", + "params": { + "target": { + "hierarchyPath": "/Perf394Cube" + }, + "type": "Rigidbody" + } + } + }, + { + "name": "remove_component", + "unity_cli": { + "tool": "remove_component", + "params": { + "gameObjectPath": "/Perf394Cube", + "componentType": "Rigidbody" + } + }, + "official": { + "tool": "remove_component", + "params": { + "target": { + "hierarchyPath": "/Perf394Cube" + }, + "type": "Rigidbody" + } + } + }, + { + "name": "delete_gameobject", + "unity_cli": { + "tool": "delete_gameobject", + "params": { + "path": "/Perf394Cube" + } + }, + "official": { + "tool": "delete_gameobject", + "params": { + "target": { + "hierarchyPath": "/Perf394Cube" + } + } + } + }, + { + "name": "scene_info", + "unity_cli": { + "tool": "get_scene_info", + "params": {} + }, + "official": { + "tool": "list_open_scenes", + "params": {} + } + }, + { + "name": "scene_save", + "unity_cli": { + "tool": "save_scene", + "params": {} + }, + "official": { + "tool": "save_scene", + "params": {} + } + }, + { + "name": "console", + "unity_cli": { + "tool": "read_console", + "params": { + "count": 20 + } + }, + "official": { + "tool": "console", + "params": { + "tail": 20, + "level": "log" + } + } + }, + { + "name": "screenshot", + "unity_cli": { + "tool": "capture_screenshot", + "params": { + "captureMode": "game", + "width": 1280, + "height": 720, + "includeUI": false, + "encodeAsBase64": false, + "osFallback": false + } + }, + "official": { + "tool": "screenshot", + "params": { + "view": "game", + "width": 1280, + "height": 720 + } + } + }, + { + "name": "material_search", + "unity_cli": { + "tool": "manage_asset_database", + "params": { + "action": "find_assets", + "filter": "t:Material", + "searchInFolders": [ + "Assets/Scenes/Generated/E2E/Performance" + ] + } + }, + "official": { + "tool": "find_assets", + "params": { + "type": "Material", + "search_in": "Assets/Scenes/Generated/E2E/Performance" + } + } + }, + { + "name": "asset_copy", + "unity_cli": { + "tool": "manage_asset_database", + "params": { + "action": "copy_asset", + "fromPath": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat", + "toPath": "Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat" + } + }, + "official": { + "tool": "copy_asset", + "params": { + "asset": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat", + "destination": "Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat" + } + } + }, + { + "name": "asset_move", + "unity_cli": { + "tool": "manage_asset_database", + "params": { + "action": "move_asset", + "fromPath": "Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat", + "toPath": "Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat" + } + }, + "official": { + "tool": "move_asset", + "params": { + "asset": "Assets/Scenes/Generated/E2E/Performance/PerfCopy.mat", + "destination": "Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat" + } + } + }, + { + "name": "asset_delete", + "unity_cli": { + "tool": "manage_asset_database", + "params": { + "action": "delete_asset", + "assetPath": "Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat" + } + }, + "official": { + "tool": "delete_asset", + "params": { + "asset": "Assets/Scenes/Generated/E2E/Performance/PerfMoved.mat", + "confirm": true + } + } + }, + { + "name": "import_settings", + "unity_cli": { + "tool": "manage_asset_import_settings", + "params": { + "action": "get", + "assetPath": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat" + } + }, + "official": { + "tool": "get_import_settings", + "params": { + "asset": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat" + } + } + }, + { + "name": "material_modify", + "unity_cli": { + "tool": "modify_material", + "params": { + "materialPath": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat", + "properties": { + "_Color": [ + 0.2, + 0.4, + 0.8, + 1 + ] + } + } + }, + "official": { + "tool": "set_material_properties", + "params": { + "material": "Assets/Scenes/Generated/E2E/Performance/PerfSource.mat", + "properties": { + "_Color": [ + 0.2, + 0.4, + 0.8, + 1 + ] + } + } + } + }, + { + "name": "time_settings", + "unity_cli": { + "tool": "get_project_settings", + "params": { + "includeTime": true, + "includePlayer": false + } + }, + "official": { + "tool": "get_time_settings", + "params": {} + } + }, + { + "name": "read_csharp", + "unity_cli": { + "tool": "read", + "params": { + "path": "Assets/HotReloadProbe.cs", + "maxLines": 50 + } + }, + "official": { + "tool": "read_text_file", + "params": { + "path": "Assets/HotReloadProbe.cs" + } + } + }, + { + "name": "play_until_ready", + "unity_cli": { + "tool": "play_game", + "params": {} + }, + "official": { + "tool": "editor_play", + "params": {} + } + }, + { + "name": "stop_until_ready", + "unity_cli": { + "tool": "stop_game", + "params": {} + }, + "official": { + "tool": "editor_stop", + "params": {} + } + } + ] + }, + "results": { + "unity-cli": { + "editor_state": { + "n": 100, + "p50_ms": 223.44, + "p95_ms": 715.67, + "mean_ms": 267.21, + "min_ms": 33.45, + "max_ms": 1246.88 + }, + "hierarchy": { + "n": 100, + "p50_ms": 40.66, + "p95_ms": 828.94, + "mean_ms": 209.29, + "min_ms": 34.81, + "max_ms": 1425.06 + }, + "find_gameobject": { + "n": 100, + "p50_ms": 38.06, + "p95_ms": 862.07, + "mean_ms": 202.51, + "min_ms": 33.79, + "max_ms": 1671.68 + }, + "transform": { + "n": 100, + "p50_ms": 40.79, + "p95_ms": 602.45, + "mean_ms": 173.05, + "min_ms": 36.16, + "max_ms": 1156.5 + }, + "position": { + "n": 100, + "p50_ms": 38.34, + "p95_ms": 598.93, + "mean_ms": 179.26, + "min_ms": 34.08, + "max_ms": 1190.91 + }, + "create_cube": { + "n": 100, + "p50_ms": 39.69, + "p95_ms": 898.57, + "mean_ms": 202.01, + "min_ms": 33.47, + "max_ms": 1432.58 + }, + "add_component": { + "n": 100, + "p50_ms": 51.85, + "p95_ms": 878.84, + "mean_ms": 157.4, + "min_ms": 42.28, + "max_ms": 1177.79 + }, + "remove_component": { + "n": 100, + "p50_ms": 46.29, + "p95_ms": 592.21, + "mean_ms": 152.19, + "min_ms": 36.99, + "max_ms": 1192.27 + }, + "delete_gameobject": { + "n": 100, + "p50_ms": 40.93, + "p95_ms": 328.88, + "mean_ms": 124.7, + "min_ms": 34.55, + "max_ms": 811.29 + }, + "scene_info": { + "n": 100, + "p50_ms": 37.65, + "p95_ms": 334.26, + "mean_ms": 104.6, + "min_ms": 34.31, + "max_ms": 887.18 + }, + "scene_save": { + "n": 100, + "p50_ms": 131.45, + "p95_ms": 647.33, + "mean_ms": 214.7, + "min_ms": 122.29, + "max_ms": 971.45 + }, + "console": { + "n": 100, + "p50_ms": 194.53, + "p95_ms": 319.23, + "mean_ms": 167.32, + "min_ms": 36.52, + "max_ms": 796.68 + }, + "screenshot": { + "n": 100, + "p50_ms": 96.07, + "p95_ms": 404.13, + "mean_ms": 181.16, + "min_ms": 84.06, + "max_ms": 695.93 + }, + "material_search": { + "n": 100, + "p50_ms": 43.35, + "p95_ms": 548.99, + "mean_ms": 174.78, + "min_ms": 37.24, + "max_ms": 860.0 + }, + "asset_copy": { + "n": 100, + "p50_ms": 100.9, + "p95_ms": 408.95, + "mean_ms": 190.57, + "min_ms": 93.14, + "max_ms": 930.57 + }, + "asset_move": { + "n": 100, + "p50_ms": 289.69, + "p95_ms": 593.52, + "mean_ms": 255.9, + "min_ms": 85.7, + "max_ms": 1113.76 + }, + "asset_delete": { + "n": 100, + "p50_ms": 89.09, + "p95_ms": 625.86, + "mean_ms": 256.25, + "min_ms": 79.68, + "max_ms": 1146.76 + }, + "import_settings": { + "n": 100, + "p50_ms": 248.28, + "p95_ms": 578.64, + "mean_ms": 213.08, + "min_ms": 35.15, + "max_ms": 1073.07 + }, + "material_modify": { + "n": 100, + "p50_ms": 63.1, + "p95_ms": 620.2, + "mean_ms": 181.07, + "min_ms": 57.31, + "max_ms": 1244.2 + }, + "time_settings": { + "n": 100, + "p50_ms": 39.11, + "p95_ms": 581.13, + "mean_ms": 159.04, + "min_ms": 33.87, + "max_ms": 1148.61 + }, + "read_csharp": { + "n": 100, + "p50_ms": 33.51, + "p95_ms": 596.27, + "mean_ms": 131.54, + "min_ms": 29.57, + "max_ms": 1120.63 + }, + "play_until_ready": { + "n": 100, + "p50_ms": 785.33, + "p95_ms": 1403.39, + "mean_ms": 903.03, + "min_ms": 762.15, + "max_ms": 2425.41 + }, + "stop_until_ready": { + "n": 100, + "p50_ms": 672.11, + "p95_ms": 1207.18, + "mean_ms": 761.89, + "min_ms": 568.33, + "max_ms": 1878.96 + } + }, + "official": { + "editor_state": { + "n": 100, + "p50_ms": 735.68, + "p95_ms": 1118.54, + "mean_ms": 747.35, + "min_ms": 529.21, + "max_ms": 1570.94 + }, + "hierarchy": { + "n": 100, + "p50_ms": 741.8, + "p95_ms": 1446.67, + "mean_ms": 803.88, + "min_ms": 530.98, + "max_ms": 1889.92 + }, + "find_gameobject": { + "n": 100, + "p50_ms": 711.2, + "p95_ms": 1209.85, + "mean_ms": 760.51, + "min_ms": 527.79, + "max_ms": 2252.91 + }, + "transform": { + "n": 100, + "p50_ms": 851.6, + "p95_ms": 1595.39, + "mean_ms": 936.28, + "min_ms": 714.55, + "max_ms": 2171.77 + }, + "position": { + "n": 100, + "p50_ms": 571.22, + "p95_ms": 1069.88, + "mean_ms": 694.68, + "min_ms": 529.38, + "max_ms": 1671.05 + }, + "create_cube": { + "n": 100, + "p50_ms": 631.0, + "p95_ms": 1186.84, + "mean_ms": 702.18, + "min_ms": 535.32, + "max_ms": 1954.51 + }, + "add_component": { + "n": 100, + "p50_ms": 839.05, + "p95_ms": 1353.01, + "mean_ms": 915.66, + "min_ms": 714.72, + "max_ms": 2513.51 + }, + "remove_component": { + "n": 100, + "p50_ms": 865.47, + "p95_ms": 1811.9, + "mean_ms": 963.6, + "min_ms": 716.6, + "max_ms": 2349.96 + }, + "delete_gameobject": { + "n": 100, + "p50_ms": 618.58, + "p95_ms": 1333.86, + "mean_ms": 749.76, + "min_ms": 532.01, + "max_ms": 1966.6 + }, + "scene_info": { + "n": 100, + "p50_ms": 626.42, + "p95_ms": 1164.28, + "mean_ms": 719.91, + "min_ms": 528.38, + "max_ms": 1438.63 + }, + "scene_save": { + "n": 100, + "p50_ms": 731.03, + "p95_ms": 1118.06, + "mean_ms": 790.75, + "min_ms": 628.34, + "max_ms": 1586.48 + }, + "console": { + "n": 100, + "p50_ms": 608.51, + "p95_ms": 883.48, + "mean_ms": 677.94, + "min_ms": 524.29, + "max_ms": 1897.85 + }, + "screenshot": { + "n": 100, + "p50_ms": 696.99, + "p95_ms": 1092.53, + "mean_ms": 762.98, + "min_ms": 579.11, + "max_ms": 1820.82 + }, + "material_search": { + "n": 100, + "p50_ms": 672.49, + "p95_ms": 1200.97, + "mean_ms": 722.98, + "min_ms": 541.07, + "max_ms": 1439.61 + }, + "asset_copy": { + "n": 100, + "p50_ms": 773.65, + "p95_ms": 1283.73, + "mean_ms": 837.09, + "min_ms": 585.97, + "max_ms": 1840.75 + }, + "asset_move": { + "n": 100, + "p50_ms": 745.94, + "p95_ms": 1191.12, + "mean_ms": 787.75, + "min_ms": 581.2, + "max_ms": 1481.79 + }, + "asset_delete": { + "n": 100, + "p50_ms": 727.89, + "p95_ms": 1127.38, + "mean_ms": 770.42, + "min_ms": 573.56, + "max_ms": 2212.99 + }, + "import_settings": { + "n": 100, + "p50_ms": 677.56, + "p95_ms": 1136.85, + "mean_ms": 720.65, + "min_ms": 528.74, + "max_ms": 1373.52 + }, + "material_modify": { + "n": 100, + "p50_ms": 670.51, + "p95_ms": 1219.39, + "mean_ms": 749.42, + "min_ms": 546.62, + "max_ms": 1771.48 + }, + "time_settings": { + "n": 100, + "p50_ms": 675.52, + "p95_ms": 1140.79, + "mean_ms": 715.55, + "min_ms": 522.11, + "max_ms": 1751.6 + }, + "read_csharp": { + "n": 100, + "p50_ms": 657.45, + "p95_ms": 1245.12, + "mean_ms": 735.52, + "min_ms": 527.29, + "max_ms": 2094.03 + }, + "play_until_ready": { + "n": 100, + "p50_ms": 1372.78, + "p95_ms": 2092.59, + "mean_ms": 1460.37, + "min_ms": 1074.07, + "max_ms": 2701.18 + }, + "stop_until_ready": { + "n": 100, + "p50_ms": 1356.79, + "p95_ms": 2300.94, + "mean_ms": 1463.95, + "min_ms": 1079.5, + "max_ms": 2630.34 + } + } + }, + "finished_at": "2026-10-04T00:43:08.815130+00:00" } \ No newline at end of file diff --git a/docs/verification/issue-386/resume/official-windows-summary.json b/docs/verification/issue-386/resume/official-windows-summary.json index c03472da..e5e9d9ce 100644 --- a/docs/verification/issue-386/resume/official-windows-summary.json +++ b/docs/verification/issue-386/resume/official-windows-summary.json @@ -1,6 +1,6 @@ { "conditions": { - "started_at": "2026-10-03T23:33:26.503448+00:00", + "started_at": "2026-10-04T00:00:25.043499+00:00", "os": "Windows-11-10.0.26300-SP0", "arch": "AMD64", "logical_cpus": 32, @@ -13,8 +13,8 @@ "pipeline_version": "0.8.0-exp.1", "unity_cli_sha256": "087d057cd62483c3c0aa64ceb85a77421349f2ace1ba236a13c1ddcffe909d35", "official_cli_sha256": "4cad9230dd98cc8d123d3ef9d18fef5e7ee65f353814c3cf9d94d9129293dda3", - "benchmark_sha256": "857569c8c542221f43a27423ecfa8fce3d11a690ed979985ebc670a56912f372", - "windows_adapter_sha256": "1d72ca848808f1fcce45a46b133691c7c6119f908e67e9519f72759a19d5af7b", + "benchmark_sha256": "8b4a77c97260fec724a5d1187c1561a7a0f25d9c3734fe8eada1c0a3ca4bc1e6", + "windows_adapter_sha256": "c47d896f41e81c6db8ba63ced94e927388b55cc81796b54578b3135685929c8a", "windows_adapter": "Original benchmark operations, validation, focus-discard and alternating order; Windows HWND foreground inspection and bounded reader thread replace macOS focus and POSIX select. No platform spoofing.", "background_condition": "Owned Editor minimized, because Windows refused activation of the existing GWT background window. This differs from macOS visible-background measurements.", "host_contention": "Other project canonical verification was active on this host; results are observations, no Windows budget or prior baseline was enforced.", @@ -36,7 +36,7 @@ "unityRemoteCompression": "", "unityRemoteResolution": "" }, - "unityd_pid": 52020 + "unityd_pid": 56288 }, "runs": [ { @@ -49,13 +49,19 @@ "mode": "process", "focus": "background", "status": "PASS", - "error": null + "source": "previous completed run, original conditions preserved" }, { "mode": "resident", "focus": "frontmost", - "status": "FAIL", - "error": "Invalid official NDJSON response: {'id': '15', 'exitCode': 6, 'envelope': {'success': False, 'command': 'unity command find_assets', 'data': None, 'errors': [{'code': 'COMMAND_FAILED', 'message': 'Pipeline server returned 400 Bad Request: Parameter Validation Failed. Illegal characters in path.'}], 'warnings': []}}" + "status": "PASS", + "error": null + }, + { + "mode": "resident", + "focus": "background", + "status": "PASS", + "error": null } ] } \ No newline at end of file diff --git a/docs/verification/issue-386/resume/source-snapshot.json b/docs/verification/issue-386/resume/source-snapshot.json index a1ec0efe..5f268fca 100644 --- a/docs/verification/issue-386/resume/source-snapshot.json +++ b/docs/verification/issue-386/resume/source-snapshot.json @@ -1,6 +1,6 @@ { - "recorded_at": "2026-10-04T00:10:05.758930+00:00", - "source_git_head_before_evidence_commit": "342f499fffba1d28c6e0839cd3c109b595083841", + "recorded_at": "2026-10-04T01:35:08.912579+00:00", + "source_git_head_before_evidence_commit": "d0c5ce21d85d171b285162b06edff03acdef53c9", "working_file_hashes": { "Cargo.lock": "0189b962ae9a4c0d8cbf492b3994ddc964a61b7fb3684b1bda27bc5b463d887f", "Cargo.toml": "d701e98bf9734c3bddea1f3f3bfdf49617141e598982bc09f309d09e6fe662bc", diff --git a/docs/verification/issue-386/resume/windows-comparison.md b/docs/verification/issue-386/resume/windows-comparison.md new file mode 100644 index 00000000..621c6c87 --- /dev/null +++ b/docs/verification/issue-386/resume/windows-comparison.md @@ -0,0 +1,89 @@ +# Windows 公式CLI比較の計測値 + +Windows 11 x64 / Unity6000.4.4f1 / unity-cli・Bridge0.18.1 debug / official1.0.0-beta.11 / Pipeline0.8.0-exp.1。 + +各操作は3回のwarmup後に100回、両ツールの順を交互にした。背景はEditorの最小化条件であり、macOSの表示した背景とは異なる。 +ほかのプロジェクトの正式検証がhostで稼働中だった。性能予算への合格や過去のbaselineとの同一条件比較ではない。 + +プロセス方式は呼出ごとに起動、常駐方式は同じunitydと同じ公式NDJSON shellを保持する。 +全条件で同一プロジェクトとEditorを確認した。バイナリ・scriptのSHA256とfocusによる除外数は各JSONに保持する。 + +## process / 前面 + +[全サンプル・条件JSON](official-windows-process-frontmost.json)。単位: ms。 + +| 操作 | unity-cli p50 | unity-cli p95 | 公式 p50 | 公式 p95 | +| --- | ---: | ---: | ---: | ---: | +| `create_gameobject` | 152.56 | 772.00 | 566.91 | 1400.40 | +| `hierarchy` | 41.16 | 677.94 | 616.34 | 1109.08 | +| `eval` | 1749.75 | 3522.45 | 736.40 | 1401.74 | + +## process / 最小化 + +[全サンプル・条件JSON](official-windows-process-background.json)。単位: ms。 + +| 操作 | unity-cli p50 | unity-cli p95 | 公式 p50 | 公式 p95 | +| --- | ---: | ---: | ---: | ---: | +| `create_gameobject` | 161.36 | 713.62 | 607.91 | 1141.02 | +| `hierarchy` | 270.32 | 1009.96 | 788.11 | 1180.21 | +| `eval` | 1708.23 | 3227.09 | 668.51 | 1310.37 | + +## resident / 前面 + +[全サンプル・条件JSON](official-windows-resident-frontmost.json)。単位: ms。 + +| 操作 | unity-cli p50 | unity-cli p95 | 公式 p50 | 公式 p95 | +| --- | ---: | ---: | ---: | ---: | +| `editor_state` | 223.44 | 715.67 | 735.68 | 1118.54 | +| `hierarchy` | 40.66 | 828.94 | 741.80 | 1446.67 | +| `find_gameobject` | 38.06 | 862.07 | 711.20 | 1209.85 | +| `transform` | 40.79 | 602.45 | 851.60 | 1595.39 | +| `position` | 38.34 | 598.93 | 571.22 | 1069.88 | +| `create_cube` | 39.69 | 898.57 | 631.00 | 1186.84 | +| `add_component` | 51.85 | 878.84 | 839.05 | 1353.01 | +| `remove_component` | 46.29 | 592.21 | 865.47 | 1811.90 | +| `delete_gameobject` | 40.93 | 328.88 | 618.58 | 1333.86 | +| `scene_info` | 37.65 | 334.26 | 626.42 | 1164.28 | +| `scene_save` | 131.45 | 647.33 | 731.03 | 1118.06 | +| `console` | 194.53 | 319.23 | 608.51 | 883.48 | +| `screenshot` | 96.07 | 404.13 | 696.99 | 1092.53 | +| `material_search` | 43.35 | 548.99 | 672.49 | 1200.97 | +| `asset_copy` | 100.90 | 408.95 | 773.65 | 1283.73 | +| `asset_move` | 289.69 | 593.52 | 745.94 | 1191.12 | +| `asset_delete` | 89.09 | 625.86 | 727.89 | 1127.38 | +| `import_settings` | 248.28 | 578.64 | 677.56 | 1136.85 | +| `material_modify` | 63.10 | 620.20 | 670.51 | 1219.39 | +| `time_settings` | 39.11 | 581.13 | 675.52 | 1140.79 | +| `read_csharp` | 33.51 | 596.27 | 657.45 | 1245.12 | +| `play_until_ready` | 785.33 | 1403.39 | 1372.78 | 2092.59 | +| `stop_until_ready` | 672.11 | 1207.18 | 1356.79 | 2300.94 | + +## resident / 最小化 + +[全サンプル・条件JSON](official-windows-resident-background.json)。単位: ms。 + +| 操作 | unity-cli p50 | unity-cli p95 | 公式 p50 | 公式 p95 | +| --- | ---: | ---: | ---: | ---: | +| `editor_state` | 201.96 | 706.68 | 705.11 | 1094.77 | +| `hierarchy` | 103.11 | 899.01 | 691.88 | 1272.59 | +| `find_gameobject` | 106.43 | 707.95 | 692.45 | 1292.24 | +| `transform` | 107.25 | 701.11 | 895.84 | 1391.78 | +| `position` | 103.13 | 1102.66 | 694.65 | 1316.50 | +| `create_cube` | 103.87 | 902.30 | 701.23 | 1121.95 | +| `add_component` | 102.21 | 702.83 | 890.33 | 1204.97 | +| `remove_component` | 102.97 | 903.02 | 909.00 | 1511.48 | +| `delete_gameobject` | 101.15 | 602.33 | 702.73 | 1195.75 | +| `scene_info` | 100.75 | 598.80 | 686.22 | 1287.26 | +| `scene_save` | 193.74 | 506.45 | 813.59 | 1310.85 | +| `console` | 219.77 | 423.74 | 618.18 | 1146.31 | +| `screenshot` | 206.83 | 831.21 | 734.02 | 1355.40 | +| `material_search` | 200.25 | 563.19 | 715.92 | 1396.92 | +| `asset_copy` | 162.34 | 959.58 | 843.09 | 1356.51 | +| `asset_move` | 263.80 | 667.39 | 682.49 | 1277.85 | +| `asset_delete` | 335.01 | 662.07 | 684.14 | 1192.27 | +| `import_settings` | 118.93 | 914.90 | 642.20 | 1133.44 | +| `material_modify` | 139.28 | 932.20 | 653.47 | 1244.54 | +| `time_settings` | 117.84 | 914.90 | 623.08 | 1197.13 | +| `read_csharp` | 37.44 | 580.05 | 694.92 | 1302.50 | +| `play_until_ready` | 822.01 | 1466.44 | 1435.69 | 2099.78 | +| `stop_until_ready` | 737.03 | 1428.65 | 1441.33 | 2158.01 | diff --git a/docs/verification/issue-386/resume/winget-secret-state.json b/docs/verification/issue-386/resume/winget-secret-state.json new file mode 100644 index 00000000..371179c7 --- /dev/null +++ b/docs/verification/issue-386/resume/winget-secret-state.json @@ -0,0 +1,5 @@ +{ + "WINGET_TOKEN_name_present": false, + "secret_values_read": false, + "source": "gh secret list --repo akiojin/unity-cli --json name" +} \ No newline at end of file diff --git a/docs/verification/issue-386/resume/winget-source-final.txt b/docs/verification/issue-386/resume/winget-source-final.txt new file mode 100644 index 00000000..bba90bf4 --- /dev/null +++ b/docs/verification/issue-386/resume/winget-source-final.txt @@ -0,0 +1 @@ +入力条件に一致するパッケージが見つかりませんでした。 From a50ddd407fb041b0ac463852bf0965cd3ce56f7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Oct 2026 00:08:40 +0000 Subject: [PATCH 08/73] chore(deps): bump the npm_and_yarn group with 3 updates --- updated-dependencies: - dependency-name: "@google/gemini-cli" dependency-version: 0.62.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm_and_yarn - dependency-name: "@openai/codex" dependency-version: 0.160.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm_and_yarn - dependency-name: globals dependency-version: 17.13.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package.json | 6 ++-- pnpm-lock.yaml | 88 +++++++++++++++++++++++++------------------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 8779bd51..f8b6d3b8 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,10 @@ "@commitlint/cli": "^21.1.0", "@commitlint/config-conventional": "^21.1.0", "@eslint/js": "^10.0.1", - "@google/gemini-cli": "^0.49.0", - "@openai/codex": "^0.142.3", + "@google/gemini-cli": "^0.62.0", + "@openai/codex": "^0.160.0", "eslint": "^10.6.0", - "globals": "^17.7.0", + "globals": "^17.13.0", "husky": "^9.1.7", "markdownlint-cli": "^0.49.0", "prettier": "^3.9.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25b18a24..aa066c09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,17 +28,17 @@ importers: specifier: ^10.0.1 version: 10.0.1(eslint@10.11.0(jiti@2.6.1)) '@google/gemini-cli': - specifier: ^0.49.0 - version: 0.49.0 + specifier: ^0.62.0 + version: 0.62.0 '@openai/codex': - specifier: ^0.142.3 - version: 0.142.5 + specifier: ^0.160.0 + version: 0.160.0 eslint: specifier: ^10.6.0 version: 10.11.0(jiti@2.6.1) globals: - specifier: ^17.7.0 - version: 17.12.0 + specifier: ^17.13.0 + version: 17.13.0 husky: specifier: ^9.1.7 version: 9.1.7 @@ -192,8 +192,8 @@ packages: '@github/keytar@7.10.6': resolution: {integrity: sha512-mRW6cUsSG+nj4jp5gp8e91zPySaT73r+2JM6VyMZfrEgksjPmjSMr+tPGNOK3HUHV+GUU9B1LAiiYy/wmAnIxA==} - '@google/gemini-cli@0.49.0': - resolution: {integrity: sha512-S0b6nfAf+lHbSPMKRuQziU1/710a7f/Jag2mZ7N1J1b48qxoCmjwNCJJ7XPEv/ropvDqkCjJupE32qcw+ym3jQ==} + '@google/gemini-cli@0.62.0': + resolution: {integrity: sha512-A1rw0Tf2sHLpGncfYdaq5WaJIufKAP8il4BmHD5Yw4ewmB/Wo0vRQb2bEvx7OqyaPFPZCh0hVhcMKsICZyIBww==} engines: {node: '>=20'} hasBin: true @@ -259,43 +259,43 @@ packages: '@lydell/node-pty@1.1.0': resolution: {integrity: sha512-VDD8LtlMTOrPKWMXUAcB9+LTktzuunqrMwkYR1DMRBkS6LQrCt+0/Ws1o2rMml/n3guePpS7cxhHF7Nm5K4iMw==} - '@openai/codex@0.142.5': - resolution: {integrity: sha512-WQEpD7l3k68eIAP0aq28EdR18ENBAf8DyprzFhzNwCOQJSv4nHzpwT8Fl30IJacprko2ZCmUBZjM2u941l2yLw==} + '@openai/codex@0.160.0': + resolution: {integrity: sha512-kEtVGzjRAYAMOwJxN39bGcna7LT3IDQgq64NNJ/dDTfu4OzZaocJcyNb5/gGJ/IVF/Vj7oK7E2m3nmTan7lpjg==} engines: {node: '>=16'} hasBin: true - '@openai/codex@0.142.5-darwin-arm64': - resolution: {integrity: sha512-l43p8xv+Z/2/b6fCUc7/FmcQZsaPB7RFizLponGwHAnFOWe3i9Vky69p+up3BUam9AetoQQUv7Mo+2KdaFEqhA==} + '@openai/codex@0.160.0-darwin-arm64': + resolution: {integrity: sha512-aefV6cqZA2REZgR//4McyXlp7zLcTti4CI2v3j9IVgNndPBv2kCeNEcz07qeelXcwOdSFPUKb6roA48vZmDgrQ==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@openai/codex@0.142.5-darwin-x64': - resolution: {integrity: sha512-yk6A06/VmW7NFsa48OVPaj//g/zeSpd79wjuqfXZwW8ZKRYQm3+wCd3hWjPl79F3QnXvDvM2j3JMIBL3m3GXXg==} + '@openai/codex@0.160.0-darwin-x64': + resolution: {integrity: sha512-ir7cdsPrb9VkqNqpTECoTiomv04xws/FQ968mHQzuL+2J5Da0Dkh2Qlxp7sguDDZJab4YpYmNjQvBVMXbTeQaQ==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@openai/codex@0.142.5-linux-arm64': - resolution: {integrity: sha512-77ka5PSnm5HdxdBT99IwntCasmbqevlS0eiC0AtEb6ZXCLkim2gm0AWm+jNYy0EhbssvNK+KghayWo34HMgXeA==} + '@openai/codex@0.160.0-linux-arm64': + resolution: {integrity: sha512-VnVdsS06YlDsL8OwaJjQ3xdqdJNG4i+eBJBV3LytddknzSaF/urijLzVg3ptkwvoj8C7Gn7iWpVE+y8WEaPiCg==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@openai/codex@0.142.5-linux-x64': - resolution: {integrity: sha512-pxY+d3NgNE57Y/MApD3/TZUAygxJN6I9h3ZeDUwe67mxWjUxsuapxMRFTKSznCalYbRAeZp752+AAXmUbmguEg==} + '@openai/codex@0.160.0-linux-x64': + resolution: {integrity: sha512-KI/73OqGrHmR18s7ya7E1NqV6rT0y3lxr0s8S1qR2m6zU6QRF/HlR529jALLh5vjdUnsRT4Ahoxt0axb4kY99g==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@openai/codex@0.142.5-win32-arm64': - resolution: {integrity: sha512-65BEqGbUZ7r0ayunIHdBjo5crwgbwKX/6puOcO+VCswUw/dXvDsN2IGcbXB52+bS9U5+FxP783cUHfTT6m40DQ==} + '@openai/codex@0.160.0-win32-arm64': + resolution: {integrity: sha512-tTvK9ZIGuj9WnYaYOAnfjJVSfPV7dKqWtDHqUPLf0Hadp6SgynTxx7S7iMXRieFeXVOI2XH76KxEHSOTOnz3zw==} engines: {node: '>=16'} cpu: [arm64] os: [win32] - '@openai/codex@0.142.5-win32-x64': - resolution: {integrity: sha512-a+wI4PEx9a2fg6V5ueTTDkOkr1XpEvA5RFXIbo/L2hOfzMmGtyRnbG24bCGu5Q2RSgVxSQV0aLkdb3vdYMNH9A==} + '@openai/codex@0.160.0-win32-x64': + resolution: {integrity: sha512-/gCFcuOmGlQkgGivWCtY8BNEDixh70Pue0HZOk9S8bj2vUIE1GLD9zcNB/KqqDJmn0S+lIttauLpzQnw6HOCHA==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -576,8 +576,8 @@ packages: resolution: {integrity: sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==} engines: {node: '>=20'} - globals@17.12.0: - resolution: {integrity: sha512-cezEd/DTyyht9cvSSURyygXPfy04GtWO/5e6ZPvH7fCtjKz9PYOmuawphw1Ctd1f6C+5JypXfGD7ahNMXvevBA==} + globals@17.13.0: + resolution: {integrity: sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==} engines: {node: '>=18'} hashery@1.5.1: @@ -811,8 +811,8 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - node-addon-api@8.8.0: - resolution: {integrity: sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA==} + node-addon-api@8.9.2: + resolution: {integrity: sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg==} engines: {node: ^18 || ^20 || >= 21} node-pty@1.0.0: @@ -1158,10 +1158,10 @@ snapshots: '@github/keytar@7.10.6': dependencies: - node-addon-api: 8.8.0 + node-addon-api: 8.9.2 optional: true - '@google/gemini-cli@0.49.0': + '@google/gemini-cli@0.62.0': optionalDependencies: '@github/keytar': 7.10.6 '@lydell/node-pty': 1.1.0 @@ -1224,31 +1224,31 @@ snapshots: '@lydell/node-pty-win32-x64': 1.1.0 optional: true - '@openai/codex@0.142.5': + '@openai/codex@0.160.0': optionalDependencies: - '@openai/codex-darwin-arm64': '@openai/codex@0.142.5-darwin-arm64' - '@openai/codex-darwin-x64': '@openai/codex@0.142.5-darwin-x64' - '@openai/codex-linux-arm64': '@openai/codex@0.142.5-linux-arm64' - '@openai/codex-linux-x64': '@openai/codex@0.142.5-linux-x64' - '@openai/codex-win32-arm64': '@openai/codex@0.142.5-win32-arm64' - '@openai/codex-win32-x64': '@openai/codex@0.142.5-win32-x64' - - '@openai/codex@0.142.5-darwin-arm64': + '@openai/codex-darwin-arm64': '@openai/codex@0.160.0-darwin-arm64' + '@openai/codex-darwin-x64': '@openai/codex@0.160.0-darwin-x64' + '@openai/codex-linux-arm64': '@openai/codex@0.160.0-linux-arm64' + '@openai/codex-linux-x64': '@openai/codex@0.160.0-linux-x64' + '@openai/codex-win32-arm64': '@openai/codex@0.160.0-win32-arm64' + '@openai/codex-win32-x64': '@openai/codex@0.160.0-win32-x64' + + '@openai/codex@0.160.0-darwin-arm64': optional: true - '@openai/codex@0.142.5-darwin-x64': + '@openai/codex@0.160.0-darwin-x64': optional: true - '@openai/codex@0.142.5-linux-arm64': + '@openai/codex@0.160.0-linux-arm64': optional: true - '@openai/codex@0.142.5-linux-x64': + '@openai/codex@0.160.0-linux-x64': optional: true - '@openai/codex@0.142.5-win32-arm64': + '@openai/codex@0.160.0-win32-arm64': optional: true - '@openai/codex@0.142.5-win32-x64': + '@openai/codex@0.160.0-win32-x64': optional: true '@simple-libs/child-process-utils@2.0.0': @@ -1513,7 +1513,7 @@ snapshots: dependencies: ini: 6.0.0 - globals@17.12.0: {} + globals@17.13.0: {} hashery@1.5.1: dependencies: @@ -1837,7 +1837,7 @@ snapshots: natural-compare@1.4.0: {} - node-addon-api@8.8.0: + node-addon-api@8.9.2: optional: true node-pty@1.0.0: From 7d2ef384c9f01587d26f809890f188e11c2bbe86 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Mon, 5 Oct 2026 15:29:53 +0900 Subject: [PATCH 09/73] ci: make Codecov upload non-fatal and ignore bincode >=3 (#472) The required coverage checks failed because codecov-action could not download its uploader (TLS handshake failure), not because coverage dropped. Keep the 90% gates (--fail-under-lines 90, coverlet Threshold=90) required and make only the external upload best-effort. bincode 3.0.0 is a compile_error!-only release, so exclude >=3 from dependabot cargo updates. Co-Authored-By: Claude Fable 5.1 --- .github/dependabot.yml | 4 ++++ .github/workflows/test.yml | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3f6960f8..27e7de9a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -34,6 +34,10 @@ updates: cargo: patterns: - "*" + ignore: + # bincode 3.0.0 is a compile_error!-only release; stay on 1.x (#342, #472). + - dependency-name: "bincode" + versions: [">=3"] commit-message: prefix: "chore(deps)" labels: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ffc74a69..57cb5a10 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -244,14 +244,16 @@ jobs: --fail-under-lines 90 \ -- --test-threads=1 + # Codecov upload is best-effort: the 90% gate above stays required, an external outage must not block merges (#472). - name: Upload Rust coverage to Codecov + continue-on-error: true uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage/rust/cobertura.xml flags: rust name: rust-coverage - fail_ci_if_error: true + fail_ci_if_error: false verbose: true lsp-coverage: @@ -274,14 +276,16 @@ jobs: /p:ThresholdType=line \ /p:ThresholdStat=total + # Codecov upload is best-effort: the 90% gate above stays required, an external outage must not block merges (#472). - name: Upload LSP coverage to Codecov + continue-on-error: true uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} files: lsp/coverage.cobertura.xml flags: lsp name: lsp-coverage - fail_ci_if_error: true + fail_ci_if_error: false verbose: true lsp-perf: From b390d54256586a4c4d3ca1f1f48ed6076f39ed18 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Mon, 5 Oct 2026 15:29:54 +0900 Subject: [PATCH 10/73] chore(gwt): record work events for #472 Co-Authored-By: Claude Fable 5.1 --- ...49df6fcd7a525d56e05c85d5c4c0d7e615458d34682bb7bff292a30.jsonl | 1 + ...0a43a8e22014334dafec05839fb0595a4c62eaa078e7555617c25ae.jsonl | 1 + 2 files changed, 2 insertions(+) create mode 100644 .gwt/work/events/06/068f272fd49df6fcd7a525d56e05c85d5c4c0d7e615458d34682bb7bff292a30.jsonl create mode 100644 .gwt/work/events/8e/8ed6def970a43a8e22014334dafec05839fb0595a4c62eaa078e7555617c25ae.jsonl diff --git a/.gwt/work/events/06/068f272fd49df6fcd7a525d56e05c85d5c4c0d7e615458d34682bb7bff292a30.jsonl b/.gwt/work/events/06/068f272fd49df6fcd7a525d56e05c85d5c4c0d7e615458d34682bb7bff292a30.jsonl new file mode 100644 index 00000000..5e2e5878 --- /dev/null +++ b/.gwt/work/events/06/068f272fd49df6fcd7a525d56e05c85d5c4c0d7e615458d34682bb7bff292a30.jsonl @@ -0,0 +1 @@ +{"id":"34292acb-30f2-46c4-af57-745f925210b5","work_item_id":"work-work-issue-472-3e7dc4d8","kind":"update","title":"Issue #472 の残り受け入れ基準の実装","intent":"Issue #472 の受け入れ基準を評価中","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #472","next_action":null,"agent_session_id":"af4d50d1-e3e4-4be1-984c-46d1c52b560c","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-472","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-472","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-05T06:23:59.102393Z"} diff --git a/.gwt/work/events/8e/8ed6def970a43a8e22014334dafec05839fb0595a4c62eaa078e7555617c25ae.jsonl b/.gwt/work/events/8e/8ed6def970a43a8e22014334dafec05839fb0595a4c62eaa078e7555617c25ae.jsonl new file mode 100644 index 00000000..50165e15 --- /dev/null +++ b/.gwt/work/events/8e/8ed6def970a43a8e22014334dafec05839fb0595a4c62eaa078e7555617c25ae.jsonl @@ -0,0 +1 @@ +{"id":"0317fd08-2bd2-4a47-b053-7f5cb9809757","work_item_id":"work-work-issue-472-3e7dc4d8","kind":"start","title":"ci: Codecov アップロード失敗で必須カバレッジチェックが落ちる問題と bincode 3 の除外","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #472","next_action":"Check Board for latest updates","agent_session_id":"af4d50d1-e3e4-4be1-984c-46d1c52b560c","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-472","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-472","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-05T06:23:48.482316Z"} From 376a57a4b4e54a532f0cb7fd2a6522b36d20494e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Oct 2026 06:37:34 +0000 Subject: [PATCH 11/73] chore(deps): bump actions/upload-artifact from 6 to 7 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 57cb5a10..4117f91c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,7 +49,7 @@ jobs: - name: Upload CLI latency evidence if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: cli-latency path: artifacts/cli-latency*.json From 7f52551a8640e8a1ca1ac65e95967dbeab444422 Mon Sep 17 00:00:00 2001 From: akiojin Date: Mon, 5 Oct 2026 19:49:19 +0900 Subject: [PATCH 12/73] chore(deps): update cargo group and preserve embedding indexes --- .github/dependabot.yml | 5 ++- ...927cd3270f94952a1394e40c74c0d1c29dd9.jsonl | 1 + ...336b0f678f89d1e54101551e6c61689eebdc.jsonl | 1 + ...dd859b92e2ba8fb0e412f6759e6e37c7a54c.jsonl | 1 + Cargo.lock | 14 +++---- Cargo.toml | 7 ++-- src/reference/embed.rs | 37 +++++++++++++++++- .../fastembed6-bincode1.bin | Bin 0 -> 1683 bytes 8 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 .gwt/work/events/87/87518854cd606f8fb7879ae5aa7a927cd3270f94952a1394e40c74c0d1c29dd9.jsonl create mode 100644 .gwt/work/events/a4/a4b4785c35358bc10513ba81717f336b0f678f89d1e54101551e6c61689eebdc.jsonl create mode 100644 .gwt/work/events/ad/adf8548a76ec7f2e0af45130f8f8dd859b92e2ba8fb0e412f6759e6e37c7a54c.jsonl create mode 100644 tests/fixtures/reference-embedding/fastembed6-bincode1.bin diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 27e7de9a..03b5c921 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -35,9 +35,10 @@ updates: patterns: - "*" ignore: - # bincode 3.0.0 is a compile_error!-only release; stay on 1.x (#342, #472). + # bincode >=2 changes the persisted embedding index format; retain 1.3.3 (#342, #475). + # bincode 3.0.0 is also a compile_error!-only release (#472). - dependency-name: "bincode" - versions: [">=3"] + versions: [">=2"] commit-message: prefix: "chore(deps)" labels: diff --git a/.gwt/work/events/87/87518854cd606f8fb7879ae5aa7a927cd3270f94952a1394e40c74c0d1c29dd9.jsonl b/.gwt/work/events/87/87518854cd606f8fb7879ae5aa7a927cd3270f94952a1394e40c74c0d1c29dd9.jsonl new file mode 100644 index 00000000..4bc3e28c --- /dev/null +++ b/.gwt/work/events/87/87518854cd606f8fb7879ae5aa7a927cd3270f94952a1394e40c74c0d1c29dd9.jsonl @@ -0,0 +1 @@ +{"id":"d0df8370-674e-40f5-a015-d7e43a868c00","work_item_id":"work-work-issue-475-ccff3abe","kind":"start","title":"chore(deps): cargo 依存更新(#474: fastembed 7 / base64 0.23)を取り込み、bincode は 1.x に固定","intent":"Check Board for latest updates","summary":"Codex is running","progress_summary":null,"status_category":"active","owner":"Issue #475","next_action":"Check Board for latest updates","agent_session_id":"4a83e26a-e282-4ed3-99ee-9fcb8e1a903c","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-475","worktree_path":"E:\\unity-cli\\work\\issue-475","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-05T10:33:16.717425800Z"} diff --git a/.gwt/work/events/a4/a4b4785c35358bc10513ba81717f336b0f678f89d1e54101551e6c61689eebdc.jsonl b/.gwt/work/events/a4/a4b4785c35358bc10513ba81717f336b0f678f89d1e54101551e6c61689eebdc.jsonl new file mode 100644 index 00000000..cafc322e --- /dev/null +++ b/.gwt/work/events/a4/a4b4785c35358bc10513ba81717f336b0f678f89d1e54101551e6c61689eebdc.jsonl @@ -0,0 +1 @@ +{"id":"5e1134be-5e8f-4bee-a9f8-c7d496bad0b9","work_item_id":"work-work-issue-475-ccff3abe","kind":"done","title":"Cargo 依存更新(#475)","intent":"実装とローカル検証が終了。正式検証記録・置換 PR・CI マージを進める","summary":"base64 0.23.1 / fastembed 7.1.0 / socket2 0.6.5 / libc 0.2.189 を更新。bincode=1.3.3 と既存インデックス形式を保持。Rust611件、clippy/fmt/skills lint PASS。Windows LSP既存2件失敗はbaseline再現・PM共有済み。","progress_summary":null,"status_category":"done","owner":"Issue #475","next_action":"commit/push後に全Rust targetの正式verify.runを実行し、#474置換Ready PRをauto-mergeまで追跡する","agent_session_id":"4a83e26a-e282-4ed3-99ee-9fcb8e1a903c","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-475","worktree_path":"E:\\unity-cli\\work\\issue-475","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-05T10:49:16.238847400Z"} diff --git a/.gwt/work/events/ad/adf8548a76ec7f2e0af45130f8f8dd859b92e2ba8fb0e412f6759e6e37c7a54c.jsonl b/.gwt/work/events/ad/adf8548a76ec7f2e0af45130f8f8dd859b92e2ba8fb0e412f6759e6e37c7a54c.jsonl new file mode 100644 index 00000000..688aedb2 --- /dev/null +++ b/.gwt/work/events/ad/adf8548a76ec7f2e0af45130f8f8dd859b92e2ba8fb0e412f6759e6e37c7a54c.jsonl @@ -0,0 +1 @@ +{"id":"231cd0a0-b6ef-47bb-8c7a-044a265ad564","work_item_id":"work-work-issue-475-ccff3abe","kind":"update","title":"Issue #475 の受け入れ条件","intent":"Issue 本文、関連 PR、実装を照合し、残る受け入れ条件を監査","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #475","next_action":null,"agent_session_id":"4a83e26a-e282-4ed3-99ee-9fcb8e1a903c","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-475","worktree_path":"E:\\unity-cli\\work\\issue-475","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-05T10:35:30.643259600Z"} diff --git a/Cargo.lock b/Cargo.lock index 2518956d..0ebe7c9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -653,9 +653,9 @@ checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" [[package]] name = "fastembed" -version = "6.1.0" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf2876a78b0fa3a9095baf8bbec83126b3c5b7eab8fc4e1e7ad9e68b14ed5c8a" +checksum = "3850d724d559da51a4b88f68b0ba111a2627c32279bec6b3c256f073c71a3195" dependencies = [ "hf-hub", "ndarray", @@ -1221,9 +1221,9 @@ checksum = "34b357333733e8260735ba5894eb928c02ecc69c78715f01a8019e7fa7f2db4c" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libloading" @@ -2181,9 +2181,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.60.2", @@ -2670,7 +2670,7 @@ name = "unity-cli" version = "0.18.1" dependencies = [ "anyhow", - "base64 0.22.1", + "base64 0.23.1", "bincode", "clap", "dirs 7.0.0", diff --git a/Cargo.toml b/Cargo.toml index f0ff0b7a..1fc73bf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ keywords = ["unity", "cli", "automation", "editor"] categories = ["command-line-utilities", "development-tools"] include = [ "/src/**", + "/tests/fixtures/reference-embedding/*.bin", "/build.rs", "/.claude-plugin/plugins/unity-cli/skills/**", "/Cargo.toml", @@ -26,7 +27,7 @@ path = "src/main.rs" [dependencies] anyhow = "1.0" -base64 = "0.22" +base64 = "0.23" clap = { version = "4.6", features = ["derive"] } dirs = "7.0" serde = { version = "1.0", features = ["derive"] } @@ -51,10 +52,10 @@ bincode = "=1.3.3" # ONNX Runtime ships no prebuilt binaries for Intel macOS, so that target loads # libonnxruntime dynamically at runtime (ORT_DYLIB_PATH / Homebrew onnxruntime). [target.'cfg(not(all(target_os = "macos", target_arch = "x86_64")))'.dependencies] -fastembed = { version = "6", default-features = false, features = ["hf-hub-rustls-tls", "ort-download-binaries"] } +fastembed = { version = "7", default-features = false, features = ["hf-hub-rustls-tls", "ort-download-binaries"] } [target.'cfg(all(target_os = "macos", target_arch = "x86_64"))'.dependencies] -fastembed = { version = "6", default-features = false, features = ["hf-hub-rustls-tls", "ort-load-dynamic"] } +fastembed = { version = "7", default-features = false, features = ["hf-hub-rustls-tls", "ort-load-dynamic"] } [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/reference/embed.rs b/src/reference/embed.rs index ea406b7a..b92fc99d 100644 --- a/src/reference/embed.rs +++ b/src/reference/embed.rs @@ -60,7 +60,7 @@ impl FastEmbedder { std::env::set_var("ORT_DYLIB_PATH", dylib); } let model_id = format!("{model:?}"); - let options = fastembed::InitOptions::new(model); + let options = fastembed::TextInitOptions::new(model); let inner = fastembed::TextEmbedding::try_new(options) .map_err(|e| anyhow!("failed to initialize embedding model: {e}"))?; Ok(Self { @@ -402,6 +402,41 @@ mod tests { assert_eq!(loaded, index); } + #[test] + fn embedding_reads_fastembed6_bincode1_fixture() { + // Written by save_embedding_index with fastembed 6.1.0 and bincode 1.3.3 + // before the fastembed 7 migration. Do not regenerate with the new writer. + let bytes = + include_bytes!("../../tests/fixtures/reference-embedding/fastembed6-bincode1.bin"); + let tmp = TempDir::new().unwrap(); + let path = tmp.path().join(EMBEDDING_INDEX_REL_PATH); + fs::create_dir_all(path.parent().unwrap()).unwrap(); + fs::write(&path, bytes).unwrap(); + + let index = load_embedding_index(&path).unwrap(); + let model = fastembed::EmbeddingModel::BGESmallENV15; + let model_info = fastembed::TextEmbedding::get_model_info(&model).unwrap(); + assert_eq!(index.version, EMBEDDING_INDEX_VERSION); + assert_eq!(index.model_id, format!("{model:?}")); + assert_eq!(index.dim, model_info.dim); + assert_eq!(index.items.len(), 1); + let item = &index.items[0]; + assert_eq!(item.symbol, "UnityEngine.Animator"); + assert_eq!(item.kind, "class"); + assert_eq!(item.path, "Runtime/Export/Animation/Animator.bindings.cs"); + assert_eq!(item.line, 42); + let mut query = vec![0.0; model_info.dim]; + query[0] = 1.0; + assert_eq!(item.vector, query); + let hits = search(&index, &query, 1); + assert_eq!(hits[0].0, *item); + assert!((hits[0].1 - 1.0).abs() < f32::EPSILON); + + // Updating an existing index must also retain its on-disk format. + save_embedding_index(&path, &index).unwrap(); + assert_eq!(fs::read(&path).unwrap(), bytes); + } + #[test] fn search_ranks_by_cosine_similarity() { let index = EmbeddingIndex { diff --git a/tests/fixtures/reference-embedding/fastembed6-bincode1.bin b/tests/fixtures/reference-embedding/fastembed6-bincode1.bin new file mode 100644 index 0000000000000000000000000000000000000000..072f12db1dace6bd2b38a75225a2d58937a60340 GIT binary patch literal 1683 zcmZQ%U|`?{Vi0h0cMZ->%*k=}3o|rrV1x)lDFzV;mmxGSv!v2BFFi9aRnIXmGdHm$ zzlaqomz Date: Fri, 9 Oct 2026 00:22:02 -0400 Subject: [PATCH 13/73] docs(skills): document per-tool GameObject parameter names The key that names the target object differs by tool (path, gameObjectPath, name, gameObjectName, rootPath), and a wrong key fails schema validation before the call reaches Unity. Add a short table to unity-gameobject-edit and unity-scene-inspect, checked against the tool catalog, plus a pointer to `tool schema`. Co-Authored-By: Claude Opus 5.5 --- .../unity-cli/skills/unity-gameobject-edit/SKILL.md | 13 +++++++++++++ .../unity-cli/skills/unity-scene-inspect/SKILL.md | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-gameobject-edit/SKILL.md b/.claude-plugin/plugins/unity-cli/skills/unity-gameobject-edit/SKILL.md index 51e2c985..1a7c4889 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-gameobject-edit/SKILL.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-gameobject-edit/SKILL.md @@ -57,6 +57,19 @@ Modify existing GameObjects and their components in an already-prepared scene. T 4. Reserve `delete_gameobject` and `remove_component` for confirmed scopes. 5. Save the scene after destructive or bulk updates so reloads do not lose work. +## Target Parameter Names + +The key that names the target object differs by tool. A wrong key fails locally with `INVALID_ARGUMENT` (`$. is required` or `$. is not allowed`) before reaching Unity. + +| Key | Tools | +| ---------------- | ------------------------------------------------------------------------------------------------- | +| `path` | `modify_gameobject` (its `name` renames), `delete_gameobject` (`paths` for several) | +| `gameObjectPath` | `add_component`, `modify_component`, `set_component_field`, `remove_component`, `list_components` | +| `name` | `find_gameobject`, `create_gameobject` (parent via `parentPath`) | +| `gameObjectName` | read-only queries such as `get_component_values`; see `unity-scene-inspect` | + +When unsure, read the schema: `unity-cli tool schema --output json`. + ```bash unity-cli raw modify_gameobject --json '{"path":"/Player","name":"Hero","active":true}' unity-cli raw add_component --json '{"gameObjectPath":"/Player","componentType":"Rigidbody"}' diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-scene-inspect/SKILL.md b/.claude-plugin/plugins/unity-cli/skills/unity-scene-inspect/SKILL.md index 14de6dc5..688a39c2 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-scene-inspect/SKILL.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-scene-inspect/SKILL.md @@ -44,6 +44,19 @@ Inspect scene hierarchy, find objects, and read component data without mutating 3. Inspect targets with `get_gameobject_details`, `get_component_values`, or animator queries. 4. Use `analyze_scene_contents` with `includeInactive` for broad audits. +## Target Parameter Names + +Read-only queries name their target differently from the edit tools. A wrong key fails locally with `INVALID_ARGUMENT` before reaching Unity. + +| Key | Tools | +| -------------------------- | -------------------------------------------------------------------------------------------------- | +| `gameObjectName` | `get_component_values`, `get_object_references`, `get_animator_state`, `get_animator_runtime_info` | +| `gameObjectName` or `path` | `get_gameobject_details` | +| `name` | `find_gameobject` | +| `rootPath` | `get_hierarchy` | + +`gameObjectName` takes a name or a hierarchy path such as `/Root/Child`. Edit tools use `path` or `gameObjectPath` instead; see `unity-gameobject-edit`. When unsure: `unity-cli tool schema --output json`. + ```bash unity-cli raw get_hierarchy --json '{"nameOnly":true}' unity-cli raw find_gameobject --json '{"name":"Player"}' From a647572470700c001be6a082cd7bd8d785808c64 Mon Sep 17 00:00:00 2001 From: arghhhhh Date: Fri, 9 Oct 2026 00:36:42 -0400 Subject: [PATCH 14/73] feat(scripts): install a source build as the managed binary Contributors testing a change the way users run unity-cli need their build where unityd and agent skills pick it up. A cargo install puts it in ~/.cargo/bin, which shadows the managed binary (warn_cargo_conflict) while unityd keeps running the managed one. scripts/install-from-source.sh (macOS/Linux) and .ps1 (Windows) build the checkout and install it into ~/.unity/tools/unity-cli// like install.sh / install.ps1: stop unityd, replace the binary (moving a locked exe aside on Windows), write VERSION, link or add to PATH, then refresh installed skills or install them for --skills . They warn when UNITY_CLI_NO_AUTO_UPDATE is unset, since the next release's self-update would replace the build. CONTRIBUTING documents them (EN/JA). Co-Authored-By: Claude Opus 5.5 --- CONTRIBUTING.md | 33 ++++++++++ scripts/install-from-source.ps1 | 105 ++++++++++++++++++++++++++++++++ scripts/install-from-source.sh | 93 ++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+) create mode 100644 scripts/install-from-source.ps1 create mode 100755 scripts/install-from-source.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3921fd35..c7b8f1d3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,22 @@ docker build -t unity-cli-dev . docker run --rm unity-cli-dev ``` +### Running Your Build + +To test a change the way users run unity-cli (through `unityd` and your agent's +skills), install your checkout as the managed binary, where `scripts/install.sh` +and `scripts/install.ps1` put a release: + +```bash +./scripts/install-from-source.sh --skills claude-code # macOS / Linux +./scripts/install-from-source.ps1 -Skills claude-code # Windows +``` + +It builds a release binary, stops `unityd`, installs into +`~/.unity/tools/unity-cli//` and refreshes installed skills to the build. +Set `UNITY_CLI_NO_AUTO_UPDATE=1` while you run a source build, or the next +release's self-update replaces it. Run the release installer again to go back. + ## Validation Commands ```bash @@ -178,6 +194,23 @@ docker build -t unity-cli-dev . docker run --rm unity-cli-dev ``` +### 自分のビルドを使う + +ユーザーと同じ経路(`unityd` とエージェントの skill)で変更を確認するには、 +チェックアウトを managed バイナリとしてインストールします。配置先は +`scripts/install.sh` / `scripts/install.ps1` がリリースを置く場所と同じです。 + +```bash +./scripts/install-from-source.sh --skills claude-code # macOS / Linux +./scripts/install-from-source.ps1 -Skills claude-code # Windows +``` + +リリースビルドを作成し、`unityd` を停止して `~/.unity/tools/unity-cli//` +にインストールし、インストール済みの skill をビルドに合わせて更新します。 +ソースビルドを使う間は `UNITY_CLI_NO_AUTO_UPDATE=1` を設定してください。 +設定しないと次のリリースの自動更新で置き換わります。戻すときはリリース用 +インストーラーを再実行します。 + ## 検証コマンド ```bash diff --git a/scripts/install-from-source.ps1 b/scripts/install-from-source.ps1 new file mode 100644 index 00000000..90d9dd72 --- /dev/null +++ b/scripts/install-from-source.ps1 @@ -0,0 +1,105 @@ +# Build this checkout and install it as the managed unity-cli binary, the same +# place scripts/install.ps1 puts a release, so unityd and your agents run your +# build. For contributors testing changes the way users run them. +# Usage: ./scripts/install-from-source.ps1 [-DebugBuild] [-SkipBuild] [-Skills ] +# +# Environment (same as install.ps1): +# UNITY_CLI_TOOLS_ROOT managed tools root (default: ~\.unity\tools) +# UNITY_CLI_SKIP_PATH_UPDATE set to 1 to leave the user PATH unchanged +# +# Set UNITY_CLI_NO_AUTO_UPDATE=1 (user scope) while you run a source build: +# otherwise the next release's self-update replaces it. +param( + [switch]$DebugBuild, + [switch]$SkipBuild, + [ValidateSet('claude-code', 'cursor', 'windsurf', 'vscode')][string]$Skills +) +$ErrorActionPreference = 'Stop' + +function Fail([string]$Message) { Write-Error "error: $Message"; exit 1 } + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..') +$profileDir = if ($DebugBuild) { 'debug' } else { 'release' } +$targetDir = if ($env:CARGO_TARGET_DIR) { $env:CARGO_TARGET_DIR } else { Join-Path $repoRoot 'target' } +$built = Join-Path $targetDir "$profileDir\unity-cli.exe" + +# 1. Build +if (-not $SkipBuild) { + if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) { Fail 'cargo not found (install Rust from https://rustup.rs)' } + $cargoArgs = @('build', '--bin', 'unity-cli', '--locked') + if (-not $DebugBuild) { $cargoArgs += '--release' } + Push-Location $repoRoot + try { & cargo @cargoArgs; if ($LASTEXITCODE -ne 0) { Fail 'cargo build failed' } } + finally { Pop-Location } +} +if (-not (Test-Path $built)) { Fail "no build at $built (drop -SkipBuild)" } + +$versionLine = (& $built --version | Out-String).Trim() +if ($versionLine -notmatch '^unity-cli (\S+)$') { Fail "unexpected version output: $versionLine" } +$version = $Matches[1] +$commit = (git -C $repoRoot rev-parse --short HEAD 2>$null) + +# 2. Stop the daemon so the installed exe is not locked +$toolsRoot = if ($env:UNITY_CLI_TOOLS_ROOT) { $env:UNITY_CLI_TOOLS_ROOT.Trim() } ` + else { Join-Path $HOME '.unity\tools' } +$destDir = Join-Path $toolsRoot 'unity-cli\win-x64' +$binary = Join-Path $destDir 'unity-cli.exe' +New-Item -ItemType Directory -Force -Path $destDir | Out-Null +if (Test-Path $binary) { + $env:UNITY_CLI_NO_AUTO_UPDATE = '1' + & $binary unityd stop *> $null + # Anything else still running the old exe keeps it locked; Windows allows + # renaming a running exe, so move it aside instead of failing. + Get-ChildItem -Path $destDir -Filter 'unity-cli.exe.old-*' -ErrorAction SilentlyContinue | + Remove-Item -Force -ErrorAction SilentlyContinue + $locked = $true + foreach ($i in 1..10) { + try { [IO.File]::Open($binary, 'Open', 'ReadWrite', 'None').Close(); $locked = $false; break } + catch { Start-Sleep -Milliseconds 500 } + } + if ($locked) { + $aside = "$binary.old-$PID" + Move-Item -Force -Path $binary -Destination $aside + Write-Host "unity-cli.exe is in use; moved it to $aside" + } +} + +# 3. Install and write VERSION. VERSION holds the build's own version, so +# self-update only replaces the build once a newer release exists. +$tmp = Join-Path $destDir 'unity-cli.download' +Copy-Item -Force -Path $built -Destination $tmp +Move-Item -Force -Path $tmp -Destination $binary +Set-Content -Path (Join-Path $destDir 'VERSION') -Value $version -NoNewline:$false -Encoding ascii +Write-Host "Installed unity-cli $version ($profileDir build of $commit) -> $binary" + +# 4. Add the managed directory to the user PATH (same as install.ps1) +if ($env:UNITY_CLI_SKIP_PATH_UPDATE -ne '1') { + $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') + $entries = @($userPath -split ';' | Where-Object { $_ }) + if ($entries -notcontains $destDir) { + [Environment]::SetEnvironmentVariable('Path', (($entries + $destDir) -join ';'), 'User') + Write-Host "Added $destDir to the user PATH. Restart your terminal to pick it up." + } + if (($env:Path -split ';') -notcontains $destDir) { + $env:Path = "$env:Path;$destDir" + } +} + +# 5. Skills: refresh installed copies to this build, or install for a client +if ($Skills) { + & $binary skills install $Skills --force + if ($LASTEXITCODE -ne 0) { Fail "skills install $Skills failed" } +} else { + & $binary skills refresh *> $null + if ($LASTEXITCODE -eq 0) { Write-Host 'Refreshed installed skills to this build.' } +} + +$cargoBin = Join-Path $HOME '.cargo\bin\unity-cli.exe' +if (Test-Path $cargoBin) { + Write-Warning "$cargoBin exists and may shadow the managed binary. Consider running: cargo uninstall unity-cli" +} +$noAuto = [Environment]::GetEnvironmentVariable('UNITY_CLI_NO_AUTO_UPDATE', 'User') +if ($noAuto -ne '1' -and $env:UNITY_CLI_NO_AUTO_UPDATE -ne '1') { + Write-Warning ("Self-update will replace this build when a newer release ships. To keep it, run: " + + "[Environment]::SetEnvironmentVariable('UNITY_CLI_NO_AUTO_UPDATE','1','User')") +} diff --git a/scripts/install-from-source.sh b/scripts/install-from-source.sh new file mode 100755 index 00000000..6b499d3a --- /dev/null +++ b/scripts/install-from-source.sh @@ -0,0 +1,93 @@ +#!/bin/sh +# Build this checkout and install it as the managed unity-cli binary, the same +# place scripts/install.sh puts a release, so unityd and your agents run your +# build. For contributors testing changes the way users run them. +# Usage: ./scripts/install-from-source.sh [--debug] [--skip-build] [--skills ] +# +# Environment: +# UNITY_CLI_TOOLS_ROOT managed tools root (default: ~/.unity/tools) +# +# Export UNITY_CLI_NO_AUTO_UPDATE=1 (in your shell profile) while you run a +# source build: otherwise the next release's self-update replaces it. +set -e + +die() { echo "error: $*" >&2; exit 1; } + +PROFILE=release +SKIP_BUILD=0 +SKILLS="" +while [ $# -gt 0 ]; do + case "$1" in + --debug) PROFILE=debug; shift ;; + --skip-build) SKIP_BUILD=1; shift ;; + --skills) SKILLS="${2:-}"; [ -n "$SKILLS" ] || die "--skills needs a client"; shift 2 ;; + -h|--help) sed -n '2,11p' "$0"; exit 0 ;; + *) die "unknown option: $1" ;; + esac +done + +REPO_ROOT=$(cd "$(dirname "$0")/.." && pwd) +BUILT="${CARGO_TARGET_DIR:-${REPO_ROOT}/target}/${PROFILE}/unity-cli" + +case "$(uname -s)/$(uname -m)" in + Darwin/arm64|Darwin/aarch64) RID=osx-arm64 ;; + Darwin/x86_64) RID=osx-x64 ;; + Linux/aarch64|Linux/arm64) RID=linux-arm64 ;; + Linux/x86_64) RID=linux-x64 ;; + *) die "unsupported platform $(uname -s)/$(uname -m) (on Windows use scripts/install-from-source.ps1)" ;; +esac + +# 1. Build +if [ "$SKIP_BUILD" = 0 ]; then + command -v cargo >/dev/null 2>&1 || die "cargo not found (install Rust from https://rustup.rs)" + if [ "$PROFILE" = release ]; then + (cd "$REPO_ROOT" && cargo build --bin unity-cli --locked --release) + else + (cd "$REPO_ROOT" && cargo build --bin unity-cli --locked) + fi +fi +[ -x "$BUILT" ] || die "no build at ${BUILT} (drop --skip-build)" + +VERSION=$("$BUILT" --version | awk '{print $2}') +[ -n "$VERSION" ] || die "could not read the build's version" +COMMIT=$(git -C "$REPO_ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown) + +# 2. Stop the daemon running the old binary +DEST_DIR="${UNITY_CLI_TOOLS_ROOT:-${HOME}/.unity/tools}/unity-cli/${RID}" +BINARY="${DEST_DIR}/unity-cli" +mkdir -p "$DEST_DIR" +if [ -x "$BINARY" ]; then + UNITY_CLI_NO_AUTO_UPDATE=1 "$BINARY" unityd stop >/dev/null 2>&1 || true +fi + +# 3. Install and write VERSION. VERSION holds the build's own version, so +# self-update only replaces the build once a newer release exists. +TMP="${DEST_DIR}/unity-cli.download" +cp "$BUILT" "$TMP" +chmod 755 "$TMP" +mv -f "$TMP" "$BINARY" +printf '%s\n' "$VERSION" > "${DEST_DIR}/VERSION" + +# 4. Symlink (same as install.sh) +LINK_DIR="${HOME}/.local/bin" +mkdir -p "$LINK_DIR" +ln -sf "$BINARY" "${LINK_DIR}/unity-cli" +echo "Installed unity-cli ${VERSION} (${PROFILE} build of ${COMMIT}) -> ${LINK_DIR}/unity-cli" + +# 5. Skills: refresh installed copies to this build, or install for a client +if [ -n "$SKILLS" ]; then + "$BINARY" skills install "$SKILLS" --force +elif "$BINARY" skills refresh >/dev/null 2>&1; then + echo "Refreshed installed skills to this build." +fi + +if [ -f "${HOME}/.cargo/bin/unity-cli" ]; then + echo "" + echo "WARNING: ${HOME}/.cargo/bin/unity-cli exists and may shadow the managed binary." + echo " Consider running: cargo uninstall unity-cli" +fi +if [ "${UNITY_CLI_NO_AUTO_UPDATE:-}" != 1 ]; then + echo "" + echo "WARNING: self-update will replace this build when a newer release ships." + echo " To keep it, add to your shell profile: export UNITY_CLI_NO_AUTO_UPDATE=1" +fi From 9d12d9e2e0a5a41466ee0af3ac6a98e63377de17 Mon Sep 17 00:00:00 2001 From: arghhhhh Date: Fri, 9 Oct 2026 01:10:16 -0400 Subject: [PATCH 15/73] fix(update): keep the installed CLI on daemon start when auto-update is off UNITY_CLI_NO_AUTO_UPDATE=1 stopped maybe_self_update, but `unityd start` and lspd go through ensure_latest_cli_for_daemon, which fetched the latest release and replaced the managed binary whenever VERSION differed. A user who had opted out (a pinned release, a source build) got upgraded by starting the daemon. ensure_latest_for now returns the installed CLI on the daemon-start path when the opt-out is set. A missing binary is still installed, explicit installs (`force_download`, `allow_stale_existing = false`) are unchanged, and both callers read the flag through auto_update_disabled(). Co-Authored-By: Claude Opus 5.5 --- src/core/managed_binaries.rs | 61 ++++++++++++++++++++++++++++++++++++ src/core/self_update.rs | 6 ++-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/core/managed_binaries.rs b/src/core/managed_binaries.rs index 8a059614..31838fec 100644 --- a/src/core/managed_binaries.rs +++ b/src/core/managed_binaries.rs @@ -306,6 +306,12 @@ fn install_latest_for( ensure_latest_for(managed_binary, force_download, false) } +/// `UNITY_CLI_NO_AUTO_UPDATE=1`: never replace an installed unity-cli with a +/// newer release unless the user asks for it. +pub(crate) fn auto_update_disabled() -> bool { + std::env::var("UNITY_CLI_NO_AUTO_UPDATE").ok().as_deref() == Some("1") +} + fn ensure_latest_for( managed_binary: ManagedBinary, force_download: bool, @@ -322,6 +328,18 @@ fn ensure_latest_for( )); } + // Daemon startup (`unityd start`, `lspd`) honours the same opt-out as + // `maybe_self_update` and keeps the installed CLI. A missing binary is + // still installed, since the daemon needs one to run. + if allow_stale_existing + && !force_download + && status.binary_exists + && managed_binary == ManagedBinary::UnityCli + && auto_update_disabled() + { + return Ok(status); + } + match fetch_latest_release(managed_binary) { Ok(latest) => { status.update_available = @@ -1001,6 +1019,49 @@ mod tests { assert!(status.latest.is_none()); } + #[test] + fn daemon_startup_keeps_installed_cli_when_auto_update_disabled() { + let _guard = env_lock() + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + let dir = tempdir().expect("tempdir should succeed"); + let _env = EnvVarGuard::set( + "UNITY_CLI_TOOLS_ROOT", + dir.path() + .to_str() + .expect("tempdir path should be valid UTF-8"), + ); + // Exercise the real code path, not the test-only skip. + let _skip = EnvVarGuard::set("UNITY_CLI_TEST_SKIP_MANAGED_UPDATE", "0"); + let _opt_out = EnvVarGuard::set("UNITY_CLI_NO_AUTO_UPDATE", "1"); + + let binary = + binary_path_for(ManagedBinary::UnityCli).expect("unity-cli binary path should resolve"); + if let Some(parent) = binary.parent() { + fs::create_dir_all(parent).expect("binary parent directory should be created"); + } + fs::write(&binary, b"source-build").expect("binary fixture should be writable"); + // A VERSION that can never match a release, so an update would be due. + write_local_version_for(ManagedBinary::UnityCli, "0.0.0-local") + .expect("VERSION fixture should be writable"); + + let status = + ensure_latest_cli_for_daemon().expect("opt-out should keep the installed binary"); + assert_eq!(status.binary_path, binary); + assert!(status.binary_exists); + // No release lookup at all: neither a result nor a lookup error. + assert!(status.latest.is_none()); + assert!(status.latest_error.is_none()); + assert_eq!( + fs::read(&binary).expect("binary should be readable"), + b"source-build" + ); + assert_eq!( + read_local_version_for(ManagedBinary::UnityCli).as_deref(), + Some("0.0.0-local") + ); + } + #[test] fn sha256_file_matches_known_hash() { let dir = tempdir().expect("tempdir should succeed"); diff --git a/src/core/self_update.rs b/src/core/self_update.rs index 2397cdb8..1f59b2a7 100644 --- a/src/core/self_update.rs +++ b/src/core/self_update.rs @@ -4,8 +4,8 @@ use std::thread::{self, JoinHandle}; use std::time::{Duration, SystemTime}; use crate::core::managed_binaries::{ - binary_path_for, detect_rid, download_latest_binary, fetch_latest_release, install_dir_for, - read_local_version_for, ManagedBinary, + auto_update_disabled, binary_path_for, detect_rid, download_latest_binary, + fetch_latest_release, install_dir_for, read_local_version_for, ManagedBinary, }; const THROTTLE_SECS: u64 = 4 * 60 * 60; // 4 hours @@ -14,7 +14,7 @@ const THROTTLE_SECS: u64 = 4 * 60 * 60; // 4 hours /// binary if a newer version is available. Returns `None` when the check is /// skipped (opt-out env, throttle, or error resolving paths). pub fn maybe_self_update() -> Option> { - if std::env::var("UNITY_CLI_NO_AUTO_UPDATE").ok().as_deref() == Some("1") { + if auto_update_disabled() { tracing::debug!("self-update skipped: UNITY_CLI_NO_AUTO_UPDATE=1"); return None; } From 40908a048a502afba3fd3e7b02373480782aa1b3 Mon Sep 17 00:00:00 2001 From: arghhhhh Date: Fri, 9 Oct 2026 01:17:55 -0400 Subject: [PATCH 16/73] fix(scripts): install-from-source warning, broken installs, --no-skills - The Windows script set UNITY_CLI_NO_AUTO_UPDATE for its own unityd-stop call and then read it back, so the auto-update warning never showed on a reinstall. Read the opt-out before changing it. - A corrupt or partial install no longer aborts the Windows run at the unityd-stop step. - --no-skills / -NoSkills skip the skills step, for tests and binary-only changes (unity-cli resolves the skills home through the OS on Windows, so a temporary HOME can't isolate it). Co-Authored-By: Claude Opus 5.5 --- scripts/install-from-source.ps1 | 19 +++++++++++++------ scripts/install-from-source.sh | 8 ++++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/scripts/install-from-source.ps1 b/scripts/install-from-source.ps1 index 90d9dd72..e9f08cd7 100644 --- a/scripts/install-from-source.ps1 +++ b/scripts/install-from-source.ps1 @@ -1,7 +1,7 @@ # Build this checkout and install it as the managed unity-cli binary, the same # place scripts/install.ps1 puts a release, so unityd and your agents run your # build. For contributors testing changes the way users run them. -# Usage: ./scripts/install-from-source.ps1 [-DebugBuild] [-SkipBuild] [-Skills ] +# Usage: ./scripts/install-from-source.ps1 [-DebugBuild] [-SkipBuild] [-Skills | -NoSkills] # # Environment (same as install.ps1): # UNITY_CLI_TOOLS_ROOT managed tools root (default: ~\.unity\tools) @@ -12,12 +12,17 @@ param( [switch]$DebugBuild, [switch]$SkipBuild, - [ValidateSet('claude-code', 'cursor', 'windsurf', 'vscode')][string]$Skills + [ValidateSet('claude-code', 'cursor', 'windsurf', 'vscode')][string]$Skills, + [switch]$NoSkills ) $ErrorActionPreference = 'Stop' function Fail([string]$Message) { Write-Error "error: $Message"; exit 1 } +# Read before step 2 sets it for the daemon-stop call. +$optedOut = ($env:UNITY_CLI_NO_AUTO_UPDATE -eq '1') -or + ([Environment]::GetEnvironmentVariable('UNITY_CLI_NO_AUTO_UPDATE', 'User') -eq '1') + $repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..') $profileDir = if ($DebugBuild) { 'debug' } else { 'release' } $targetDir = if ($env:CARGO_TARGET_DIR) { $env:CARGO_TARGET_DIR } else { Join-Path $repoRoot 'target' } @@ -47,7 +52,8 @@ $binary = Join-Path $destDir 'unity-cli.exe' New-Item -ItemType Directory -Force -Path $destDir | Out-Null if (Test-Path $binary) { $env:UNITY_CLI_NO_AUTO_UPDATE = '1' - & $binary unityd stop *> $null + # A broken or partial install must not block reinstalling. + try { & $binary unityd stop *> $null } catch { } # Anything else still running the old exe keeps it locked; Windows allows # renaming a running exe, so move it aside instead of failing. Get-ChildItem -Path $destDir -Filter 'unity-cli.exe.old-*' -ErrorAction SilentlyContinue | @@ -86,7 +92,9 @@ if ($env:UNITY_CLI_SKIP_PATH_UPDATE -ne '1') { } # 5. Skills: refresh installed copies to this build, or install for a client -if ($Skills) { +if ($NoSkills) { + # Leave installed skills alone (tests, or a binary-only change). +} elseif ($Skills) { & $binary skills install $Skills --force if ($LASTEXITCODE -ne 0) { Fail "skills install $Skills failed" } } else { @@ -98,8 +106,7 @@ $cargoBin = Join-Path $HOME '.cargo\bin\unity-cli.exe' if (Test-Path $cargoBin) { Write-Warning "$cargoBin exists and may shadow the managed binary. Consider running: cargo uninstall unity-cli" } -$noAuto = [Environment]::GetEnvironmentVariable('UNITY_CLI_NO_AUTO_UPDATE', 'User') -if ($noAuto -ne '1' -and $env:UNITY_CLI_NO_AUTO_UPDATE -ne '1') { +if (-not $optedOut) { Write-Warning ("Self-update will replace this build when a newer release ships. To keep it, run: " + "[Environment]::SetEnvironmentVariable('UNITY_CLI_NO_AUTO_UPDATE','1','User')") } diff --git a/scripts/install-from-source.sh b/scripts/install-from-source.sh index 6b499d3a..34902b72 100755 --- a/scripts/install-from-source.sh +++ b/scripts/install-from-source.sh @@ -2,7 +2,7 @@ # Build this checkout and install it as the managed unity-cli binary, the same # place scripts/install.sh puts a release, so unityd and your agents run your # build. For contributors testing changes the way users run them. -# Usage: ./scripts/install-from-source.sh [--debug] [--skip-build] [--skills ] +# Usage: ./scripts/install-from-source.sh [--debug] [--skip-build] [--skills | --no-skills] # # Environment: # UNITY_CLI_TOOLS_ROOT managed tools root (default: ~/.unity/tools) @@ -16,10 +16,12 @@ die() { echo "error: $*" >&2; exit 1; } PROFILE=release SKIP_BUILD=0 SKILLS="" +NO_SKILLS=0 while [ $# -gt 0 ]; do case "$1" in --debug) PROFILE=debug; shift ;; --skip-build) SKIP_BUILD=1; shift ;; + --no-skills) NO_SKILLS=1; shift ;; --skills) SKILLS="${2:-}"; [ -n "$SKILLS" ] || die "--skills needs a client"; shift 2 ;; -h|--help) sed -n '2,11p' "$0"; exit 0 ;; *) die "unknown option: $1" ;; @@ -75,7 +77,9 @@ ln -sf "$BINARY" "${LINK_DIR}/unity-cli" echo "Installed unity-cli ${VERSION} (${PROFILE} build of ${COMMIT}) -> ${LINK_DIR}/unity-cli" # 5. Skills: refresh installed copies to this build, or install for a client -if [ -n "$SKILLS" ]; then +if [ "$NO_SKILLS" = 1 ]; then + : # leave installed skills alone (tests, or a binary-only change) +elif [ -n "$SKILLS" ]; then "$BINARY" skills install "$SKILLS" --force elif "$BINARY" skills refresh >/dev/null 2>&1; then echo "Refreshed installed skills to this build." From 826d7d66a2fb6526bc0fa303ead00850e8edd39a Mon Sep 17 00:00:00 2001 From: arghhhhh Date: Fri, 9 Oct 2026 01:17:55 -0400 Subject: [PATCH 17/73] test(scripts): cover install-from-source on Windows and Linux CI tests/scripts/install-from-source-ps1-test.ps1 and -sh-test.sh install the job's debug build with --skip-build into a temporary UNITY_CLI_TOOLS_ROOT (and HOME on Unix) and check: fresh install and VERSION, the ~/.local/bin symlink, PATH left alone with UNITY_CLI_SKIP_PATH_UPDATE=1, reinstall over a stale binary, a held-open exe moved aside and cleaned up on the next run (Windows), a missing build failing without touching the install, and the UNITY_CLI_NO_AUTO_UPDATE warning. Run in windows-test and linux-platform-checks after their existing builds. Refs #480 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test.yml | 8 ++ .../scripts/install-from-source-ps1-test.ps1 | 110 ++++++++++++++++++ tests/scripts/install-from-source-sh-test.sh | 69 +++++++++++ 3 files changed, 187 insertions(+) create mode 100644 tests/scripts/install-from-source-ps1-test.ps1 create mode 100755 tests/scripts/install-from-source-sh-test.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4117f91c..139b8957 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -135,6 +135,11 @@ jobs: shell: pwsh run: ./tests/scripts/install-ps1-binary-test.ps1 -Binary target/debug/unity-cli.exe + - name: Install the built binary with install-from-source.ps1 + if: ${{ !cancelled() }} + shell: pwsh + run: ./tests/scripts/install-from-source-ps1-test.ps1 -Binary target/debug/unity-cli.exe + linux-platform-checks: name: Linux Platform Checks runs-on: ubuntu-latest @@ -168,6 +173,9 @@ jobs: xvfb-run -a -s "-screen 0 1280x720x24" python3 tests/scripts/platform-checks.py --unity-cli target/debug/unity-cli + - name: Install the built binary with install-from-source.sh + run: sh tests/scripts/install-from-source-sh-test.sh target/debug/unity-cli + - name: Check the grim OS screenshot fallback under headless sway # A wlroots compositor on the headless backend with the software # renderer; WAYLAND_DISPLAY switches the check to grim (#465). diff --git a/tests/scripts/install-from-source-ps1-test.ps1 b/tests/scripts/install-from-source-ps1-test.ps1 new file mode 100644 index 00000000..c1cb24c7 --- /dev/null +++ b/tests/scripts/install-from-source-ps1-test.ps1 @@ -0,0 +1,110 @@ +# Installs a locally built unity-cli.exe through scripts/install-from-source.ps1 +# (-SkipBuild) into a temporary UNITY_CLI_TOOLS_ROOT and checks the managed +# layout: fresh install, reinstall, a locked exe, a missing build, and the +# auto-update warning. +param( + [Parameter(Mandatory = $true)][string]$Binary +) +$ErrorActionPreference = 'Stop' + +function Assert([bool]$Condition, [string]$Message) { + if (-not $Condition) { throw "FAIL: $Message" } +} + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..') +$installer = Join-Path $repoRoot 'scripts\install-from-source.ps1' +$built = (Resolve-Path $Binary).Path +$shell = (Get-Process -Id $PID).Path + +$builtVersion = (& $built --version | Out-String).Trim() +Assert ($builtVersion -match '^unity-cli (\S+)$') "unexpected version output: $builtVersion" +$version = $Matches[1] +$builtHash = (Get-FileHash -Algorithm SHA256 -Path $built).Hash + +$work = Join-Path ([System.IO.Path]::GetTempPath()) ("unity-cli-install-from-source-" + [guid]::NewGuid()) +$targetDir = Join-Path $work 'target' +$emptyTarget = Join-Path $work 'empty-target' +$toolsRoot = Join-Path $work 'tools' +New-Item -ItemType Directory -Force -Path (Join-Path $targetDir 'debug'), $emptyTarget | Out-Null +Copy-Item -Path $built -Destination (Join-Path $targetDir 'debug\unity-cli.exe') + +$destDir = Join-Path $toolsRoot 'unity-cli\win-x64' +$installed = Join-Path $destDir 'unity-cli.exe' +$saved = @{} +foreach ($name in 'CARGO_TARGET_DIR', 'UNITY_CLI_TOOLS_ROOT', 'UNITY_CLI_SKIP_PATH_UPDATE', 'UNITY_CLI_NO_AUTO_UPDATE') { + $saved[$name] = [Environment]::GetEnvironmentVariable($name, 'Process') +} +$originalUserPath = [Environment]::GetEnvironmentVariable('Path', 'User') +$userOptOut = [Environment]::GetEnvironmentVariable('UNITY_CLI_NO_AUTO_UPDATE', 'User') + +# Runs the installer in a child shell so its `exit 1` can't end this test. +# Continue: Windows PowerShell turns the child's stderr into terminating errors. +function Invoke-Installer { + $ErrorActionPreference = 'Continue' + $output = & $shell -NoProfile -ExecutionPolicy Bypass -File $installer -DebugBuild -SkipBuild -NoSkills 2>&1 | Out-String + return [pscustomobject]@{ Code = $LASTEXITCODE; Output = $output } +} + +try { + $env:CARGO_TARGET_DIR = $targetDir + $env:UNITY_CLI_TOOLS_ROOT = $toolsRoot + $env:UNITY_CLI_SKIP_PATH_UPDATE = '1' + $env:UNITY_CLI_NO_AUTO_UPDATE = '1' + + # Fresh install + $run = Invoke-Installer + Assert ($run.Code -eq 0) "fresh install exited with $($run.Code): $($run.Output)" + Assert (Test-Path $installed) 'binary must be installed into the managed layout' + Assert ((Get-FileHash -Algorithm SHA256 -Path $installed).Hash -eq $builtHash) 'installed binary must match the build' + Assert ((Get-Content -Raw (Join-Path $destDir 'VERSION')).Trim() -eq $version) 'VERSION must hold the build version' + Assert ((& $installed --version | Out-String).Trim() -eq $builtVersion) 'installed binary must run' + Assert ([Environment]::GetEnvironmentVariable('Path', 'User') -eq $originalUserPath) 'UNITY_CLI_SKIP_PATH_UPDATE=1 must leave the user PATH alone' + Assert ($run.Output -notmatch 'Self-update will replace') 'no auto-update warning when UNITY_CLI_NO_AUTO_UPDATE=1' + + # Reinstall replaces an existing binary + Set-Content -Path $installed -Value 'stale' -Encoding ascii + $run = Invoke-Installer + Assert ($run.Code -eq 0) "reinstall exited with $($run.Code): $($run.Output)" + Assert ((Get-FileHash -Algorithm SHA256 -Path $installed).Hash -eq $builtHash) 'reinstall must replace the binary' + + # A held-open exe (like one a running daemon was started from) is moved aside + $handle = [System.IO.File]::Open($installed, 'Open', 'Read', [System.IO.FileShare]'Read, Delete') + try { + $run = Invoke-Installer + } finally { + $handle.Dispose() + } + Assert ($run.Code -eq 0) "install over a locked exe exited with $($run.Code): $($run.Output)" + Assert (@(Get-ChildItem -Path $destDir -Filter 'unity-cli.exe.old-*').Count -eq 1) 'the locked exe must be moved aside' + Assert ((Get-FileHash -Algorithm SHA256 -Path $installed).Hash -eq $builtHash) 'the build must replace the locked exe' + $run = Invoke-Installer + Assert ($run.Code -eq 0) "install after a locked exe exited with $($run.Code)" + Assert (@(Get-ChildItem -Path $destDir -Filter 'unity-cli.exe.old-*').Count -eq 0) 'the next run must remove the moved-aside exe' + + # A missing build fails and leaves the install alone + $env:CARGO_TARGET_DIR = $emptyTarget + $run = Invoke-Installer + Assert ($run.Code -ne 0) 'a missing build must fail' + Assert ($run.Output -match 'no build at') "missing build must say so: $($run.Output)" + Assert ((Get-FileHash -Algorithm SHA256 -Path $installed).Hash -eq $builtHash) 'a failed run must leave the install alone' + $env:CARGO_TARGET_DIR = $targetDir + + # Auto-update warning when the opt-out is not set (skipped when the + # machine sets it at user scope, which the installer also honours) + if ($userOptOut -ne '1') { + Remove-Item Env:UNITY_CLI_NO_AUTO_UPDATE + $run = Invoke-Installer + Assert ($run.Code -eq 0) "install without the opt-out exited with $($run.Code)" + Assert ($run.Output -match 'Self-update will replace') 'must warn when UNITY_CLI_NO_AUTO_UPDATE is unset' + } else { + Write-Host 'Skipping the warning check: UNITY_CLI_NO_AUTO_UPDATE=1 is set at user scope.' + } + + Write-Host "install-from-source.ps1 test passed ($builtVersion)" +} finally { + foreach ($name in $saved.Keys) { + [Environment]::SetEnvironmentVariable($name, $saved[$name], 'Process') + } + [Environment]::SetEnvironmentVariable('Path', $originalUserPath, 'User') + Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $work +} diff --git a/tests/scripts/install-from-source-sh-test.sh b/tests/scripts/install-from-source-sh-test.sh new file mode 100755 index 00000000..ff445dd1 --- /dev/null +++ b/tests/scripts/install-from-source-sh-test.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# Installs a locally built unity-cli through scripts/install-from-source.sh +# (--skip-build) into a temporary HOME and UNITY_CLI_TOOLS_ROOT and checks the +# managed layout: fresh install, symlink, reinstall, a missing build, and the +# auto-update warning. +# Usage: tests/scripts/install-from-source-sh-test.sh target/debug/unity-cli +set -eu + +BUILT=${1:?usage: $0 } +REPO_ROOT=$(cd "$(dirname "$0")/../.." && pwd) +INSTALLER="${REPO_ROOT}/scripts/install-from-source.sh" + +fail() { echo "FAIL: $*" >&2; exit 1; } + +case "$(uname -s)/$(uname -m)" in + Darwin/arm64|Darwin/aarch64) RID=osx-arm64 ;; + Darwin/x86_64) RID=osx-x64 ;; + Linux/aarch64|Linux/arm64) RID=linux-arm64 ;; + Linux/x86_64) RID=linux-x64 ;; + *) fail "unsupported platform $(uname -s)/$(uname -m)" ;; +esac + +BUILT_VERSION=$("$BUILT" --version) +VERSION=$(echo "$BUILT_VERSION" | awk '{print $2}') +hash_of() { cksum < "$1"; } +BUILT_HASH=$(hash_of "$BUILT") + +WORK=$(mktemp -d) +trap 'rm -rf "$WORK"' EXIT +mkdir -p "$WORK/home" "$WORK/target/debug" "$WORK/empty-target" +cp "$BUILT" "$WORK/target/debug/unity-cli" + +export HOME="$WORK/home" +export UNITY_CLI_TOOLS_ROOT="$WORK/tools" +export CARGO_TARGET_DIR="$WORK/target" +export UNITY_CLI_NO_AUTO_UPDATE=1 +DEST="$WORK/tools/unity-cli/$RID" +INSTALLED="$DEST/unity-cli" +OUT="$WORK/out" + +run() { sh "$INSTALLER" --debug --skip-build --no-skills >"$OUT" 2>&1; } + +# Fresh install +run || fail "fresh install failed: $(cat "$OUT")" +[ -x "$INSTALLED" ] || fail "binary must be installed into the managed layout" +[ "$(hash_of "$INSTALLED")" = "$BUILT_HASH" ] || fail "installed binary must match the build" +[ "$(cat "$DEST/VERSION")" = "$VERSION" ] || fail "VERSION must hold the build version" +[ "$("$INSTALLED" --version)" = "$BUILT_VERSION" ] || fail "installed binary must run" +[ "$(readlink "$HOME/.local/bin/unity-cli")" = "$INSTALLED" ] || fail "~/.local/bin/unity-cli must point at the managed binary" +! grep -q "self-update will replace" "$OUT" || fail "no auto-update warning when UNITY_CLI_NO_AUTO_UPDATE=1" + +# Reinstall replaces an existing binary +printf 'stale\n' > "$INSTALLED" +run || fail "reinstall failed: $(cat "$OUT")" +[ "$(hash_of "$INSTALLED")" = "$BUILT_HASH" ] || fail "reinstall must replace the binary" + +# A missing build fails and leaves the install alone +CARGO_TARGET_DIR="$WORK/empty-target" +if run; then fail "a missing build must fail"; fi +grep -q "no build at" "$OUT" || fail "missing build must say so: $(cat "$OUT")" +[ "$(hash_of "$INSTALLED")" = "$BUILT_HASH" ] || fail "a failed run must leave the install alone" +CARGO_TARGET_DIR="$WORK/target" + +# Auto-update warning when the opt-out is not set +unset UNITY_CLI_NO_AUTO_UPDATE +run || fail "install without the opt-out failed: $(cat "$OUT")" +grep -q "self-update will replace" "$OUT" || fail "must warn when UNITY_CLI_NO_AUTO_UPDATE is unset" + +echo "install-from-source.sh test passed (${BUILT_VERSION})" From f7a4a3a7ac195714bb00c51068ad6998c462cbc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 00:27:16 +0000 Subject: [PATCH 18/73] chore(deps): bump the npm_and_yarn group with 3 updates --- updated-dependencies: - dependency-name: "@google/gemini-cli" dependency-version: 0.63.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm_and_yarn - dependency-name: "@openai/codex" dependency-version: 0.162.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm_and_yarn - dependency-name: eslint dependency-version: 10.12.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package.json | 6 +-- pnpm-lock.yaml | 138 +++++++++++++++++++++++++++---------------------- 2 files changed, 80 insertions(+), 64 deletions(-) diff --git a/package.json b/package.json index f8b6d3b8..34f8142b 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ "@commitlint/cli": "^21.1.0", "@commitlint/config-conventional": "^21.1.0", "@eslint/js": "^10.0.1", - "@google/gemini-cli": "^0.62.0", - "@openai/codex": "^0.160.0", - "eslint": "^10.6.0", + "@google/gemini-cli": "^0.63.0", + "@openai/codex": "^0.162.0", + "eslint": "^10.12.0", "globals": "^17.13.0", "husky": "^9.1.7", "markdownlint-cli": "^0.49.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa066c09..84ce9760 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,16 +26,16 @@ importers: version: 21.2.3 '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.11.0(jiti@2.6.1)) + version: 10.0.1(eslint@10.12.0(jiti@2.6.1)) '@google/gemini-cli': - specifier: ^0.62.0 - version: 0.62.0 + specifier: ^0.63.0 + version: 0.63.0 '@openai/codex': - specifier: ^0.160.0 - version: 0.160.0 + specifier: ^0.162.0 + version: 0.162.0 eslint: - specifier: ^10.6.0 - version: 10.11.0(jiti@2.6.1) + specifier: ^10.12.0 + version: 10.12.0(jiti@2.6.1) globals: specifier: ^17.13.0 version: 17.13.0 @@ -150,8 +150,8 @@ packages: resolution: {integrity: sha512-aalGyl7dbB5PArRebDIX43ZvBlXrYm9uWzGJ26t+4SzJVPsOuvfILGGbw5X4yX7i50YEmJ8zvbiWnqH/AAnZqg==} engines: {node: '>=22'} - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -192,8 +192,8 @@ packages: '@github/keytar@7.10.6': resolution: {integrity: sha512-mRW6cUsSG+nj4jp5gp8e91zPySaT73r+2JM6VyMZfrEgksjPmjSMr+tPGNOK3HUHV+GUU9B1LAiiYy/wmAnIxA==} - '@google/gemini-cli@0.62.0': - resolution: {integrity: sha512-A1rw0Tf2sHLpGncfYdaq5WaJIufKAP8il4BmHD5Yw4ewmB/Wo0vRQb2bEvx7OqyaPFPZCh0hVhcMKsICZyIBww==} + '@google/gemini-cli@0.63.0': + resolution: {integrity: sha512-mmhqMmAdsoplCzrLQQC4yJBqr4uSKXghnrLspgUU6N9drmsaq7pi7oF09skRYzEq2dYK6eMT4UpFQP6rG2o/ew==} engines: {node: '>=20'} hasBin: true @@ -259,43 +259,43 @@ packages: '@lydell/node-pty@1.1.0': resolution: {integrity: sha512-VDD8LtlMTOrPKWMXUAcB9+LTktzuunqrMwkYR1DMRBkS6LQrCt+0/Ws1o2rMml/n3guePpS7cxhHF7Nm5K4iMw==} - '@openai/codex@0.160.0': - resolution: {integrity: sha512-kEtVGzjRAYAMOwJxN39bGcna7LT3IDQgq64NNJ/dDTfu4OzZaocJcyNb5/gGJ/IVF/Vj7oK7E2m3nmTan7lpjg==} + '@openai/codex@0.162.0': + resolution: {integrity: sha512-qWWckMfknyVym1lD5y2rTwPJA2sgHkzePF2l/Uevss4hVpqbt23rMIHKNTrqECdnv82denylHWEzrAmDnCYNIw==} engines: {node: '>=16'} hasBin: true - '@openai/codex@0.160.0-darwin-arm64': - resolution: {integrity: sha512-aefV6cqZA2REZgR//4McyXlp7zLcTti4CI2v3j9IVgNndPBv2kCeNEcz07qeelXcwOdSFPUKb6roA48vZmDgrQ==} + '@openai/codex@0.162.0-darwin-arm64': + resolution: {integrity: sha512-hyiGlMCbZog7IY2TcSWzXbsmtUnynT93QA4utqGlVmFlmz8TurADk3LV28zqUIdgh9GLOzumDIdHQbYieo9Nqw==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@openai/codex@0.160.0-darwin-x64': - resolution: {integrity: sha512-ir7cdsPrb9VkqNqpTECoTiomv04xws/FQ968mHQzuL+2J5Da0Dkh2Qlxp7sguDDZJab4YpYmNjQvBVMXbTeQaQ==} + '@openai/codex@0.162.0-darwin-x64': + resolution: {integrity: sha512-4XzCUJgEDDdme6VWDEKvbWDA6f+470d4xhhorYUgNBZwY8Dq5NYqvWkO33rnc1vjxkqSj+SwkymHxRMxL6h1CA==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@openai/codex@0.160.0-linux-arm64': - resolution: {integrity: sha512-VnVdsS06YlDsL8OwaJjQ3xdqdJNG4i+eBJBV3LytddknzSaF/urijLzVg3ptkwvoj8C7Gn7iWpVE+y8WEaPiCg==} + '@openai/codex@0.162.0-linux-arm64': + resolution: {integrity: sha512-6NYWwy09FsZ+/0Dz/bvV/yz3aFhkNzj86fSiux9Ax9VMBOID5nPdwd51OySm7fy8TMRud4fgJFELSi3Enc1s7Q==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@openai/codex@0.160.0-linux-x64': - resolution: {integrity: sha512-KI/73OqGrHmR18s7ya7E1NqV6rT0y3lxr0s8S1qR2m6zU6QRF/HlR529jALLh5vjdUnsRT4Ahoxt0axb4kY99g==} + '@openai/codex@0.162.0-linux-x64': + resolution: {integrity: sha512-qHWp6oKpf456PqjberGN8avs8zChv2oS+UuDiqVFYAuDOhq6vBc1drh8jEsnR7dBX+zcw03PN5VLtePGlMcC3w==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@openai/codex@0.160.0-win32-arm64': - resolution: {integrity: sha512-tTvK9ZIGuj9WnYaYOAnfjJVSfPV7dKqWtDHqUPLf0Hadp6SgynTxx7S7iMXRieFeXVOI2XH76KxEHSOTOnz3zw==} + '@openai/codex@0.162.0-win32-arm64': + resolution: {integrity: sha512-scdBHlUz4AfLOUWT4r4kwe3GFvjbBbWxreLDGoLSyMFf566e7sHSJvlJuV7uha2S7uRoQnMmWwmqYMJuT322UQ==} engines: {node: '>=16'} cpu: [arm64] os: [win32] - '@openai/codex@0.160.0-win32-x64': - resolution: {integrity: sha512-/gCFcuOmGlQkgGivWCtY8BNEDixh70Pue0HZOk9S8bj2vUIE1GLD9zcNB/KqqDJmn0S+lIttauLpzQnw6HOCHA==} + '@openai/codex@0.162.0-win32-x64': + resolution: {integrity: sha512-W8kqHaqpW0qPz71E0rRT5dq+socGz1BbJyYN7o3SP1TWQt8Zl6ML74R9Hvt/xn1NNLVlDTRfXqNmaMkte6yEMQ==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -337,8 +337,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.17.0: - resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} engines: {node: '>=0.4.0'} hasBin: true @@ -367,6 +367,10 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} + brace-expansion@5.0.6: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} @@ -496,8 +500,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.11.0: - resolution: {integrity: sha512-P7a6UEEqb9G95MYAtqkmsTbVXIYyzIfl6NGOIJk162PaahFxFyeGcrlXYFSiagECg4sEm8IseJdZBKR3rx6MsQ==} + eslint@10.12.0: + resolution: {integrity: sha512-npHjrHb2o4ehH3mE+YuxABR+0gyb0aVWCIolgJDArwCiHEIsonBm3ZKjel5b0U5+a+MbEvIyRCGCzD3eKKK2NA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -557,8 +561,8 @@ packages: flat-cache@6.1.23: resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} @@ -799,6 +803,10 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -1122,9 +1130,9 @@ snapshots: '@conventional-changelog/template@1.4.0': {} - '@eslint-community/eslint-utils@4.9.1(eslint@10.11.0(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.10.1(eslint@10.12.0(jiti@2.6.1))': dependencies: - eslint: 10.11.0(jiti@2.6.1) + eslint: 10.12.0(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -1133,7 +1141,7 @@ snapshots: dependencies: '@eslint/object-schema': 3.0.5 debug: 4.4.3 - minimatch: 10.2.5 + minimatch: 10.2.6 transitivePeerDependencies: - supports-color @@ -1145,9 +1153,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.11.0(jiti@2.6.1))': + '@eslint/js@10.0.1(eslint@10.12.0(jiti@2.6.1))': optionalDependencies: - eslint: 10.11.0(jiti@2.6.1) + eslint: 10.12.0(jiti@2.6.1) '@eslint/object-schema@3.0.5': {} @@ -1161,7 +1169,7 @@ snapshots: node-addon-api: 8.9.2 optional: true - '@google/gemini-cli@0.62.0': + '@google/gemini-cli@0.63.0': optionalDependencies: '@github/keytar': 7.10.6 '@lydell/node-pty': 1.1.0 @@ -1224,31 +1232,31 @@ snapshots: '@lydell/node-pty-win32-x64': 1.1.0 optional: true - '@openai/codex@0.160.0': + '@openai/codex@0.162.0': optionalDependencies: - '@openai/codex-darwin-arm64': '@openai/codex@0.160.0-darwin-arm64' - '@openai/codex-darwin-x64': '@openai/codex@0.160.0-darwin-x64' - '@openai/codex-linux-arm64': '@openai/codex@0.160.0-linux-arm64' - '@openai/codex-linux-x64': '@openai/codex@0.160.0-linux-x64' - '@openai/codex-win32-arm64': '@openai/codex@0.160.0-win32-arm64' - '@openai/codex-win32-x64': '@openai/codex@0.160.0-win32-x64' - - '@openai/codex@0.160.0-darwin-arm64': + '@openai/codex-darwin-arm64': '@openai/codex@0.162.0-darwin-arm64' + '@openai/codex-darwin-x64': '@openai/codex@0.162.0-darwin-x64' + '@openai/codex-linux-arm64': '@openai/codex@0.162.0-linux-arm64' + '@openai/codex-linux-x64': '@openai/codex@0.162.0-linux-x64' + '@openai/codex-win32-arm64': '@openai/codex@0.162.0-win32-arm64' + '@openai/codex-win32-x64': '@openai/codex@0.162.0-win32-x64' + + '@openai/codex@0.162.0-darwin-arm64': optional: true - '@openai/codex@0.160.0-darwin-x64': + '@openai/codex@0.162.0-darwin-x64': optional: true - '@openai/codex@0.160.0-linux-arm64': + '@openai/codex@0.162.0-linux-arm64': optional: true - '@openai/codex@0.160.0-linux-x64': + '@openai/codex@0.162.0-linux-x64': optional: true - '@openai/codex@0.160.0-win32-arm64': + '@openai/codex@0.162.0-win32-arm64': optional: true - '@openai/codex@0.160.0-win32-x64': + '@openai/codex@0.162.0-win32-x64': optional: true '@simple-libs/child-process-utils@2.0.0': @@ -1277,11 +1285,11 @@ snapshots: '@types/unist@2.0.11': {} - acorn-jsx@5.3.2(acorn@8.17.0): + acorn-jsx@5.3.2(acorn@8.19.0): dependencies: - acorn: 8.17.0 + acorn: 8.19.0 - acorn@8.17.0: {} + acorn@8.19.0: {} ajv@6.15.0: dependencies: @@ -1307,6 +1315,10 @@ snapshots: balanced-match@4.0.4: {} + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 @@ -1417,9 +1429,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.11.0(jiti@2.6.1): + eslint@10.12.0(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.11.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.7.0 @@ -1446,7 +1458,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.5 + minimatch: 10.2.6 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -1456,8 +1468,8 @@ snapshots: espree@11.2.0: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) eslint-visitor-keys: 5.0.1 esquery@1.7.0: @@ -1496,10 +1508,10 @@ snapshots: flat-cache@6.1.23: dependencies: cacheable: 2.5.0 - flatted: 3.4.2 + flatted: 3.4.4 hookified: 1.15.1 - flatted@3.4.2: {} + flatted@3.4.4: {} get-caller-file@2.0.5: {} @@ -1828,6 +1840,10 @@ snapshots: dependencies: brace-expansion: 5.0.6 + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + minimist@1.2.8: {} ms@2.1.3: {} From 742a4923d1c8e665465e9218fa0f906d42f52249 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 00:29:24 +0000 Subject: [PATCH 19/73] chore(deps): bump the cargo group with 4 updates Bumps the cargo group with 4 updates: [tokio](https://github.com/tokio-rs/tokio), [toml_edit](https://github.com/toml-rs/toml), [fastembed](https://github.com/Anush008/fastembed-rs) and [libc](https://github.com/rust-lang/libc). Updates `tokio` from 1.53.1 to 1.53.2 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.53.1...tokio-1.53.2) Updates `toml_edit` from 0.25.15+spec-1.1.0 to 0.25.16+spec-1.1.0 - [Commits](https://github.com/toml-rs/toml/compare/v0.25.15...v0.25.16) Updates `fastembed` from 7.1.0 to 7.1.1 - [Release notes](https://github.com/Anush008/fastembed-rs/releases) - [Commits](https://github.com/Anush008/fastembed-rs/compare/v7.1.0...v7.1.1) Updates `libc` from 0.2.189 to 0.2.190 - [Release notes](https://github.com/rust-lang/libc/releases) - [Changelog](https://github.com/rust-lang/libc/blob/0.2.190/CHANGELOG.md) - [Commits](https://github.com/rust-lang/libc/compare/0.2.189...0.2.190) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.53.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo - dependency-name: toml_edit dependency-version: 0.25.16+spec-1.1.0 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo - dependency-name: fastembed dependency-version: 7.1.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo - dependency-name: libc dependency-version: 0.2.190 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo ... Signed-off-by: dependabot[bot] --- Cargo.lock | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ebe7c9f..2bf3af70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,7 +84,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -95,7 +95,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -594,7 +594,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -642,7 +642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -653,9 +653,9 @@ checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" [[package]] name = "fastembed" -version = "7.1.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3850d724d559da51a4b88f68b0ba111a2627c32279bec6b3c256f073c71a3195" +checksum = "ca64ada7d0ad74737f45609542930cd5813fcb453b3f72ecb4255d8bd6fe4604" dependencies = [ "hf-hub", "ndarray", @@ -1221,9 +1221,9 @@ checksum = "34b357333733e8260735ba5894eb928c02ecc69c78715f01a8019e7fa7f2db4c" [[package]] name = "libc" -version = "0.2.189" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "libloading" @@ -1441,7 +1441,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1939,7 +1939,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2186,7 +2186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2288,7 +2288,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2412,9 +2412,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.53.1" +version = "1.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044" dependencies = [ "bytes", "libc", @@ -2461,18 +2461,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.25.15+spec-1.1.0" +version = "0.25.16+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" +checksum = "88f38f3af8bf71841c67a990f4e2b52143b2d0a1a994c72513ff4c14977fc722" dependencies = [ "indexmap", "toml_datetime", @@ -2483,18 +2483,18 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.1.3+spec-1.1.0" +version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" [[package]] name = "tower" @@ -2989,7 +2989,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] From 69d4cbe1b1be6d8e70d1fb877ba379112d2dc2a3 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 15:28:10 +0900 Subject: [PATCH 20/73] docs(readme): split install instructions into LLM-prompt and manual paths Getting Started now has Editor compatibility, an "Install with an LLM agent" section with one copy-paste prompt (OS detection, Quick Install, PATH check, manifest.json confirmation, setup, system ping, doctor on failure), and an "Install manually" section that keeps every existing install path. All translated READMEs follow the same structure with translated prompts. Closes #484 Co-Authored-By: Claude Opus 5.5 --- README.de.md | 133 ++++++++++++++++++++++++-- README.es.md | 138 ++++++++++++++++++++++++--- README.fr.md | 136 +++++++++++++++++++++++--- README.it.md | 138 ++++++++++++++++++++++++--- README.ja.md | 64 ++++++++++--- README.md | 51 +++++++--- README.zh.md | 131 ++++++++++++++++++++++--- tests/scripts/test_readme_install.py | 91 ++++++++++++++++++ 8 files changed, 796 insertions(+), 86 deletions(-) create mode 100644 tests/scripts/test_readme_install.py diff --git a/README.de.md b/README.de.md index bb2dd0cd..6dad5017 100644 --- a/README.de.md +++ b/README.de.md @@ -24,24 +24,107 @@ Einige Code Tools (`read`, `search`, `find_symbol`, `find_refs` usw.) laufen lok ## Einstieg -### Empfohlen: Claude Code Plugin +### Editor Kompatibilitat -Installieren Sie das `unity-cli` Plugin aus dem Claude Code Marketplace: +Die Bridge benotigt Unity 2022.3 oder neuer. Die macOS Matrix umfasst +2022.3.62f3, 6000.0.84f1, 6000.3.25f1, 6000.4.11f1, 6000.5.3f1, +6000.6.3f1, 6000.7.0a2 und 6000.7.0b2 (Abnahme E2E: PASS am 2026-09-30). Prufen Sie die +[Testdaten und Ergebnisse](docs/editor-compatibility.md), bevor Sie eine Version wahlen. +Der Unity 6000.7 Editor lauft auf Mono; CoreCLR Player Builds sind nicht Teil dieser Matrix. + +### Installation mit einem LLM Agenten + +Kopieren Sie diesen Prompt in Claude Code, Codex oder einen anderen Coding Agenten, +der in Ihrem Unity Projekt geoffnet ist: + +```text +Installiere unity-cli fur dieses Unity Projekt und verbinde es mit dem Unity Editor. + +1. Erkenne mein Betriebssystem (macOS, Linux oder Windows). +2. Wenn `unity-cli` noch nicht im PATH ist, fuhre das offizielle Quick Install Skript aus: + - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh + - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +3. Prufe, dass `unity-cli --version` uber den PATH funktioniert. Wenn es unter macOS / Linux + nicht gefunden wird, fuge ~/.local/bin fur diese Shell zum PATH hinzu und nenne mir die + Zeile fur mein Shell Profil. Unter Windows offne eine neue Shell, damit der aktualisierte + Benutzer PATH gilt. +4. Bevor du mein Projekt anderst, sage mir, dass setup Packages/manifest.json bearbeitet + (fugt die OpenUPM Scoped Registry und com.akiojin.unity-cli-bridge in der CLI Version hinzu) + und bei Projekten nur mit dem alten Input Manager activeInputHandler in + ProjectSettings/ProjectSettings.asset auf Both setzt. Warte auf meine Bestatigung. +5. Fuhre im Unity Projektstamm aus: unity-cli --output json setup --launch-editor + Wenn das JSON ok: false enthalt, folge editor.hint (der erste Import kann einige + Minuten dauern; fuhre setup erneut aus, um weiter zu warten). +6. Prufe die Verbindung mit: unity-cli system ping +7. Wenn ein Schritt fehlschlagt, fuhre aus: unity-cli doctor --output json + Melde den diagnosis Code und folge dessen Hinweis, bevor du es erneut versuchst. +``` + +**Claude Code Plugin**: Installieren Sie das `unity-cli` Plugin aus dem Claude Code +Marketplace, damit der Agent die Unity Workflow Skills nutzen kann: ```bash /plugin marketplace add akiojin/unity-cli ``` -Das Marketplace Plugin installiert nur Skills. Installieren Sie das -`unity-cli` Binary separat mit einer der manuellen Optionen unten. - -### Codex Skills +Das Plugin liefert Skills; Binary und Unity Bridge werden bei Bedarf eingerichtet. +Wenn eine Aufgabe Unity benotigt und `unity-cli` fehlt, lasst der Skill +`unity-cli-usage` den Agenten das Quick Install Skript und danach `unity-cli setup` +in Ihrem Unity Projekt ausfuhren (er informiert Sie, bevor `Packages/manifest.json` +geandert wird). -Wenn Sie dieses Repository mit Codex verwenden, sind Skills uber `.codex/skills/` verfugbar (Symlinks zur Plugin Quelle). +**Codex Skills**: Wenn Sie dieses Repository mit Codex verwenden, sind Skills uber +`.agents/skills/` verfugbar (Symlinks zur Plugin Quelle, auch uber `.claude/skills/`). Es ist keine zusatzliche Einrichtung erforderlich — klonen Sie einfach das Repository. ### Manuelle Installation +#### Quick Install (empfohlen) + +macOS (Apple silicon / Intel) und Linux: + +```bash +curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh +``` + +Windows (PowerShell): + +```powershell +irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +``` + +Beide Installer laden das Release Binary in das verwaltete Layout +`~/.unity/tools/unity-cli/{rid}/` und prufen es vor der Installation gegen die +Release `SHA256SUMS`; bei abweichender Prufsumme wird die Installation abgebrochen und +das vorhandene Binary bleibt unverandert. `install.sh` legt einen Symlink unter +`~/.local/bin/unity-cli` an; `install.ps1` fugt das verwaltete Verzeichnis zum Benutzer +`PATH` hinzu. Mit `UNITY_CLI_VERSION=v0.16.0` fixieren Sie ein Release. Nach der +Erstinstallation pruft die CLI im Hintergrund automatisch auf Updates, und jedes Update +wird gegen dieselben Prufsummen verifiziert. + +Wenn `~/.local/bin` nicht im PATH ist, fugen Sie Folgendes zu Ihrem Shell Profil hinzu +(z. B. `~/.zshrc` oder `~/.bashrc`): + +```bash +export PATH="$HOME/.local/bin:$PATH" +``` + +Setzen Sie `UNITY_CLI_NO_AUTO_UPDATE=1`, um Auto Updates zu deaktivieren. + +#### Paketmanager + +```bash +brew install akiojin/tap/unity-cli # macOS / Linux (Homebrew) +winget install akiojin.unity-cli # Windows (winget) +``` + +Installationen uber Paketmanager werden mit `brew upgrade` / `winget upgrade` aktualisiert. +Unter Intel macOS laden Reference Embeddings (`unity-cli reference embed-build` / `embed-search`) ONNX Runtime +dynamisch; die Homebrew Formula installiert `onnxruntime`, andernfalls fuhren Sie +`brew install onnxruntime` aus oder setzen `ORT_DYLIB_PATH`. + +#### Releases oder cargo install + Laden Sie das neueste Binary von [GitHub Releases](https://github.com/akiojin/unity-cli/releases) herunter oder installieren Sie es aus einem lokalen Checkout: @@ -52,9 +135,28 @@ cd unity-cli cargo install --path . ``` -Bridge Paket auf Unity Seite (eine Option wahlen): +#### Projekt Einrichtung -**OpenUPM** (empfohlen): +Projekt Einrichtung mit einem Befehl (Binary Prufung → Bridge Installation → Editor Verbindung): + +```bash +cd /path/to/YourUnityProject +unity-cli --output json setup --launch-editor +``` + +`setup` fugt die OpenUPM Scoped Registry und `com.akiojin.unity-cli-bridge` +(auf die CLI Version fixiert) zu `Packages/manifest.json` hinzu, startet optional den +Unity Hub Editor des Projekts, wartet auf die Bridge und gibt einen JSON Bericht zuruck. +`unity-cli bridge install | upgrade | status` verwalten das Paket einzeln; `install` ist +idempotent, und `setup` / `system ping` melden einen `versionCheck`, wenn sich CLI und +Bridge Version unterscheiden. Nutzt das Projekt nur den alten Input Manager und ist der +Editor geschlossen, setzt `install` zusatzlich `activeInputHandler` in +`ProjectSettings/ProjectSettings.asset` auf Both, damit die Input System Abhangigkeit +ohne blockierenden Neustart Dialog importiert wird. + +Bridge Paket auf Unity Seite, manuelle Alternativen (eine Option wahlen): + +**OpenUPM**: ```bash openupm add com.akiojin.unity-cli-bridge @@ -66,12 +168,23 @@ openupm add com.akiojin.unity-cli-bridge https://github.com/akiojin/unity-cli.git?path=UnityCliBridge/Packages/unity-cli-bridge ``` -Verbindungstest: +#### Verbindungstest ```bash unity-cli system ping +unity-cli doctor --output json # wenn ping fehlschlagt: SAFE_MODE / BRIDGE_NOT_INSTALLED / PORT_IN_USE / ... ``` +#### Wartung des verwalteten Binary + +```bash +unity-cli cli doctor +unity-cli cli install +``` + +`unityd` und `lspd` aktualisieren ihre verwalteten `unity-cli` / C# LSP Binaries beim Daemon Start automatisch. +Die verwalteten Kopien liegen unter `UNITY_CLI_TOOLS_ROOT` (oder dem OS Standard Tools Verzeichnis) und werden ohne interaktive Bestatigung aktualisiert. + ## Skills (13) | Kategorie | Skills | diff --git a/README.es.md b/README.es.md index 775e9429..f810e916 100644 --- a/README.es.md +++ b/README.es.md @@ -24,27 +24,107 @@ Algunas herramientas de codigo (`read`, `search`, `find_symbol`, `find_refs`, et ## Inicio rapido -### Recomendado: plugin de Claude Code +### Compatibilidad del Editor -Instala el plugin `unity-cli` desde Claude Code Marketplace: +El Bridge requiere Unity 2022.3 o posterior. La matriz de macOS cubre +2022.3.62f3, 6000.0.84f1, 6000.3.25f1, 6000.4.11f1, 6000.5.3f1, +6000.6.3f1, 6000.7.0a2 y 6000.7.0b2 (E2E de aceptacion: PASS el 2026-09-30). Consulte las +[fechas y resultados de verificacion](docs/editor-compatibility.md) antes de elegir una version. +El Editor de Unity 6000.7 se ejecuta sobre Mono; los builds de Player con CoreCLR quedan fuera de esta matriz. + +### Instalar con un agente LLM + +Copie este prompt en Claude Code, Codex u otro agente de programacion abierto en +su proyecto de Unity: + +```text +Instala unity-cli para este proyecto de Unity y conectalo al Unity Editor. + +1. Detecta mi sistema operativo (macOS, Linux o Windows). +2. Si `unity-cli` todavia no esta en el PATH, ejecuta el script oficial de Quick Install: + - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh + - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +3. Comprueba que `unity-cli --version` funciona desde el PATH. En macOS / Linux, si no se + encuentra, agrega ~/.local/bin al PATH de esta shell y dime la linea que debo agregar a + mi perfil de shell. En Windows, abre una shell nueva para aplicar el PATH de usuario actualizado. +4. Antes de modificar mi proyecto, dime que setup edita Packages/manifest.json (agrega el + scoped registry de OpenUPM y com.akiojin.unity-cli-bridge fijado a la version del CLI) y, + en proyectos que solo usan el Input Manager antiguo, establece activeInputHandler en Both + en ProjectSettings/ProjectSettings.asset. Espera mi confirmacion. +5. Desde la raiz del proyecto de Unity, ejecuta: unity-cli --output json setup --launch-editor + Si el JSON tiene ok: false, sigue editor.hint (la primera importacion puede tardar + varios minutos; vuelve a ejecutar setup para seguir esperando). +6. Verifica la conexion con: unity-cli system ping +7. Si algun paso falla, ejecuta: unity-cli doctor --output json + Informa el codigo diagnosis y sigue su indicacion antes de reintentar. +``` + +**Plugin de Claude Code**: instale el plugin `unity-cli` desde Claude Code +Marketplace para que el agente pueda usar los skills de flujos de trabajo de Unity: ```bash /plugin marketplace add akiojin/unity-cli ``` -El plugin del Marketplace instala solo los skills. Instala el binario -`unity-cli` por separado con una de las opciones manuales de abajo. - -### Codex Skills +El plugin incluye skills; el binario y el bridge de Unity se preparan cuando hacen falta. +Cuando una tarea necesita Unity y falta `unity-cli`, el skill `unity-cli-usage` hace que +el agente ejecute el script de Quick Install y luego `unity-cli setup` en su proyecto de +Unity (le avisa antes de editar `Packages/manifest.json`). -Al usar este repositorio con Codex, los skills estan disponibles a traves de `.codex/skills/` (enlaces simbolicos a la fuente del plugin). -No se requiere configuracion adicional — solo clona el repositorio. +**Codex Skills**: si usa este repositorio con Codex, los skills estan disponibles en +`.agents/skills/` (symlinks a la fuente del plugin, tambien expuestos en `.claude/skills/`). +No requiere configuracion adicional — solo clone el repositorio. ### Instalacion manual -Descarga el binario mas reciente desde [GitHub -Releases](https://github.com/akiojin/unity-cli/releases), o instalalo desde -un clon local: +#### Quick Install (recomendado) + +macOS (Apple silicon / Intel) y Linux: + +```bash +curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh +``` + +Windows (PowerShell): + +```powershell +irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +``` + +Ambos instaladores descargan el binario de la release en la estructura administrada +`~/.unity/tools/unity-cli/{rid}/` y lo verifican con los `SHA256SUMS` de la release antes +de instalar; si la suma de comprobacion no coincide, la instalacion se cancela y el binario +existente no se toca. `install.sh` crea un symlink en `~/.local/bin/unity-cli`; +`install.ps1` agrega el directorio administrado al `PATH` del usuario. Defina +`UNITY_CLI_VERSION=v0.16.0` para fijar una release. Tras la instalacion inicial, el CLI +busca actualizaciones automaticamente en segundo plano, y cada actualizacion se verifica +con las mismas sumas de comprobacion. + +Si `~/.local/bin` no esta en su PATH, agregue lo siguiente a su perfil de shell +(por ejemplo `~/.zshrc` o `~/.bashrc`): + +```bash +export PATH="$HOME/.local/bin:$PATH" +``` + +Defina `UNITY_CLI_NO_AUTO_UPDATE=1` para desactivar la actualizacion automatica. + +#### Gestores de paquetes + +```bash +brew install akiojin/tap/unity-cli # macOS / Linux (Homebrew) +winget install akiojin.unity-cli # Windows (winget) +``` + +Las instalaciones con gestores de paquetes se actualizan con `brew upgrade` / `winget upgrade`. +En macOS Intel, los embeddings de reference (`unity-cli reference embed-build` / `embed-search`) cargan ONNX Runtime +de forma dinamica; la formula de Homebrew instala `onnxruntime`; en otro caso ejecute +`brew install onnxruntime` o defina `ORT_DYLIB_PATH`. + +#### Releases o cargo install + +Descargue el binario mas reciente desde [GitHub +Releases](https://github.com/akiojin/unity-cli/releases) o instale desde un checkout local: ```bash git clone https://github.com/akiojin/unity-cli.git @@ -52,9 +132,28 @@ cd unity-cli cargo install --path . ``` -Paquete bridge para Unity (elige una opcion): +#### Configuracion del proyecto -**OpenUPM** (recomendado): +Configuracion del proyecto en un solo comando (comprobacion del binario → instalacion del bridge → conexion con el Editor): + +```bash +cd /path/to/YourUnityProject +unity-cli --output json setup --launch-editor +``` + +`setup` agrega el scoped registry de OpenUPM y `com.akiojin.unity-cli-bridge` +(fijado a la version del CLI) a `Packages/manifest.json`, opcionalmente inicia el Editor +de Unity Hub del proyecto, espera al bridge y devuelve un informe JSON. +`unity-cli bridge install | upgrade | status` administran el paquete por separado; +`install` es idempotente, y `setup` / `system ping` informan un `versionCheck` cuando las +versiones del CLI y del bridge difieren. Si el proyecto aun usa solo el Input Manager +antiguo y el Editor esta cerrado, `install` tambien establece `activeInputHandler` en Both +en `ProjectSettings/ProjectSettings.asset`, para que la dependencia de Input System se +importe sin un aviso de reinicio bloqueante. + +Paquete bridge del lado de Unity, alternativas manuales (elija una): + +**OpenUPM**: ```bash openupm add com.akiojin.unity-cli-bridge @@ -66,12 +165,23 @@ openupm add com.akiojin.unity-cli-bridge https://github.com/akiojin/unity-cli.git?path=UnityCliBridge/Packages/unity-cli-bridge ``` -Comprobacion de conexion: +#### Comprobacion de conexion ```bash unity-cli system ping +unity-cli doctor --output json # si ping falla: SAFE_MODE / BRIDGE_NOT_INSTALLED / PORT_IN_USE / ... ``` +#### Mantenimiento del binario administrado + +```bash +unity-cli cli doctor +unity-cli cli install +``` + +`unityd` y `lspd` actualizan automaticamente sus binarios administrados de `unity-cli` / C# LSP al iniciar el daemon. +Las copias administradas residen en `UNITY_CLI_TOOLS_ROOT` (o en el directorio de tools predeterminado del SO) y se actualizan sin confirmacion interactiva. + ## Skills (13) | Categoria | Skills | diff --git a/README.fr.md b/README.fr.md index 55203395..c85bfb56 100644 --- a/README.fr.md +++ b/README.fr.md @@ -24,27 +24,107 @@ Certains outils code (`read`, `search`, `find_symbol`, `find_refs`, etc.) s exec ## Demarrage -### Recommande: plugin Claude Code +### Compatibilite de l'Editor -Installez le plugin `unity-cli` depuis la Marketplace de Claude Code: +Le Bridge requiert Unity 2022.3 ou plus recent. La matrice macOS couvre +2022.3.62f3, 6000.0.84f1, 6000.3.25f1, 6000.4.11f1, 6000.5.3f1, +6000.6.3f1, 6000.7.0a2 et 6000.7.0b2 (E2E d'acceptation: PASS le 2026-09-30). Consultez les +[dates et resultats de verification](docs/editor-compatibility.md) avant de choisir une version. +L'Editor Unity 6000.7 s'execute sur Mono; les builds Player CoreCLR sont hors de cette matrice. + +### Installer avec un agent LLM + +Copiez ce prompt dans Claude Code, Codex ou un autre agent de code ouvert dans +votre projet Unity: + +```text +Installe unity-cli pour ce projet Unity et connecte-le au Unity Editor. + +1. Detecte mon systeme d'exploitation (macOS, Linux ou Windows). +2. Si `unity-cli` n'est pas encore dans le PATH, execute le script officiel de Quick Install: + - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh + - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +3. Verifie que `unity-cli --version` fonctionne depuis le PATH. Sous macOS / Linux, s'il est + introuvable, ajoute ~/.local/bin au PATH de ce shell et indique-moi la ligne a ajouter a + mon profil de shell. Sous Windows, ouvre un nouveau shell pour appliquer le PATH utilisateur mis a jour. +4. Avant de modifier mon projet, dis-moi que setup modifie Packages/manifest.json (ajoute le + scoped registry OpenUPM et com.akiojin.unity-cli-bridge fixe a la version du CLI) et, pour + les projets qui n'utilisent que l'ancien Input Manager, met activeInputHandler a Both dans + ProjectSettings/ProjectSettings.asset. Attends ma confirmation. +5. A la racine du projet Unity, execute: unity-cli --output json setup --launch-editor + Si le JSON contient ok: false, suis editor.hint (le premier import peut prendre + plusieurs minutes; relance setup pour continuer a attendre). +6. Verifie la connexion avec: unity-cli system ping +7. Si une etape echoue, execute: unity-cli doctor --output json + Indique le code diagnosis et suis son conseil avant de reessayer. +``` + +**Plugin Claude Code**: installez le plugin `unity-cli` depuis Claude Code +Marketplace pour que l'agent puisse utiliser les skills de workflow Unity: ```bash /plugin marketplace add akiojin/unity-cli ``` -Le plugin Marketplace installe uniquement les skills. Installez le binaire -`unity-cli` separement avec l une des options manuelles ci-dessous. - -### Codex Skills +Le plugin fournit les skills; le binaire et le bridge Unity sont installes a la demande. +Quand une tache necessite Unity et que `unity-cli` manque, le skill `unity-cli-usage` fait +executer par l'agent le script de Quick Install puis `unity-cli setup` dans votre projet +Unity (il vous previent avant de modifier `Packages/manifest.json`). -Lorsque vous utilisez ce depot avec Codex, les skills sont disponibles via `.codex/skills/` (liens symboliques vers la source du plugin). -Aucune configuration supplementaire n est necessaire — il suffit de cloner le depot. +**Codex Skills**: si vous utilisez ce depot avec Codex, les skills sont disponibles via +`.agents/skills/` (liens symboliques vers la source du plugin, aussi exposes via +`.claude/skills/`). Aucune configuration supplementaire n'est requise — clonez simplement le depot. ### Installation manuelle +#### Quick Install (recommande) + +macOS (Apple silicon / Intel) et Linux: + +```bash +curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh +``` + +Windows (PowerShell): + +```powershell +irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +``` + +Les deux installeurs telechargent le binaire de la release dans l'arborescence geree +`~/.unity/tools/unity-cli/{rid}/` et le verifient avec les `SHA256SUMS` de la release avant +l'installation; en cas de somme de controle differente, l'installation est annulee et le +binaire existant reste intact. `install.sh` cree un lien symbolique `~/.local/bin/unity-cli`; +`install.ps1` ajoute le repertoire gere au `PATH` utilisateur. Definissez +`UNITY_CLI_VERSION=v0.16.0` pour fixer une release. Apres l'installation initiale, le CLI +verifie automatiquement les mises a jour en arriere-plan, et chaque mise a jour est +verifiee avec les memes sommes de controle. + +Si `~/.local/bin` n'est pas dans votre PATH, ajoutez ceci a votre profil de shell +(par ex. `~/.zshrc` ou `~/.bashrc`): + +```bash +export PATH="$HOME/.local/bin:$PATH" +``` + +Definissez `UNITY_CLI_NO_AUTO_UPDATE=1` pour desactiver la mise a jour automatique. + +#### Gestionnaires de paquets + +```bash +brew install akiojin/tap/unity-cli # macOS / Linux (Homebrew) +winget install akiojin.unity-cli # Windows (winget) +``` + +Les installations par gestionnaire de paquets se mettent a jour avec `brew upgrade` / `winget upgrade`. +Sous macOS Intel, les embeddings reference (`unity-cli reference embed-build` / `embed-search`) chargent ONNX Runtime +dynamiquement; la formule Homebrew installe `onnxruntime`, sinon executez +`brew install onnxruntime` ou definissez `ORT_DYLIB_PATH`. + +#### Releases ou cargo install + Telechargez le dernier binaire depuis [GitHub -Releases](https://github.com/akiojin/unity-cli/releases), ou installez-le -depuis un clone local: +Releases](https://github.com/akiojin/unity-cli/releases) ou installez depuis un checkout local: ```bash git clone https://github.com/akiojin/unity-cli.git @@ -52,9 +132,28 @@ cd unity-cli cargo install --path . ``` -Package bridge cote Unity (choisir une option): +#### Configuration du projet -**OpenUPM** (recommande): +Configuration du projet en une commande (verification du binaire → installation du bridge → connexion a l'Editor): + +```bash +cd /path/to/YourUnityProject +unity-cli --output json setup --launch-editor +``` + +`setup` ajoute le scoped registry OpenUPM et `com.akiojin.unity-cli-bridge` +(fixe a la version du CLI) a `Packages/manifest.json`, lance eventuellement l'Editor Unity +Hub du projet, attend le bridge et renvoie un rapport JSON. +`unity-cli bridge install | upgrade | status` gerent le paquet separement; `install` est +idempotent, et `setup` / `system ping` signalent un `versionCheck` quand les versions du CLI +et du bridge different. Si le projet n'utilise encore que l'ancien Input Manager et que +l'Editor est ferme, `install` met aussi `activeInputHandler` a Both dans +`ProjectSettings/ProjectSettings.asset`, afin que la dependance Input System s'importe sans +demande de redemarrage bloquante. + +Paquet bridge cote Unity, alternatives manuelles (choisissez une option): + +**OpenUPM**: ```bash openupm add com.akiojin.unity-cli-bridge @@ -66,12 +165,23 @@ openupm add com.akiojin.unity-cli-bridge https://github.com/akiojin/unity-cli.git?path=UnityCliBridge/Packages/unity-cli-bridge ``` -Verification de connexion: +#### Verification de connexion ```bash unity-cli system ping +unity-cli doctor --output json # si ping echoue: SAFE_MODE / BRIDGE_NOT_INSTALLED / PORT_IN_USE / ... ``` +#### Maintenance du binaire gere + +```bash +unity-cli cli doctor +unity-cli cli install +``` + +`unityd` et `lspd` mettent automatiquement a jour leurs binaires geres `unity-cli` / C# LSP au demarrage du daemon. +Les copies gerees se trouvent sous `UNITY_CLI_TOOLS_ROOT` (ou le repertoire tools par defaut de l'OS) et sont mises a jour sans confirmation interactive. + ## Skills (13) | Categorie | Skills | diff --git a/README.it.md b/README.it.md index 67dac398..b165509b 100644 --- a/README.it.md +++ b/README.it.md @@ -24,27 +24,107 @@ Alcuni strumenti di codice (`read`, `search`, `find_symbol`, `find_refs`, ecc.) ## Inizio rapido -### Consigliato: plugin Claude Code +### Compatibilita dell'Editor -Installa il plugin `unity-cli` dal Claude Code Marketplace: +Il Bridge richiede Unity 2022.3 o successivo. La matrice macOS copre +2022.3.62f3, 6000.0.84f1, 6000.3.25f1, 6000.4.11f1, 6000.5.3f1, +6000.6.3f1, 6000.7.0a2 e 6000.7.0b2 (E2E di accettazione: PASS il 2026-09-30). Consultare le +[date e i risultati di verifica](docs/editor-compatibility.md) prima di scegliere una versione. +L'Editor Unity 6000.7 gira su Mono; le build Player CoreCLR sono escluse da questa matrice. + +### Installare con un agente LLM + +Copiare questo prompt in Claude Code, Codex o un altro agente di programmazione aperto +nel proprio progetto Unity: + +```text +Installa unity-cli per questo progetto Unity e collegalo allo Unity Editor. + +1. Rileva il mio sistema operativo (macOS, Linux o Windows). +2. Se `unity-cli` non e ancora nel PATH, esegui lo script ufficiale di Quick Install: + - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh + - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +3. Verifica che `unity-cli --version` funzioni dal PATH. Su macOS / Linux, se non viene + trovato, aggiungi ~/.local/bin al PATH di questa shell e indicami la riga da aggiungere al + mio profilo della shell. Su Windows, apri una nuova shell per applicare il PATH utente aggiornato. +4. Prima di modificare il mio progetto, dimmi che setup modifica Packages/manifest.json + (aggiunge lo scoped registry OpenUPM e com.akiojin.unity-cli-bridge fissato alla versione + della CLI) e, per i progetti che usano solo il vecchio Input Manager, imposta + activeInputHandler su Both in ProjectSettings/ProjectSettings.asset. Attendi la mia conferma. +5. Dalla radice del progetto Unity, esegui: unity-cli --output json setup --launch-editor + Se il JSON contiene ok: false, segui editor.hint (la prima importazione puo richiedere + alcuni minuti; riesegui setup per continuare ad attendere). +6. Verifica la connessione con: unity-cli system ping +7. Se un passaggio fallisce, esegui: unity-cli doctor --output json + Riporta il codice diagnosis e segui il suo suggerimento prima di riprovare. +``` + +**Plugin Claude Code**: installare il plugin `unity-cli` da Claude Code +Marketplace per permettere all'agente di usare gli skill dei workflow Unity: ```bash /plugin marketplace add akiojin/unity-cli ``` -Il plugin del Marketplace installa solo gli skill. Installa il binario -`unity-cli` separatamente con una delle opzioni manuali qui sotto. - -### Codex Skills +Il plugin fornisce gli skill; il binario e il bridge Unity vengono preparati quando servono. +Quando un'attivita richiede Unity e `unity-cli` manca, lo skill `unity-cli-usage` fa eseguire +all'agente lo script di Quick Install e poi `unity-cli setup` nel progetto Unity +(avvisa prima di modificare `Packages/manifest.json`). -Quando si utilizza questo repository con Codex, le skill sono disponibili tramite `.codex/skills/` (link simbolici alla sorgente del plugin). -Non e necessaria alcuna configurazione aggiuntiva — basta clonare il repository. +**Codex Skills**: usando questo repository con Codex, gli skill sono disponibili tramite +`.agents/skills/` (symlink alla sorgente del plugin, esposti anche tramite `.claude/skills/`). +Non serve alcuna configurazione aggiuntiva — basta clonare il repository. ### Installazione manuale -Scarica il binary piu recente da [GitHub -Releases](https://github.com/akiojin/unity-cli/releases), oppure installalo da -un clone locale: +#### Quick Install (consigliato) + +macOS (Apple silicon / Intel) e Linux: + +```bash +curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh +``` + +Windows (PowerShell): + +```powershell +irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +``` + +Entrambi gli installer scaricano il binario della release nella struttura gestita +`~/.unity/tools/unity-cli/{rid}/` e lo verificano con i `SHA256SUMS` della release prima +dell'installazione; se il checksum non corrisponde, l'installazione viene interrotta e il +binario esistente non viene toccato. `install.sh` crea un symlink in `~/.local/bin/unity-cli`; +`install.ps1` aggiunge la directory gestita al `PATH` utente. Impostare +`UNITY_CLI_VERSION=v0.16.0` per fissare una release. Dopo l'installazione iniziale la CLI +controlla automaticamente gli aggiornamenti in background, e ogni aggiornamento viene +verificato con gli stessi checksum. + +Se `~/.local/bin` non e nel PATH, aggiungere quanto segue al profilo della shell +(ad es. `~/.zshrc` o `~/.bashrc`): + +```bash +export PATH="$HOME/.local/bin:$PATH" +``` + +Impostare `UNITY_CLI_NO_AUTO_UPDATE=1` per disattivare l'aggiornamento automatico. + +#### Gestori di pacchetti + +```bash +brew install akiojin/tap/unity-cli # macOS / Linux (Homebrew) +winget install akiojin.unity-cli # Windows (winget) +``` + +Le installazioni tramite gestore di pacchetti si aggiornano con `brew upgrade` / `winget upgrade`. +Su macOS Intel, gli embedding reference (`unity-cli reference embed-build` / `embed-search`) caricano ONNX Runtime +dinamicamente; la formula Homebrew installa `onnxruntime`, altrimenti eseguire +`brew install onnxruntime` o impostare `ORT_DYLIB_PATH`. + +#### Releases o cargo install + +Scaricare il binario piu recente da [GitHub +Releases](https://github.com/akiojin/unity-cli/releases) oppure installarlo da un checkout locale: ```bash git clone https://github.com/akiojin/unity-cli.git @@ -52,9 +132,28 @@ cd unity-cli cargo install --path . ``` -Pacchetto bridge lato Unity (scegli un'opzione): +#### Configurazione del progetto -**OpenUPM** (consigliato): +Configurazione del progetto con un solo comando (controllo del binario → installazione del bridge → connessione all'Editor): + +```bash +cd /path/to/YourUnityProject +unity-cli --output json setup --launch-editor +``` + +`setup` aggiunge lo scoped registry OpenUPM e `com.akiojin.unity-cli-bridge` +(fissato alla versione della CLI) a `Packages/manifest.json`, avvia facoltativamente +l'Editor Unity Hub del progetto, attende il bridge e restituisce un report JSON. +`unity-cli bridge install | upgrade | status` gestiscono il pacchetto separatamente; +`install` e idempotente, e `setup` / `system ping` segnalano un `versionCheck` quando le +versioni di CLI e bridge differiscono. Se il progetto usa ancora solo il vecchio Input +Manager e l'Editor e chiuso, `install` imposta anche `activeInputHandler` su Both in +`ProjectSettings/ProjectSettings.asset`, cosi la dipendenza Input System viene importata +senza un prompt di riavvio bloccante. + +Pacchetto bridge lato Unity, alternative manuali (sceglierne una): + +**OpenUPM**: ```bash openupm add com.akiojin.unity-cli-bridge @@ -66,12 +165,23 @@ openupm add com.akiojin.unity-cli-bridge https://github.com/akiojin/unity-cli.git?path=UnityCliBridge/Packages/unity-cli-bridge ``` -Verifica connessione: +#### Verifica della connessione ```bash unity-cli system ping +unity-cli doctor --output json # se ping fallisce: SAFE_MODE / BRIDGE_NOT_INSTALLED / PORT_IN_USE / ... ``` +#### Manutenzione del binario gestito + +```bash +unity-cli cli doctor +unity-cli cli install +``` + +`unityd` e `lspd` aggiornano automaticamente i propri binari gestiti `unity-cli` / C# LSP all'avvio del daemon. +Le copie gestite si trovano in `UNITY_CLI_TOOLS_ROOT` (o nella directory tools predefinita del sistema operativo) e vengono aggiornate senza conferma interattiva. + ## Skills (13) | Categoria | Skills | diff --git a/README.ja.md b/README.ja.md index 85fc0529..fa364d15 100644 --- a/README.ja.md +++ b/README.ja.md @@ -33,9 +33,37 @@ Bridge の最小バージョンは Unity 2022.3 です。macOS 検証対象は [対応表の検証日・結果](docs/editor-compatibility.md)を確認してください。 6000.7 の Editor は Mono で動作し、CoreCLR Player ビルドはこの検証の対象外です。 -### 推奨: Claude Code プラグイン +### LLM エージェントでインストール -Claude Code Marketplace から `unity-cli` プラグインをインストールします: +Unity プロジェクトで開いた Claude Code や Codex などのコーディングエージェントに、 +次のプロンプトをそのまま貼り付けてください: + +```text +この Unity プロジェクトに unity-cli をインストールし、Unity Editor と接続してください。 + +1. OS(macOS / Linux / Windows)を判定してください。 +2. `unity-cli` が PATH 上にない場合は、公式のクイックインストールスクリプトを実行してください: + - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh + - Windows(PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +3. PATH から `unity-cli --version` が実行できることを確認してください。macOS / Linux で + 見つからない場合は、このシェルの PATH に ~/.local/bin を追加し、シェルプロファイルに + 追記する行を教えてください。Windows では、更新されたユーザー PATH を反映するため + 新しいシェルを開いてください。 +4. プロジェクトを変更する前に、setup が Packages/manifest.json を編集すること + (OpenUPM の scoped registry と、CLI と同じバージョンに固定した + com.akiojin.unity-cli-bridge を追加すること)と、旧 Input Manager のみのプロジェクトでは + ProjectSettings/ProjectSettings.asset の activeInputHandler を Both に設定することを + 説明し、私の確認を待ってください。 +5. Unity プロジェクトのルートで次を実行してください: unity-cli --output json setup --launch-editor + JSON が ok: false の場合は editor.hint に従ってください(初回インポートは数分かかる + ことがあります。待ち続けるには setup を再実行します)。 +6. 次のコマンドで接続を確認してください: unity-cli system ping +7. いずれかの手順が失敗した場合は、次を実行してください: unity-cli doctor --output json + diagnosis コードを報告し、そのヒントに従ってから再試行してください。 +``` + +**Claude Code プラグイン**: Claude Code Marketplace から `unity-cli` プラグインを +インストールすると、エージェントが Unity 操作用のスキルを使えるようになります: ```bash /plugin marketplace add akiojin/unity-cli @@ -43,15 +71,16 @@ Claude Code Marketplace から `unity-cli` プラグインをインストール プラグインが提供するのはスキルで、バイナリと Unity ブリッジは必要時に導入されます。 Unity 操作が必要なのに `unity-cli` が未導入の場合、`unity-cli-usage` スキルに従って -エージェントがインストールスクリプト(`scripts/install.sh`)を実行し、Unity プロジェクトで +エージェントがクイックインストールスクリプトを実行し、Unity プロジェクトで `unity-cli setup` を実行します(`Packages/manifest.json` を変更する前にユーザーへ明示します)。 -### Codex スキル - -Codex でこのリポジトリを利用する場合、`.codex/skills/` にスキルのシンボリックリンクが配置済みです。 +**Codex スキル**: Codex でこのリポジトリを利用する場合、`.agents/skills/` に +スキルのシンボリックリンクが配置済みです(`.claude/skills/` からも参照できます)。 リポジトリをクローンするだけで追加セットアップは不要です。 -### クイックインストール(推奨) +### 手動でインストール + +#### クイックインストール(推奨) macOS(Apple silicon / Intel)と Linux: @@ -70,10 +99,19 @@ irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 ハッシュが一致しない場合は導入を中止し、既存のバイナリには触れません。 `install.sh` は `~/.local/bin/unity-cli` にシンボリックリンクを作り、`install.ps1` は managed ディレクトリをユーザーの `PATH` に追加します。`UNITY_CLI_VERSION=v0.16.0` で -リリースを固定できます。導入後の自動更新も同じチェックサムで検証されます。 +リリースを固定できます。導入後は CLI がバックグラウンドで自動更新を確認し、 +更新も同じチェックサムで検証されます。 + +`~/.local/bin` が PATH に含まれていない場合は、シェルプロファイル +(例: `~/.zshrc` や `~/.bashrc`)に次を追加してください: + +```bash +export PATH="$HOME/.local/bin:$PATH" +``` + 自動更新を止めるには `UNITY_CLI_NO_AUTO_UPDATE=1` を設定してください。 -### パッケージマネージャ +#### パッケージマネージャ ```bash brew install akiojin/tap/unity-cli # macOS / Linux(Homebrew) @@ -85,7 +123,7 @@ Intel Mac の reference 埋め込み(`unity-cli reference embed-build` / `embe Homebrew formula は `onnxruntime` を依存として導入します。それ以外の導入方法では `brew install onnxruntime` を実行するか、`ORT_DYLIB_PATH` を設定してください。 -### 手動インストール +#### Releases / cargo install 最新バイナリは [GitHub Releases](https://github.com/akiojin/unity-cli/releases) から取得できます。 @@ -97,6 +135,8 @@ cd unity-cli cargo install --path . ``` +#### プロジェクトのセットアップ + プロジェクトのセットアップを 1 コマンドで行う(binary 検証 → bridge 導入 → Editor 接続確認): ```bash @@ -127,14 +167,14 @@ openupm add com.akiojin.unity-cli-bridge https://github.com/akiojin/unity-cli.git?path=UnityCliBridge/Packages/unity-cli-bridge ``` -接続確認: +#### 接続確認 ```bash unity-cli system ping unity-cli doctor --output json # ping 失敗時: SAFE_MODE / BRIDGE_NOT_INSTALLED / PORT_IN_USE など ``` -managed バイナリの確認と更新: +#### managed バイナリの確認と更新 ```bash unity-cli cli doctor diff --git a/README.md b/README.md index a0dfbd54..d8eb0926 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,35 @@ The Bridge requires Unity 2022.3 or newer. The macOS matrix covers [verification dates and results](docs/editor-compatibility.md) before choosing a version. Unity 6000.7 Editor runs on Mono; CoreCLR Player builds are outside this matrix. -### Recommended: Claude Code Plugin +### Install with an LLM agent -Install the `unity-cli` plugin from Claude Code Marketplace: +Copy this prompt into Claude Code, Codex, or another coding agent opened in +your Unity project: + +```text +Install unity-cli for this Unity project and connect it to the Unity Editor. + +1. Detect my OS (macOS, Linux, or Windows). +2. If `unity-cli` is not already on PATH, run the official Quick Install script: + - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh + - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +3. Check that `unity-cli --version` works from PATH. On macOS / Linux, if it is + not found, add ~/.local/bin to PATH for this shell and tell me the line to add + to my shell profile. On Windows, open a new shell so the updated user PATH applies. +4. Before changing my project, tell me that setup edits Packages/manifest.json + (adds the OpenUPM scoped registry and com.akiojin.unity-cli-bridge pinned to + the CLI version) and, for legacy-input-only projects, sets activeInputHandler + to Both in ProjectSettings/ProjectSettings.asset. Wait for my confirmation. +5. From the Unity project root, run: unity-cli --output json setup --launch-editor + If the JSON has ok: false, follow editor.hint (the first import can take + several minutes; rerun setup to keep waiting). +6. Verify the connection with: unity-cli system ping +7. If any step fails, run: unity-cli doctor --output json + Report the diagnosis code and follow its hint before retrying. +``` + +**Claude Code plugin**: install the `unity-cli` plugin from Claude Code +Marketplace to give the agent the Unity workflow skills: ```bash /plugin marketplace add akiojin/unity-cli @@ -56,16 +82,17 @@ Install the `unity-cli` plugin from Claude Code Marketplace: The plugin ships skills; the binary and the Unity bridge are bootstrapped on demand. When a task needs Unity and `unity-cli` is missing, the -`unity-cli-usage` skill has the agent run the Quick Install script below and then +`unity-cli-usage` skill has the agent run the Quick Install script and then `unity-cli setup` in your Unity project (it tells you before editing `Packages/manifest.json`). -### Codex Skills +**Codex Skills**: when using this repository with Codex, skills are available +via `.agents/skills/` (symlinks to the plugin source, also exposed through +`.claude/skills/`). No additional setup is required - just clone the repository. -When using this repository with Codex, skills are available via `.agents/skills/` (symlinks to the plugin source, also exposed through `.claude/skills/`). -No additional setup is required - just clone the repository. +### Install manually -### Quick Install (recommended) +#### Quick Install (recommended) macOS (Apple silicon / Intel) and Linux: @@ -97,7 +124,7 @@ export PATH="$HOME/.local/bin:$PATH" Set `UNITY_CLI_NO_AUTO_UPDATE=1` to disable auto-update. -### Package Managers +#### Package Managers ```bash brew install akiojin/tap/unity-cli # macOS / Linux (Homebrew) @@ -109,7 +136,7 @@ On Intel macOS, reference embeddings (`unity-cli reference embed-build` / `embed dynamically; the Homebrew formula installs `onnxruntime`, otherwise run `brew install onnxruntime` or set `ORT_DYLIB_PATH`. -### Manual Install +#### Releases or cargo install Download the latest binary from [GitHub Releases](https://github.com/akiojin/unity-cli/releases), or install from a @@ -121,6 +148,8 @@ cd unity-cli cargo install --path . ``` +#### Project setup + One-command project setup (binary check → bridge install → Editor connection): ```bash @@ -152,14 +181,14 @@ openupm add com.akiojin.unity-cli-bridge https://github.com/akiojin/unity-cli.git?path=UnityCliBridge/Packages/unity-cli-bridge ``` -Connection check: +#### Connection check ```bash unity-cli system ping unity-cli doctor --output json # when ping fails: SAFE_MODE / BRIDGE_NOT_INSTALLED / PORT_IN_USE / ... ``` -Managed binary maintenance: +#### Managed binary maintenance ```bash unity-cli cli doctor diff --git a/README.zh.md b/README.zh.md index 22125b6b..23ddd234 100644 --- a/README.zh.md +++ b/README.zh.md @@ -24,25 +24,104 @@ Claude Code ## 快速开始 -### 推荐: Claude Code 插件 +### Editor 兼容性 -从 Claude Code Marketplace 安装 `unity-cli` 插件: +Bridge 要求 Unity 2022.3 或更高版本。macOS 验证矩阵覆盖 +2022.3.62f3、6000.0.84f1、6000.3.25f1、6000.4.11f1、6000.5.3f1、 +6000.6.3f1、6000.7.0a2 和 6000.7.0b2(2026-09-30 验收 E2E: 全部 PASS)。 +选择版本前请查看[验证日期与结果](docs/editor-compatibility.md)。 +Unity 6000.7 的 Editor 运行在 Mono 上,CoreCLR Player 构建不在此矩阵范围内。 + +### 使用 LLM 代理安装 + +在 Unity 项目中打开 Claude Code、Codex 或其他编码代理,然后直接粘贴以下提示词: + +```text +请为这个 Unity 项目安装 unity-cli,并将其连接到 Unity Editor。 + +1. 判断我的操作系统(macOS、Linux 或 Windows)。 +2. 如果 PATH 中还没有 `unity-cli`,运行官方快速安装脚本: + - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh + - Windows(PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +3. 确认可以从 PATH 运行 `unity-cli --version`。在 macOS / Linux 上如果找不到, + 请把 ~/.local/bin 加入当前 shell 的 PATH,并告诉我需要写入 shell 配置文件的那一行。 + 在 Windows 上,请打开新的 shell 以应用更新后的用户 PATH。 +4. 修改项目之前,请告诉我 setup 会编辑 Packages/manifest.json(添加 OpenUPM + scoped registry 以及固定为 CLI 同版本的 com.akiojin.unity-cli-bridge),并且对于 + 只使用旧 Input Manager 的项目,会把 ProjectSettings/ProjectSettings.asset 中的 + activeInputHandler 设为 Both。等待我的确认。 +5. 在 Unity 项目根目录运行: unity-cli --output json setup --launch-editor + 如果 JSON 返回 ok: false,请按照 editor.hint 处理(首次导入可能需要几分钟; + 重新运行 setup 可继续等待)。 +6. 使用以下命令确认连接: unity-cli system ping +7. 如果任何步骤失败,请运行: unity-cli doctor --output json + 报告 diagnosis 代码,并按照其提示处理后再重试。 +``` + +**Claude Code 插件**: 从 Claude Code Marketplace 安装 `unity-cli` 插件, +让代理可以使用 Unity 工作流 Skills: ```bash /plugin marketplace add akiojin/unity-cli ``` -Marketplace 插件只会安装 skills。`unity-cli` 二进制本体需要使用下面的手动方式之一单独安装。 - -### Codex Skills +插件只提供 Skills,二进制文件和 Unity bridge 会在需要时自动引导安装。 +当任务需要 Unity 但尚未安装 `unity-cli` 时,`unity-cli-usage` skill 会让代理运行 +快速安装脚本,然后在 Unity 项目中运行 `unity-cli setup` +(编辑 `Packages/manifest.json` 之前会先告知你)。 -使用 Codex 时,`.codex/skills/` 中已提供指向插件源的符号链接。 -只需克隆仓库即可,无需额外配置。 +**Codex Skills**: 在 Codex 中使用本仓库时,可以通过 `.agents/skills/` 使用 Skills +(指向插件源码的符号链接,也可通过 `.claude/skills/` 访问)。只需克隆仓库,无需额外设置。 ### 手动安装 -可以从 [GitHub Releases](https://github.com/akiojin/unity-cli/releases) -下载最新二进制,或者从本地 clone 安装: +#### 快速安装(推荐) + +macOS(Apple silicon / Intel)和 Linux: + +```bash +curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh +``` + +Windows(PowerShell): + +```powershell +irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex +``` + +两个安装脚本都会把发布版二进制文件下载到 managed 目录 +`~/.unity/tools/unity-cli/{rid}/`,并在安装前使用发布版的 `SHA256SUMS` 校验; +校验不一致时会中止安装,且不会改动已有的二进制文件。`install.sh` 会创建 +`~/.local/bin/unity-cli` 符号链接;`install.ps1` 会把 managed 目录加入用户 `PATH`。 +设置 `UNITY_CLI_VERSION=v0.16.0` 可固定发布版本。首次安装后,CLI 会在后台自动检查更新, +每次更新都使用相同的校验和进行验证。 + +如果 `~/.local/bin` 不在 PATH 中,请将以下内容加入 shell 配置文件 +(例如 `~/.zshrc` 或 `~/.bashrc`): + +```bash +export PATH="$HOME/.local/bin:$PATH" +``` + +设置 `UNITY_CLI_NO_AUTO_UPDATE=1` 可关闭自动更新。 + +#### 包管理器 + +```bash +brew install akiojin/tap/unity-cli # macOS / Linux(Homebrew) +winget install akiojin.unity-cli # Windows(winget) +``` + +通过包管理器安装时,使用 `brew upgrade` / `winget upgrade` 更新。 +在 Intel macOS 上,reference 嵌入(`unity-cli reference embed-build` / `embed-search`)会动态加载 ONNX Runtime; +Homebrew formula 会安装 `onnxruntime`,其他安装方式请运行 +`brew install onnxruntime` 或设置 `ORT_DYLIB_PATH`。 + +#### Releases 或 cargo install + +从 [GitHub +Releases](https://github.com/akiojin/unity-cli/releases) 下载最新二进制文件, +或从本地 checkout 安装: ```bash git clone https://github.com/akiojin/unity-cli.git @@ -50,9 +129,26 @@ cd unity-cli cargo install --path . ``` -Unity 侧桥接包(选择其一): +#### 项目设置 -**OpenUPM**(推荐): +一条命令完成项目设置(二进制检查 → bridge 安装 → Editor 连接): + +```bash +cd /path/to/YourUnityProject +unity-cli --output json setup --launch-editor +``` + +`setup` 会向 `Packages/manifest.json` 添加 OpenUPM scoped registry 和 +`com.akiojin.unity-cli-bridge`(固定为 CLI 同版本),必要时启动项目对应的 Unity Hub Editor, +等待 bridge 响应,并返回一份 JSON 报告。`unity-cli bridge install | upgrade | status` +可单独管理该包;`install` 是幂等的,CLI 与 bridge 版本不一致时,`setup` / `system ping` +会通过 `versionCheck` 报告。当项目仍只使用旧 Input Manager 且 Editor 已关闭时, +`install` 还会把 `ProjectSettings/ProjectSettings.asset` 中的 `activeInputHandler` 设为 Both, +从而在导入 Input System 依赖时避免阻塞式的重启提示。 + +Unity 端 bridge 包的手动安装方式(任选其一): + +**OpenUPM**: ```bash openupm add com.akiojin.unity-cli-bridge @@ -64,12 +160,23 @@ openupm add com.akiojin.unity-cli-bridge https://github.com/akiojin/unity-cli.git?path=UnityCliBridge/Packages/unity-cli-bridge ``` -连接检查: +#### 连接检查 ```bash unity-cli system ping +unity-cli doctor --output json # ping 失败时: SAFE_MODE / BRIDGE_NOT_INSTALLED / PORT_IN_USE / ... ``` +#### managed 二进制维护 + +```bash +unity-cli cli doctor +unity-cli cli install +``` + +`unityd` 和 `lspd` 会在 daemon 启动时自动更新 managed `unity-cli` / C# LSP 二进制文件。 +managed 副本位于 `UNITY_CLI_TOOLS_ROOT`(未设置时为操作系统默认的 tools 目录)下,更新时不会弹出交互式确认。 + ## Skills (13) | 类别 | Skills | diff --git a/tests/scripts/test_readme_install.py b/tests/scripts/test_readme_install.py new file mode 100644 index 00000000..8b1df67c --- /dev/null +++ b/tests/scripts/test_readme_install.py @@ -0,0 +1,91 @@ +import re +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +READMES = ['README.md', 'README.ja.md', 'README.zh.md', 'README.de.md', + 'README.es.md', 'README.fr.md', 'README.it.md'] + +PROMPT_STEPS = [ + 'scripts/install.sh', + 'scripts/install.ps1', + 'PATH', + 'unity-cli --output json setup --launch-editor', + 'unity-cli system ping', + 'unity-cli doctor --output json', + 'Packages/manifest.json', +] + +MANUAL_CONTENT = [ + 'scripts/install.sh | sh', + 'scripts/install.ps1 | iex', + 'SHA256SUMS', + 'UNITY_CLI_VERSION', + 'UNITY_CLI_NO_AUTO_UPDATE', + 'brew install akiojin/tap/unity-cli', + 'winget install akiojin.unity-cli', + 'ORT_DYLIB_PATH', + 'releases', + 'cargo install --path .', + 'unity-cli --output json setup --launch-editor', + 'unity-cli bridge install | upgrade | status', + 'activeInputHandler', + 'openupm add com.akiojin.unity-cli-bridge', + '?path=UnityCliBridge/Packages/unity-cli-bridge', + 'unity-cli system ping', + 'unity-cli doctor --output json', + 'unity-cli cli doctor', + 'unity-cli cli install', + 'UNITY_CLI_TOOLS_ROOT', +] + + +def getting_started(text): + """Return the `##` section that holds the Editor compatibility note.""" + sections = re.split(r'^(?=## )', text, flags=re.MULTILINE) + matches = [s for s in sections if 'docs/editor-compatibility.md' in s] + assert len(matches) == 1, 'Getting Started section not found' + return matches[0] + + +def subsections(section): + parts = re.split(r'^(?=### )', section, flags=re.MULTILINE)[1:] + return [(part.splitlines()[0], part) for part in parts] + + +class ReadmeInstallStructureTest(unittest.TestCase): + def test_getting_started_has_compat_llm_and_manual_paths(self): + for name in READMES: + with self.subTest(readme=name): + subs = subsections(getting_started((ROOT / name).read_text())) + self.assertEqual(len(subs), 3, [title for title, _ in subs]) + self.assertIn('docs/editor-compatibility.md', subs[0][1]) + + def test_llm_section_has_single_prompt_with_all_steps(self): + for name in READMES: + with self.subTest(readme=name): + llm = subsections(getting_started((ROOT / name).read_text()))[1][1] + prompts = re.findall(r'^```text\n(.*?)^```', llm, + flags=re.MULTILINE | re.DOTALL) + self.assertEqual(len(prompts), 1) + prompt = prompts[0] + positions = [prompt.find(step) for step in PROMPT_STEPS] + for step, pos in zip(PROMPT_STEPS, positions): + self.assertGreaterEqual(pos, 0, step) + ordered = [positions[0], positions[3], positions[4], positions[5]] + self.assertEqual(ordered, sorted(ordered)) + # manifest.json confirmation must come before setup runs + self.assertLess(positions[6], positions[3]) + self.assertIn('/plugin marketplace add akiojin/unity-cli', llm) + self.assertIn('.agents/skills/', llm) + + def test_manual_section_keeps_every_install_path(self): + for name in READMES: + with self.subTest(readme=name): + manual = subsections(getting_started((ROOT / name).read_text()))[2][1] + for needle in MANUAL_CONTENT: + self.assertIn(needle, manual, needle) + + +if __name__ == '__main__': + unittest.main() From 91f7ac838d7a9f9d38b671bedaa9ecb3223693b3 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 15:56:24 +0900 Subject: [PATCH 21/73] docs(readme): make the LLM install prompt also update the CLI and the Unity bridge The prompt now updates an existing unity-cli the way it was installed (skipping pinned installs), aligns a registry-sourced bridge with `unity-cli bridge upgrade` after confirmation, reports custom/embedded sources instead of rewriting them, and confirms versionCheck is match. Applied to all translated READMEs and covered by test_readme_install.py. Closes #487 Co-Authored-By: Claude Opus 5.5 --- README.de.md | 37 ++++++++++++++++----- README.es.md | 36 ++++++++++++++++----- README.fr.md | 37 ++++++++++++++++----- README.it.md | 36 ++++++++++++++++----- README.ja.md | 35 +++++++++++++++----- README.md | 39 +++++++++++++++++----- README.zh.md | 33 ++++++++++++++----- tests/scripts/test_readme_install.py | 48 ++++++++++++++++++++++++++++ 8 files changed, 245 insertions(+), 56 deletions(-) diff --git a/README.de.md b/README.de.md index 6dad5017..a1efadc0 100644 --- a/README.de.md +++ b/README.de.md @@ -32,31 +32,52 @@ Die Bridge benotigt Unity 2022.3 oder neuer. Die macOS Matrix umfasst [Testdaten und Ergebnisse](docs/editor-compatibility.md), bevor Sie eine Version wahlen. Der Unity 6000.7 Editor lauft auf Mono; CoreCLR Player Builds sind nicht Teil dieser Matrix. -### Installation mit einem LLM Agenten +### Installation oder Aktualisierung mit einem LLM Agenten Kopieren Sie diesen Prompt in Claude Code, Codex oder einen anderen Coding Agenten, -der in Ihrem Unity Projekt geoffnet ist: +der in Ihrem Unity Projekt geoffnet ist. Fuhren Sie denselben Prompt spater erneut aus, +um CLI und Unity Bridge Paket gemeinsam zu aktualisieren: ```text -Installiere unity-cli fur dieses Unity Projekt und verbinde es mit dem Unity Editor. +Installiere oder aktualisiere unity-cli fur dieses Unity Projekt, halte das Unity Bridge +Paket auf derselben Version wie die CLI und verbinde es mit dem Unity Editor. 1. Erkenne mein Betriebssystem (macOS, Linux oder Windows). 2. Wenn `unity-cli` noch nicht im PATH ist, fuhre das offizielle Quick Install Skript aus: - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex -3. Prufe, dass `unity-cli --version` uber den PATH funktioniert. Wenn es unter macOS / Linux +3. Wenn `unity-cli` bereits im PATH ist, aktualisiere es stattdessen auf das neueste Release. + Wenn UNITY_CLI_NO_AUTO_UPDATE=1 oder UNITY_CLI_VERSION gesetzt ist, habe ich die Version + absichtlich fixiert: aktualisiere nicht, sag es mir und frage zuerst. Andernfalls ermittle, + wo die Binardatei tatsachlich liegt (Symlinks folgen), und aktualisiere sie auf dem Weg, + auf dem sie installiert wurde: + - Quick Install (verwaltete Kopie unter ~/.unity/tools): unity-cli cli install + - Homebrew: brew upgrade akiojin/tap/unity-cli + - winget: winget upgrade akiojin.unity-cli + - Alles andere (cargo install, manueller Download): sag mir, wie es installiert wurde, + und frage, bevor du etwas anderst. +4. Prufe, dass `unity-cli --version` uber den PATH funktioniert. Wenn es unter macOS / Linux nicht gefunden wird, fuge ~/.local/bin fur diese Shell zum PATH hinzu und nenne mir die Zeile fur mein Shell Profil. Unter Windows offne eine neue Shell, damit der aktualisierte Benutzer PATH gilt. -4. Bevor du mein Projekt anderst, sage mir, dass setup Packages/manifest.json bearbeitet +5. Bevor du mein Projekt anderst, sage mir, dass setup Packages/manifest.json bearbeitet (fugt die OpenUPM Scoped Registry und com.akiojin.unity-cli-bridge in der CLI Version hinzu) und bei Projekten nur mit dem alten Input Manager activeInputHandler in ProjectSettings/ProjectSettings.asset auf Both setzt. Warte auf meine Bestatigung. -5. Fuhre im Unity Projektstamm aus: unity-cli --output json setup --launch-editor +6. Fuhre im Unity Projektstamm aus: unity-cli --output json setup --launch-editor Wenn das JSON ok: false enthalt, folge editor.hint (der erste Import kann einige Minuten dauern; fuhre setup erneut aus, um weiter zu warten). -6. Prufe die Verbindung mit: unity-cli system ping -7. Wenn ein Schritt fehlschlagt, fuhre aus: unity-cli doctor --output json +7. Prufe die Bridge Version mit: unity-cli --output json bridge status + - Wenn source registry ist und versionCheck.status (hier oder im setup Bericht) mismatch ist: + sag mir, dass dies die Zeile com.akiojin.unity-cli-bridge in Packages/manifest.json auf + die CLI Version andert, und warte auf meine Bestatigung. Fuhre dann unity-cli bridge upgrade + aus und lass den Unity Editor das Paket neu importieren. + - Wenn source custom oder embedded ist (Git URL, lokaler Pfad oder eine Kopie unter + Packages/) oder versionCheck.status unknown ist: nicht umschreiben. Melde mir stattdessen + source und beide Versionen. +8. Prufe die Verbindung mit: unity-cli system ping + Bestatige, dass versionCheck.status match ist (CLI und Bridge haben dieselbe Version). +9. Wenn ein Schritt fehlschlagt, fuhre aus: unity-cli doctor --output json Melde den diagnosis Code und folge dessen Hinweis, bevor du es erneut versuchst. ``` diff --git a/README.es.md b/README.es.md index f810e916..b06cb712 100644 --- a/README.es.md +++ b/README.es.md @@ -32,30 +32,50 @@ El Bridge requiere Unity 2022.3 o posterior. La matriz de macOS cubre [fechas y resultados de verificacion](docs/editor-compatibility.md) antes de elegir una version. El Editor de Unity 6000.7 se ejecuta sobre Mono; los builds de Player con CoreCLR quedan fuera de esta matriz. -### Instalar con un agente LLM +### Instalar o actualizar con un agente LLM Copie este prompt en Claude Code, Codex u otro agente de programacion abierto en -su proyecto de Unity: +su proyecto de Unity. Ejecute el mismo prompt mas adelante para actualizar juntos el CLI +y el paquete bridge de Unity: ```text -Instala unity-cli para este proyecto de Unity y conectalo al Unity Editor. +Instala o actualiza unity-cli para este proyecto de Unity, manten el paquete bridge de +Unity en la misma version que el CLI y conectalo al Unity Editor. 1. Detecta mi sistema operativo (macOS, Linux o Windows). 2. Si `unity-cli` todavia no esta en el PATH, ejecuta el script oficial de Quick Install: - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex -3. Comprueba que `unity-cli --version` funciona desde el PATH. En macOS / Linux, si no se +3. Si `unity-cli` ya esta en el PATH, actualizalo a la ultima version en su lugar. + Si UNITY_CLI_NO_AUTO_UPDATE=1 o UNITY_CLI_VERSION estan definidos, fije la version a + proposito: no lo actualices; dimelo y preguntame primero. En otro caso, averigua donde esta + realmente el binario (siguiendo enlaces simbolicos) y actualizalo segun como se instalo: + - Quick Install (copia gestionada en ~/.unity/tools): unity-cli cli install + - Homebrew: brew upgrade akiojin/tap/unity-cli + - winget: winget upgrade akiojin.unity-cli + - Cualquier otro caso (cargo install, descarga manual): dime como se instalo y + preguntame antes de cambiarlo. +4. Comprueba que `unity-cli --version` funciona desde el PATH. En macOS / Linux, si no se encuentra, agrega ~/.local/bin al PATH de esta shell y dime la linea que debo agregar a mi perfil de shell. En Windows, abre una shell nueva para aplicar el PATH de usuario actualizado. -4. Antes de modificar mi proyecto, dime que setup edita Packages/manifest.json (agrega el +5. Antes de modificar mi proyecto, dime que setup edita Packages/manifest.json (agrega el scoped registry de OpenUPM y com.akiojin.unity-cli-bridge fijado a la version del CLI) y, en proyectos que solo usan el Input Manager antiguo, establece activeInputHandler en Both en ProjectSettings/ProjectSettings.asset. Espera mi confirmacion. -5. Desde la raiz del proyecto de Unity, ejecuta: unity-cli --output json setup --launch-editor +6. Desde la raiz del proyecto de Unity, ejecuta: unity-cli --output json setup --launch-editor Si el JSON tiene ok: false, sigue editor.hint (la primera importacion puede tardar varios minutos; vuelve a ejecutar setup para seguir esperando). -6. Verifica la conexion con: unity-cli system ping -7. Si algun paso falla, ejecuta: unity-cli doctor --output json +7. Comprueba la version del bridge con: unity-cli --output json bridge status + - Si source es registry y versionCheck.status (aqui o en el informe de setup) es mismatch: + dime que esto cambia la linea com.akiojin.unity-cli-bridge de Packages/manifest.json a la + version del CLI y espera mi confirmacion. Luego ejecuta unity-cli bridge upgrade y deja + que el Unity Editor vuelva a importar el paquete. + - Si source es custom o embedded (URL de Git, ruta local o una copia en Packages/), o + versionCheck.status es unknown: no lo reescribas. En su lugar, informame del source y + de ambas versiones. +8. Verifica la conexion con: unity-cli system ping + Confirma que versionCheck.status es match (el CLI y el bridge usan la misma version). +9. Si algun paso falla, ejecuta: unity-cli doctor --output json Informa el codigo diagnosis y sigue su indicacion antes de reintentar. ``` diff --git a/README.fr.md b/README.fr.md index c85bfb56..c529d0be 100644 --- a/README.fr.md +++ b/README.fr.md @@ -32,30 +32,51 @@ Le Bridge requiert Unity 2022.3 ou plus recent. La matrice macOS couvre [dates et resultats de verification](docs/editor-compatibility.md) avant de choisir une version. L'Editor Unity 6000.7 s'execute sur Mono; les builds Player CoreCLR sont hors de cette matrice. -### Installer avec un agent LLM +### Installer ou mettre a jour avec un agent LLM Copiez ce prompt dans Claude Code, Codex ou un autre agent de code ouvert dans -votre projet Unity: +votre projet Unity. Relancez le meme prompt plus tard pour mettre a jour ensemble le CLI +et le package bridge Unity: ```text -Installe unity-cli pour ce projet Unity et connecte-le au Unity Editor. +Installe ou mets a jour unity-cli pour ce projet Unity, garde le package bridge Unity a la +meme version que le CLI et connecte-le au Unity Editor. 1. Detecte mon systeme d'exploitation (macOS, Linux ou Windows). 2. Si `unity-cli` n'est pas encore dans le PATH, execute le script officiel de Quick Install: - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex -3. Verifie que `unity-cli --version` fonctionne depuis le PATH. Sous macOS / Linux, s'il est +3. Si `unity-cli` est deja dans le PATH, mets-le plutot a jour vers la derniere version. + Si UNITY_CLI_NO_AUTO_UPDATE=1 ou UNITY_CLI_VERSION est defini, j'ai fixe la version + volontairement: ne le mets pas a jour; previens-moi et demande d'abord. Sinon, determine + ou se trouve reellement le binaire (en suivant les liens symboliques) et mets-le a jour + selon sa methode d'installation: + - Quick Install (copie geree sous ~/.unity/tools): unity-cli cli install + - Homebrew: brew upgrade akiojin/tap/unity-cli + - winget: winget upgrade akiojin.unity-cli + - Tout autre cas (cargo install, telechargement manuel): dis-moi comment il a ete + installe et demande avant de le modifier. +4. Verifie que `unity-cli --version` fonctionne depuis le PATH. Sous macOS / Linux, s'il est introuvable, ajoute ~/.local/bin au PATH de ce shell et indique-moi la ligne a ajouter a mon profil de shell. Sous Windows, ouvre un nouveau shell pour appliquer le PATH utilisateur mis a jour. -4. Avant de modifier mon projet, dis-moi que setup modifie Packages/manifest.json (ajoute le +5. Avant de modifier mon projet, dis-moi que setup modifie Packages/manifest.json (ajoute le scoped registry OpenUPM et com.akiojin.unity-cli-bridge fixe a la version du CLI) et, pour les projets qui n'utilisent que l'ancien Input Manager, met activeInputHandler a Both dans ProjectSettings/ProjectSettings.asset. Attends ma confirmation. -5. A la racine du projet Unity, execute: unity-cli --output json setup --launch-editor +6. A la racine du projet Unity, execute: unity-cli --output json setup --launch-editor Si le JSON contient ok: false, suis editor.hint (le premier import peut prendre plusieurs minutes; relance setup pour continuer a attendre). -6. Verifie la connexion avec: unity-cli system ping -7. Si une etape echoue, execute: unity-cli doctor --output json +7. Verifie la version du bridge avec: unity-cli --output json bridge status + - Si source vaut registry et que versionCheck.status (ici ou dans le rapport de setup) vaut + mismatch: dis-moi que cela remplace la ligne com.akiojin.unity-cli-bridge de + Packages/manifest.json par la version du CLI et attends ma confirmation. Execute ensuite + unity-cli bridge upgrade et laisse le Unity Editor reimporter le package. + - Si source vaut custom ou embedded (URL Git, chemin local ou copie sous Packages/), ou si + versionCheck.status vaut unknown: ne le reecris pas. Indique-moi plutot le source et + les deux versions. +8. Verifie la connexion avec: unity-cli system ping + Confirme que versionCheck.status vaut match (le CLI et le bridge ont la meme version). +9. Si une etape echoue, execute: unity-cli doctor --output json Indique le code diagnosis et suis son conseil avant de reessayer. ``` diff --git a/README.it.md b/README.it.md index b165509b..31bb1fbc 100644 --- a/README.it.md +++ b/README.it.md @@ -32,30 +32,50 @@ Il Bridge richiede Unity 2022.3 o successivo. La matrice macOS copre [date e i risultati di verifica](docs/editor-compatibility.md) prima di scegliere una versione. L'Editor Unity 6000.7 gira su Mono; le build Player CoreCLR sono escluse da questa matrice. -### Installare con un agente LLM +### Installare o aggiornare con un agente LLM Copiare questo prompt in Claude Code, Codex o un altro agente di programmazione aperto -nel proprio progetto Unity: +nel proprio progetto Unity. Eseguire di nuovo lo stesso prompt in seguito per aggiornare +insieme la CLI e il pacchetto bridge di Unity: ```text -Installa unity-cli per questo progetto Unity e collegalo allo Unity Editor. +Installa o aggiorna unity-cli per questo progetto Unity, mantieni il pacchetto bridge di +Unity alla stessa versione della CLI e collegalo allo Unity Editor. 1. Rileva il mio sistema operativo (macOS, Linux o Windows). 2. Se `unity-cli` non e ancora nel PATH, esegui lo script ufficiale di Quick Install: - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex -3. Verifica che `unity-cli --version` funzioni dal PATH. Su macOS / Linux, se non viene +3. Se `unity-cli` e gia nel PATH, aggiornalo invece all'ultima release. + Se UNITY_CLI_NO_AUTO_UPDATE=1 o UNITY_CLI_VERSION sono impostati, ho fissato la versione + di proposito: non aggiornarlo; dimmelo e chiedimi prima. Altrimenti individua dove si trova + davvero il binario (seguendo i link simbolici) e aggiornalo nel modo in cui e stato installato: + - Quick Install (copia gestita sotto ~/.unity/tools): unity-cli cli install + - Homebrew: brew upgrade akiojin/tap/unity-cli + - winget: winget upgrade akiojin.unity-cli + - Qualsiasi altro caso (cargo install, download manuale): dimmi come e stato installato e + chiedimi prima di modificarlo. +4. Verifica che `unity-cli --version` funzioni dal PATH. Su macOS / Linux, se non viene trovato, aggiungi ~/.local/bin al PATH di questa shell e indicami la riga da aggiungere al mio profilo della shell. Su Windows, apri una nuova shell per applicare il PATH utente aggiornato. -4. Prima di modificare il mio progetto, dimmi che setup modifica Packages/manifest.json +5. Prima di modificare il mio progetto, dimmi che setup modifica Packages/manifest.json (aggiunge lo scoped registry OpenUPM e com.akiojin.unity-cli-bridge fissato alla versione della CLI) e, per i progetti che usano solo il vecchio Input Manager, imposta activeInputHandler su Both in ProjectSettings/ProjectSettings.asset. Attendi la mia conferma. -5. Dalla radice del progetto Unity, esegui: unity-cli --output json setup --launch-editor +6. Dalla radice del progetto Unity, esegui: unity-cli --output json setup --launch-editor Se il JSON contiene ok: false, segui editor.hint (la prima importazione puo richiedere alcuni minuti; riesegui setup per continuare ad attendere). -6. Verifica la connessione con: unity-cli system ping -7. Se un passaggio fallisce, esegui: unity-cli doctor --output json +7. Controlla la versione del bridge con: unity-cli --output json bridge status + - Se source e registry e versionCheck.status (qui o nel report di setup) e mismatch: + dimmi che questo cambia la riga com.akiojin.unity-cli-bridge in Packages/manifest.json + alla versione della CLI e attendi la mia conferma. Poi esegui unity-cli bridge upgrade e + lascia che lo Unity Editor reimporti il pacchetto. + - Se source e custom o embedded (URL Git, percorso locale o una copia sotto Packages/), o + versionCheck.status e unknown: non riscriverlo. Riportami invece il source ed entrambe + le versioni. +8. Verifica la connessione con: unity-cli system ping + Conferma che versionCheck.status e match (la CLI e il bridge usano la stessa versione). +9. Se un passaggio fallisce, esegui: unity-cli doctor --output json Riporta il codice diagnosis e segui il suo suggerimento prima di riprovare. ``` diff --git a/README.ja.md b/README.ja.md index fa364d15..e8451c8e 100644 --- a/README.ja.md +++ b/README.ja.md @@ -33,32 +33,51 @@ Bridge の最小バージョンは Unity 2022.3 です。macOS 検証対象は [対応表の検証日・結果](docs/editor-compatibility.md)を確認してください。 6000.7 の Editor は Mono で動作し、CoreCLR Player ビルドはこの検証の対象外です。 -### LLM エージェントでインストール +### LLM エージェントでインストール・更新 Unity プロジェクトで開いた Claude Code や Codex などのコーディングエージェントに、 -次のプロンプトをそのまま貼り付けてください: +次のプロンプトをそのまま貼り付けてください。後から同じプロンプトを再実行すると、CLI と +Unity 側の bridge パッケージをまとめて更新できます: ```text -この Unity プロジェクトに unity-cli をインストールし、Unity Editor と接続してください。 +この Unity プロジェクトに unity-cli をインストールまたは更新し、Unity 側の bridge パッケージを +CLI と同じバージョンに揃えて、Unity Editor と接続してください。 1. OS(macOS / Linux / Windows)を判定してください。 2. `unity-cli` が PATH 上にない場合は、公式のクイックインストールスクリプトを実行してください: - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh - Windows(PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex -3. PATH から `unity-cli --version` が実行できることを確認してください。macOS / Linux で +3. `unity-cli` がすでに PATH 上にある場合は、代わりに最新リリースへ更新してください。 + UNITY_CLI_NO_AUTO_UPDATE=1 または UNITY_CLI_VERSION が設定されている場合は、私が意図的に + バージョンを固定しています。更新せず、私に伝えて確認を取ってください。それ以外の場合は、 + バイナリの実体の場所を(シンボリックリンクをたどって)確認し、導入方法に合わせて更新してください: + - クイックインストール(~/.unity/tools 配下の managed コピー): unity-cli cli install + - Homebrew: brew upgrade akiojin/tap/unity-cli + - winget: winget upgrade akiojin.unity-cli + - それ以外(cargo install や手動ダウンロード): 導入方法を私に伝え、変更前に確認を取ってください。 +4. PATH から `unity-cli --version` が実行できることを確認してください。macOS / Linux で 見つからない場合は、このシェルの PATH に ~/.local/bin を追加し、シェルプロファイルに 追記する行を教えてください。Windows では、更新されたユーザー PATH を反映するため 新しいシェルを開いてください。 -4. プロジェクトを変更する前に、setup が Packages/manifest.json を編集すること +5. プロジェクトを変更する前に、setup が Packages/manifest.json を編集すること (OpenUPM の scoped registry と、CLI と同じバージョンに固定した com.akiojin.unity-cli-bridge を追加すること)と、旧 Input Manager のみのプロジェクトでは ProjectSettings/ProjectSettings.asset の activeInputHandler を Both に設定することを 説明し、私の確認を待ってください。 -5. Unity プロジェクトのルートで次を実行してください: unity-cli --output json setup --launch-editor +6. Unity プロジェクトのルートで次を実行してください: unity-cli --output json setup --launch-editor JSON が ok: false の場合は editor.hint に従ってください(初回インポートは数分かかる ことがあります。待ち続けるには setup を再実行します)。 -6. 次のコマンドで接続を確認してください: unity-cli system ping -7. いずれかの手順が失敗した場合は、次を実行してください: unity-cli doctor --output json +7. 次のコマンドで bridge のバージョンを確認してください: unity-cli --output json bridge status + - source が registry で、versionCheck.status(この結果または setup の結果)が mismatch の場合: + Packages/manifest.json の com.akiojin.unity-cli-bridge の行を CLI のバージョンに変更することを + 私に伝え、確認を待ってください。その後 unity-cli bridge upgrade を実行し、 + Unity Editor にパッケージを再インポートさせてください。 + - source が custom または embedded(Git URL、ローカルパス、Packages/ 配下のコピー)の場合や、 + versionCheck.status が unknown の場合: 書き換えないでください。代わりに source と + 両方のバージョンを私に報告してください。 +8. 次のコマンドで接続を確認してください: unity-cli system ping + versionCheck.status が match(CLI と bridge が同じバージョン)であることを確認してください。 +9. いずれかの手順が失敗した場合は、次を実行してください: unity-cli doctor --output json diagnosis コードを報告し、そのヒントに従ってから再試行してください。 ``` diff --git a/README.md b/README.md index d8eb0926..418c4cca 100644 --- a/README.md +++ b/README.md @@ -46,30 +46,53 @@ The Bridge requires Unity 2022.3 or newer. The macOS matrix covers [verification dates and results](docs/editor-compatibility.md) before choosing a version. Unity 6000.7 Editor runs on Mono; CoreCLR Player builds are outside this matrix. -### Install with an LLM agent +### Install or update with an LLM agent Copy this prompt into Claude Code, Codex, or another coding agent opened in -your Unity project: +your Unity project. Run the same prompt again later to update the CLI and the +Unity bridge package together: ```text -Install unity-cli for this Unity project and connect it to the Unity Editor. +Install or update unity-cli for this Unity project, keep the Unity bridge +package on the same version as the CLI, and connect it to the Unity Editor. 1. Detect my OS (macOS, Linux, or Windows). 2. If `unity-cli` is not already on PATH, run the official Quick Install script: - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh - Windows (PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex -3. Check that `unity-cli --version` works from PATH. On macOS / Linux, if it is +3. If `unity-cli` is already on PATH, update it to the latest release instead. + If UNITY_CLI_NO_AUTO_UPDATE=1 or UNITY_CLI_VERSION is set, I pinned the + version on purpose: do not update it; tell me and ask first. Otherwise + resolve where the binary really lives (follow symlinks) and update it the + way it was installed: + - Quick Install (managed copy under ~/.unity/tools): unity-cli cli install + - Homebrew: brew upgrade akiojin/tap/unity-cli + - winget: winget upgrade akiojin.unity-cli + - Anything else (cargo install, manual download): tell me how it was + installed and ask before changing it. +4. Check that `unity-cli --version` works from PATH. On macOS / Linux, if it is not found, add ~/.local/bin to PATH for this shell and tell me the line to add to my shell profile. On Windows, open a new shell so the updated user PATH applies. -4. Before changing my project, tell me that setup edits Packages/manifest.json +5. Before changing my project, tell me that setup edits Packages/manifest.json (adds the OpenUPM scoped registry and com.akiojin.unity-cli-bridge pinned to the CLI version) and, for legacy-input-only projects, sets activeInputHandler to Both in ProjectSettings/ProjectSettings.asset. Wait for my confirmation. -5. From the Unity project root, run: unity-cli --output json setup --launch-editor +6. From the Unity project root, run: unity-cli --output json setup --launch-editor If the JSON has ok: false, follow editor.hint (the first import can take several minutes; rerun setup to keep waiting). -6. Verify the connection with: unity-cli system ping -7. If any step fails, run: unity-cli doctor --output json +7. Check the bridge version with: unity-cli --output json bridge status + - If source is registry and versionCheck.status (here or in the setup + report) is mismatch: tell me that this changes the + com.akiojin.unity-cli-bridge line in Packages/manifest.json to the CLI + version and wait for my confirmation. Then run: unity-cli bridge upgrade + and let the Unity Editor reimport the package. + - If source is custom or embedded (Git URL, local path, or a copy under + Packages/), or versionCheck.status is unknown: do not rewrite it. Report + the source and both versions to me instead. +8. Verify the connection with: unity-cli system ping + Confirm that versionCheck.status is match (the CLI and the bridge use the + same version). +9. If any step fails, run: unity-cli doctor --output json Report the diagnosis code and follow its hint before retrying. ``` diff --git a/README.zh.md b/README.zh.md index 23ddd234..fa5ae937 100644 --- a/README.zh.md +++ b/README.zh.md @@ -32,29 +32,46 @@ Bridge 要求 Unity 2022.3 或更高版本。macOS 验证矩阵覆盖 选择版本前请查看[验证日期与结果](docs/editor-compatibility.md)。 Unity 6000.7 的 Editor 运行在 Mono 上,CoreCLR Player 构建不在此矩阵范围内。 -### 使用 LLM 代理安装 +### 使用 LLM 代理安装或更新 -在 Unity 项目中打开 Claude Code、Codex 或其他编码代理,然后直接粘贴以下提示词: +在 Unity 项目中打开 Claude Code、Codex 或其他编码代理,然后直接粘贴以下提示词。之后再次运行 +同一提示词,即可同时更新 CLI 和 Unity 端的 bridge 包: ```text -请为这个 Unity 项目安装 unity-cli,并将其连接到 Unity Editor。 +请为这个 Unity 项目安装或更新 unity-cli,让 Unity 端的 bridge 包与 CLI 保持相同版本, +并将其连接到 Unity Editor。 1. 判断我的操作系统(macOS、Linux 或 Windows)。 2. 如果 PATH 中还没有 `unity-cli`,运行官方快速安装脚本: - macOS / Linux: curl -fsSL https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.sh | sh - Windows(PowerShell): irm https://raw.githubusercontent.com/akiojin/unity-cli/main/scripts/install.ps1 | iex -3. 确认可以从 PATH 运行 `unity-cli --version`。在 macOS / Linux 上如果找不到, +3. 如果 `unity-cli` 已在 PATH 中,请改为将其更新到最新版本。 + 如果设置了 UNITY_CLI_NO_AUTO_UPDATE=1 或 UNITY_CLI_VERSION,说明我有意固定了版本: + 不要更新,先告诉我并征得我的确认。否则,请找出二进制文件的实际位置(跟随符号链接), + 并按照安装方式进行更新: + - Quick Install(~/.unity/tools 下的 managed 副本): unity-cli cli install + - Homebrew: brew upgrade akiojin/tap/unity-cli + - winget: winget upgrade akiojin.unity-cli + - 其他方式(cargo install、手动下载): 告诉我安装方式,并在修改前征得我的确认。 +4. 确认可以从 PATH 运行 `unity-cli --version`。在 macOS / Linux 上如果找不到, 请把 ~/.local/bin 加入当前 shell 的 PATH,并告诉我需要写入 shell 配置文件的那一行。 在 Windows 上,请打开新的 shell 以应用更新后的用户 PATH。 -4. 修改项目之前,请告诉我 setup 会编辑 Packages/manifest.json(添加 OpenUPM +5. 修改项目之前,请告诉我 setup 会编辑 Packages/manifest.json(添加 OpenUPM scoped registry 以及固定为 CLI 同版本的 com.akiojin.unity-cli-bridge),并且对于 只使用旧 Input Manager 的项目,会把 ProjectSettings/ProjectSettings.asset 中的 activeInputHandler 设为 Both。等待我的确认。 -5. 在 Unity 项目根目录运行: unity-cli --output json setup --launch-editor +6. 在 Unity 项目根目录运行: unity-cli --output json setup --launch-editor 如果 JSON 返回 ok: false,请按照 editor.hint 处理(首次导入可能需要几分钟; 重新运行 setup 可继续等待)。 -6. 使用以下命令确认连接: unity-cli system ping -7. 如果任何步骤失败,请运行: unity-cli doctor --output json +7. 使用以下命令检查 bridge 版本: unity-cli --output json bridge status + - 如果 source 为 registry,且 versionCheck.status(此结果或 setup 报告中)为 mismatch: + 告诉我这会把 Packages/manifest.json 中 com.akiojin.unity-cli-bridge 这一行改为 CLI 版本, + 并等待我的确认。然后运行 unity-cli bridge upgrade,并让 Unity Editor 重新导入该包。 + - 如果 source 为 custom 或 embedded(Git URL、本地路径或 Packages/ 下的副本), + 或 versionCheck.status 为 unknown: 不要改写它,而是向我报告 source 和两个版本。 +8. 使用以下命令验证连接: unity-cli system ping + 确认 versionCheck.status 为 match(CLI 与 bridge 版本相同)。 +9. 如果任何步骤失败,请运行: unity-cli doctor --output json 报告 diagnosis 代码,并按照其提示处理后再重试。 ``` diff --git a/tests/scripts/test_readme_install.py b/tests/scripts/test_readme_install.py index 8b1df67c..788ce414 100644 --- a/tests/scripts/test_readme_install.py +++ b/tests/scripts/test_readme_install.py @@ -16,6 +16,29 @@ 'Packages/manifest.json', ] +UPDATE_STEPS = [ + 'UNITY_CLI_NO_AUTO_UPDATE', + 'UNITY_CLI_VERSION', + 'unity-cli cli install', + 'brew upgrade akiojin/tap/unity-cli', + 'winget upgrade akiojin.unity-cli', +] + +BRIDGE_STEPS = [ + 'unity-cli --output json bridge status', + 'mismatch', + 'unity-cli bridge upgrade', + 'custom', + 'unknown', +] + +# Heading words that say "install or update" in each README language. +UPDATE_HEADINGS = { + 'README.md': 'update', 'README.ja.md': '更新', 'README.zh.md': '更新', + 'README.de.md': 'aktualisier', 'README.es.md': 'actualiz', + 'README.fr.md': 'a jour', 'README.it.md': 'aggiorna', +} + MANUAL_CONTENT = [ 'scripts/install.sh | sh', 'scripts/install.ps1 | iex', @@ -79,6 +102,31 @@ def test_llm_section_has_single_prompt_with_all_steps(self): self.assertIn('/plugin marketplace add akiojin/unity-cli', llm) self.assertIn('.agents/skills/', llm) + def test_llm_prompt_updates_cli_and_bridge(self): + for name in READMES: + with self.subTest(readme=name): + title, llm = subsections(getting_started((ROOT / name).read_text()))[1] + self.assertIn(UPDATE_HEADINGS[name], title.lower()) + prompt = re.findall(r'^```text\n(.*?)^```', llm, + flags=re.MULTILINE | re.DOTALL)[0] + self.assertIn(UPDATE_HEADINGS[name], prompt.splitlines()[0].lower()) + for needle in UPDATE_STEPS + BRIDGE_STEPS: + self.assertIn(needle, prompt, needle) + setup = prompt.find('unity-cli --output json setup --launch-editor') + ping = prompt.find('unity-cli system ping') + # CLI update happens before setup; pinned versions are checked first + self.assertLess(prompt.find('UNITY_CLI_NO_AUTO_UPDATE'), + prompt.find('unity-cli cli install')) + self.assertLess(prompt.find('winget upgrade'), setup) + # bridge alignment runs between setup and the final ping + status = prompt.find('unity-cli --output json bridge status') + upgrade = prompt.find('unity-cli bridge upgrade') + self.assertTrue(setup < status < upgrade < ping) + # upgrade asks before touching the manifest + self.assertIn('Packages/manifest.json', prompt[status:upgrade]) + # the final ping confirms versionCheck is match + self.assertRegex(prompt[ping:], r'versionCheck\.status[^\n]*match') + def test_manual_section_keeps_every_install_path(self): for name in READMES: with self.subTest(readme=name): From b506174d361ca1aa39ae9737a5e10c1ef119188f Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 16:08:32 +0900 Subject: [PATCH 22/73] fix(skills): route C# script creation and fixes through the LSP write tools - create_class now renders its template and writes it through the same LSP path as create_csharp_file instead of fs::write (args and the success/path/content output keys are unchanged; LSP fields are added) - unity-csharp-edit guidance, references, and unity-helper agent now name create_csharp_file as the canonical new-file tool - add MonoBehaviour / ScriptableObject / class / new script / compile error triggers to unity-csharp-edit - runtime checklists fix SAFE_MODE compile errors with LSP write tools - routing benchmark: SR-072 expects create_csharp_file; add CS488 cases Refs #488 Co-Authored-By: Claude Opus 5.5 --- .../plugins/unity-cli/agents/unity-helper.md | 2 +- .../references/runtime-checklist.md | 2 +- .../references/runtime-checklist.md | 2 +- .../references/runtime-checklist.md | 2 +- .../skills/unity-csharp-edit/SKILL.md | 17 ++- .../references/file-write-recipes.md | 6 +- .../references/lsp-write-safety.md | 12 ++- .../references/runtime-checklist.md | 2 +- .../references/runtime-checklist.md | 2 +- .../references/runtime-checklist.md | 2 +- .../references/runtime-checklist.md | 2 +- .../references/runtime-checklist.md | 2 +- scripts/skill-eval/run-codex-routing.py | 10 +- src/tooling/local_tools.rs | 100 ++++++++---------- tests/csharp_post_write.rs | 35 ++++++ tests/fixtures/skill-routing/benchmark.jsonl | 7 +- tests/scripts/test_skill_routing.py | 15 +++ 17 files changed, 145 insertions(+), 75 deletions(-) diff --git a/.claude-plugin/plugins/unity-cli/agents/unity-helper.md b/.claude-plugin/plugins/unity-cli/agents/unity-helper.md index a9db29d9..4492bc6c 100644 --- a/.claude-plugin/plugins/unity-cli/agents/unity-helper.md +++ b/.claude-plugin/plugins/unity-cli/agents/unity-helper.md @@ -32,7 +32,7 @@ You are a Unity automation specialist. Execute multi-step workflows using `unity ### Code Scaffold -1. Create class with `create_class` or `create_csharp_file` → update code with `write_csharp_file` or `apply_csharp_edits` → build or update index → check compilation state +1. Create the script with `create_csharp_file` (LSP-validated; `create_class` is only an empty-class shortcut on the same LSP path) → update code with `write_csharp_file`, `apply_csharp_edits`, or symbol edits → build or update index → check compilation state → fix compile errors with the same LSP write tools, never with direct file edits ### Test Cycle diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-2d-sprite-tilemap/references/runtime-checklist.md b/.claude-plugin/plugins/unity-cli/skills/unity-2d-sprite-tilemap/references/runtime-checklist.md index f4c50a8f..6765fc38 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-2d-sprite-tilemap/references/runtime-checklist.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-2d-sprite-tilemap/references/runtime-checklist.md @@ -35,7 +35,7 @@ - A failed `system ping` does not prove the Editor is closed. Run `unity-cli doctor --output json` (add `--project-path ` outside the project) before any fallback such as hand-editing YAML. - Act on the `diagnosis` code: - - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) by editing the file directly, then let Unity recompile or restart the Editor. + - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) with the LSP write tools (`apply_csharp_edits`, `replace_symbol_body`, `write_csharp_file`); they run locally and do not need the bridge. Then let Unity recompile or restart the Editor. - `BRIDGE_NOT_INSTALLED`: run `unity-cli setup` (or `unity-cli bridge install`) to add `com.akiojin.unity-cli-bridge` to `Packages/manifest.json`. - `PORT_IN_USE`: `port.listenerPid` / `port.listenerProcess` hold the port. Stop it or change the bridge port and pass the same `--port`. - `EDITOR_NOT_RUNNING`: start the Editor for the project and wait for import to finish. diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-audio-setup/references/runtime-checklist.md b/.claude-plugin/plugins/unity-cli/skills/unity-audio-setup/references/runtime-checklist.md index f4c50a8f..6765fc38 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-audio-setup/references/runtime-checklist.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-audio-setup/references/runtime-checklist.md @@ -35,7 +35,7 @@ - A failed `system ping` does not prove the Editor is closed. Run `unity-cli doctor --output json` (add `--project-path ` outside the project) before any fallback such as hand-editing YAML. - Act on the `diagnosis` code: - - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) by editing the file directly, then let Unity recompile or restart the Editor. + - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) with the LSP write tools (`apply_csharp_edits`, `replace_symbol_body`, `write_csharp_file`); they run locally and do not need the bridge. Then let Unity recompile or restart the Editor. - `BRIDGE_NOT_INSTALLED`: run `unity-cli setup` (or `unity-cli bridge install`) to add `com.akiojin.unity-cli-bridge` to `Packages/manifest.json`. - `PORT_IN_USE`: `port.listenerPid` / `port.listenerProcess` hold the port. Stop it or change the bridge port and pass the same `--port`. - `EDITOR_NOT_RUNNING`: start the Editor for the project and wait for import to finish. diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-cli-usage/references/runtime-checklist.md b/.claude-plugin/plugins/unity-cli/skills/unity-cli-usage/references/runtime-checklist.md index 059c7bb3..159db7d7 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-cli-usage/references/runtime-checklist.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-cli-usage/references/runtime-checklist.md @@ -52,7 +52,7 @@ completion and inspect that call's exit code. - A failed `system ping` does not prove the Editor is closed. Run `unity-cli doctor --output json` (add `--project-path ` outside the project) before any fallback such as hand-editing YAML. - Act on the `diagnosis` code: - - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) by editing the file directly, then let Unity recompile or restart the Editor. + - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) with the LSP write tools (`apply_csharp_edits`, `replace_symbol_body`, `write_csharp_file`); they run locally and do not need the bridge. Then let Unity recompile or restart the Editor. - `BRIDGE_NOT_INSTALLED`: run `unity-cli setup` (or `unity-cli bridge install`) to add `com.akiojin.unity-cli-bridge` to `Packages/manifest.json`. - `PORT_IN_USE`: `port.listenerPid` / `port.listenerProcess` hold the port. Stop it or change the bridge port and pass the same `--port`. - `EDITOR_NOT_RUNNING`: start the Editor for the project and wait for import to finish. diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md index 81398193..e1fdbd0d 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md @@ -1,14 +1,19 @@ --- name: unity-csharp-edit -description: Implement, fix, and refactor Unity C# code with unity-cli write tools. Use when the user wants to change behavior in .cs files, create or rewrite scripts, update multiple C# files together, rename a symbol, add or remove members, or change project or package settings as part of a code change. Do not use for read-only inspection with no planned edit; use `unity-csharp-navigate` instead. +description: Implement, fix, and refactor Unity C# code with unity-cli write tools. Use when the user wants to change behavior in .cs files, create a new script, class, MonoBehaviour or ScriptableObject, rewrite scripts, fix compile errors, update multiple C# files together, rename a symbol, add or remove members, or change project or package settings as part of a code change. Do not use for read-only inspection with no planned edit; use `unity-csharp-navigate` instead. allowed-tools: Bash(unity-cli:*), Read, Grep, Glob, Edit, Write metadata: author: akiojin - version: 0.3.0 + version: 0.3.1 category: code triggers: - csharp - script + - new script + - class + - monobehaviour + - scriptableobject + - compile error - rename - refactor - symbol @@ -31,7 +36,8 @@ Implement Unity C# changes with `unity-cli` as the primary write path. Prefer th ## Use When - The user intends to change C# behavior in `.cs` files. -- The user wants to create or rewrite scripts (single or coordinated multi-file). +- The user wants to create a new script, class, `MonoBehaviour`, or `ScriptableObject`, or rewrite scripts (single or coordinated multi-file). +- The user wants to fix C# compile errors. - The user asks for a symbol rename, member add/remove, or refactor. - The user changes project or package settings as part of a code change. @@ -44,13 +50,14 @@ Implement Unity C# changes with `unity-cli` as the primary write path. Prefer th ## Preferred Flow -1. Decide the write shape: symbol edit, full-file write, multi-file write, or settings change. +1. Decide the write shape: new file, symbol edit, full-file write, multi-file write, or settings change. Always write `.cs` files through the LSP write tools (`create_csharp_file`, `write_csharp_file`, `apply_csharp_edits`, symbol edits) so the text is validated before it lands; do not hand-write `.cs` files with direct file edits. 2. Read only the minimum context with `read`, `get_symbols`, `find_symbol`, or `find_refs`. 3. Preview risky symbol edits with `apply: false`. 4. Apply with `refresh`, `waitForCompile`, and `updateIndex` when later steps depend on clean diagnostics. 5. Inspect `changedFiles`, `changedSymbols`, and `diagnostics`; fix compilation issues before unrelated follow-up. ```bash +unity-cli raw create_csharp_file --json '{"relative":"Assets/Scripts/EnemyAI.cs","text":"using UnityEngine;\n\npublic class EnemyAI : MonoBehaviour\n{\n}\n","validate":true,"apply":true,"waitForCompile":true,"updateIndex":true}' unity-cli raw get_symbols --json '{"path":"Assets/Scripts/Player.cs"}' unity-cli raw rename_symbol --json '{"relative":"Assets/Scripts/Player.cs","namePath":"Player/Jump","newName":"Leap","apply":false}' unity-cli raw apply_csharp_edits --json '{"files":[{"relative":"Assets/Scripts/IPlayerMover.cs","newText":"public interface IPlayerMover { void Move(); }\n"}],"validate":true,"apply":true,"waitForCompile":true,"updateIndex":true}' @@ -60,6 +67,8 @@ unity-cli raw get_compilation_state --json '{}' ## Examples - "Implement dash cooldown in `PlayerController.cs` and update the related tests." +- "Create an `EnemyAI` MonoBehaviour in `Assets/Scripts/AI`." +- "Fix the compile error in `PlayerController.cs`." - "Rename `Jump` to `Leap` across the player package without breaking serialized field names." - "Create a new editor utility script and change the matching project setting." - "Refactor an interface, its implementation, and the tests in one coordinated write." diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/file-write-recipes.md b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/file-write-recipes.md index ee3621e6..756803b4 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/file-write-recipes.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/file-write-recipes.md @@ -32,11 +32,10 @@ Recommended options: ## Choose `create_csharp_file` When -- You need a new file that is not just a standard class shell. -- The file should contain an interface, enum, test fixture, editor utility, or multiple types. +- You need any new `.cs` file: a class, `MonoBehaviour`, `ScriptableObject`, interface, enum, test fixture, editor utility, or multiple types. - You want the same validated write contract as `write_csharp_file`. -Use `create_class` only when the class template itself is the useful shortcut. +`create_class` is a shortcut for an empty class shell (`name`, `folder`, optional `namespace` / `inherits`). It writes through the same LSP path as `create_csharp_file`, so both are safe; prefer `create_csharp_file` when the file needs members. ## Choose `apply_csharp_edits` When @@ -56,6 +55,7 @@ Keep the `files` array minimal and coherent. If files are unrelated, split the t ## Example Paths ```bash +unity-cli raw create_csharp_file --json '{"relative":"Assets/Scripts/EnemyAI.cs","text":"using UnityEngine;\n\npublic class EnemyAI : MonoBehaviour\n{\n}\n","validate":true,"apply":true,"waitForCompile":true,"updateIndex":true}' unity-cli raw replace_symbol_body --json '{"relative":"Assets/Scripts/PlayerController.cs","namePath":"PlayerController/Move","body":"{ transform.position += direction * speed * Time.deltaTime; }","apply":false}' unity-cli raw write_csharp_file --json '{"relative":"Assets/Scripts/PlayerController.cs","newText":"using UnityEngine;\n\npublic sealed class PlayerController : MonoBehaviour {}\n","validate":true,"apply":true,"waitForCompile":true,"updateIndex":true}' unity-cli raw apply_csharp_edits --json '{"files":[{"relative":"Assets/Scripts/IPlayerMover.cs","newText":"public interface IPlayerMover { void Move(); }\n"},{"relative":"Assets/Scripts/PlayerMover.cs","newText":"public sealed class PlayerMover : IPlayerMover { public void Move() {} }\n"},{"relative":"Assets/Tests/EditMode/PlayerMoverTests.cs","newText":"using NUnit.Framework;\n\npublic class PlayerMoverTests {}\n"}],"validate":true,"apply":true,"waitForCompile":true,"updateIndex":true}' diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/lsp-write-safety.md b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/lsp-write-safety.md index 2782701b..5ba14019 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/lsp-write-safety.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/lsp-write-safety.md @@ -25,7 +25,15 @@ 3. Run `get_compilation_state` for non-trivial edits or when diagnostics are still unclear. 4. Report and fix real diagnostics before attempting unrelated follow-up changes. -## Class Creation +## New Files -- Use `create_class` for new files instead of hand-writing boilerplate when possible. +- Use `create_csharp_file` for every new `.cs` file (classes, `MonoBehaviour`, `ScriptableObject`, interfaces, enums, tests). It validates the text through LSP before writing. +- `create_class` (`name`, `folder`, optional `namespace` / `inherits`) is a shortcut that renders an empty class shell and writes it through the same LSP path as `create_csharp_file`. Prefer `create_csharp_file` when the file needs any members. +- Do not create or edit `.cs` files with direct file writes; they skip LSP validation. - Use `validate_text_edits` when constructing larger manual replacements. + +## Compile Error Fixes + +- Read the error `file` / `line` from `get_compilation_state` or `editorLog.compileErrors[]`. +- Fix it with the smallest LSP write: `replace_symbol_body` for one member, `write_csharp_file` for one file, `apply_csharp_edits` when several files must change together. +- These tools run locally, so they work in `SAFE_MODE` when the bridge is not loaded. diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-development-loop/references/runtime-checklist.md b/.claude-plugin/plugins/unity-cli/skills/unity-development-loop/references/runtime-checklist.md index be3cb6c4..3fe6e0ff 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-development-loop/references/runtime-checklist.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-development-loop/references/runtime-checklist.md @@ -22,7 +22,7 @@ - A failed `system ping` does not prove the Editor is closed. Run `unity-cli doctor --output json` (add `--project-path ` outside the project) before any fallback such as hand-editing YAML. - Act on the `diagnosis` code: - - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) by editing the file directly, then let Unity recompile or restart the Editor. + - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) with the LSP write tools (`apply_csharp_edits`, `replace_symbol_body`, `write_csharp_file`); they run locally and do not need the bridge. Then let Unity recompile or restart the Editor. - `BRIDGE_NOT_INSTALLED`: add `com.akiojin.unity-cli-bridge` to `Packages/manifest.json`. - `PORT_IN_USE`: `port.listenerPid` / `port.listenerProcess` hold the port. Stop it or change the bridge port and pass the same `--port`. - `EDITOR_NOT_RUNNING`: start the Editor for the project and wait for import to finish. diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-localization/references/runtime-checklist.md b/.claude-plugin/plugins/unity-cli/skills/unity-localization/references/runtime-checklist.md index f4c50a8f..6765fc38 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-localization/references/runtime-checklist.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-localization/references/runtime-checklist.md @@ -35,7 +35,7 @@ - A failed `system ping` does not prove the Editor is closed. Run `unity-cli doctor --output json` (add `--project-path ` outside the project) before any fallback such as hand-editing YAML. - Act on the `diagnosis` code: - - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) by editing the file directly, then let Unity recompile or restart the Editor. + - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) with the LSP write tools (`apply_csharp_edits`, `replace_symbol_body`, `write_csharp_file`); they run locally and do not need the bridge. Then let Unity recompile or restart the Editor. - `BRIDGE_NOT_INSTALLED`: run `unity-cli setup` (or `unity-cli bridge install`) to add `com.akiojin.unity-cli-bridge` to `Packages/manifest.json`. - `PORT_IN_USE`: `port.listenerPid` / `port.listenerProcess` hold the port. Stop it or change the bridge port and pass the same `--port`. - `EDITOR_NOT_RUNNING`: start the Editor for the project and wait for import to finish. diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-project-bootstrap/references/runtime-checklist.md b/.claude-plugin/plugins/unity-cli/skills/unity-project-bootstrap/references/runtime-checklist.md index 9a43d936..b0bc30bf 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-project-bootstrap/references/runtime-checklist.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-project-bootstrap/references/runtime-checklist.md @@ -35,7 +35,7 @@ - A failed `system ping` does not prove the Editor is closed. Run `unity-cli doctor --output json` (add `--project-path ` outside the project) before any fallback such as hand-editing YAML. - Act on the `diagnosis` code: - - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) by editing the file directly, then let Unity recompile or restart the Editor. + - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) with the LSP write tools (`apply_csharp_edits`, `replace_symbol_body`, `write_csharp_file`); they run locally and do not need the bridge. Then let Unity recompile or restart the Editor. - `BRIDGE_NOT_INSTALLED`: run `unity-cli setup` (or `unity-cli bridge install`) to add `com.akiojin.unity-cli-bridge` to `Packages/manifest.json`. - `PORT_IN_USE`: `port.listenerPid` / `port.listenerProcess` hold the port. Stop it or change the bridge port and pass the same `--port`. - `EDITOR_NOT_RUNNING`: start the Editor for the project and wait for import to finish. diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-ui-toolkit-build/references/runtime-checklist.md b/.claude-plugin/plugins/unity-cli/skills/unity-ui-toolkit-build/references/runtime-checklist.md index f4c50a8f..6765fc38 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-ui-toolkit-build/references/runtime-checklist.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-ui-toolkit-build/references/runtime-checklist.md @@ -35,7 +35,7 @@ - A failed `system ping` does not prove the Editor is closed. Run `unity-cli doctor --output json` (add `--project-path ` outside the project) before any fallback such as hand-editing YAML. - Act on the `diagnosis` code: - - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) by editing the file directly, then let Unity recompile or restart the Editor. + - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) with the LSP write tools (`apply_csharp_edits`, `replace_symbol_body`, `write_csharp_file`); they run locally and do not need the bridge. Then let Unity recompile or restart the Editor. - `BRIDGE_NOT_INSTALLED`: run `unity-cli setup` (or `unity-cli bridge install`) to add `com.akiojin.unity-cli-bridge` to `Packages/manifest.json`. - `PORT_IN_USE`: `port.listenerPid` / `port.listenerProcess` hold the port. Stop it or change the bridge port and pass the same `--port`. - `EDITOR_NOT_RUNNING`: start the Editor for the project and wait for import to finish. diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-urp-setup/references/runtime-checklist.md b/.claude-plugin/plugins/unity-cli/skills/unity-urp-setup/references/runtime-checklist.md index f4c50a8f..6765fc38 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-urp-setup/references/runtime-checklist.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-urp-setup/references/runtime-checklist.md @@ -35,7 +35,7 @@ - A failed `system ping` does not prove the Editor is closed. Run `unity-cli doctor --output json` (add `--project-path ` outside the project) before any fallback such as hand-editing YAML. - Act on the `diagnosis` code: - - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) by editing the file directly, then let Unity recompile or restart the Editor. + - `SAFE_MODE` / `COMPILE_ERRORS`: the bridge is not loaded. Fix each `editorLog.compileErrors[]` entry (`file`, `line`, `code`) with the LSP write tools (`apply_csharp_edits`, `replace_symbol_body`, `write_csharp_file`); they run locally and do not need the bridge. Then let Unity recompile or restart the Editor. - `BRIDGE_NOT_INSTALLED`: run `unity-cli setup` (or `unity-cli bridge install`) to add `com.akiojin.unity-cli-bridge` to `Packages/manifest.json`. - `PORT_IN_USE`: `port.listenerPid` / `port.listenerProcess` hold the port. Stop it or change the bridge port and pass the same `--port`. - `EDITOR_NOT_RUNNING`: start the Editor for the project and wait for import to finish. diff --git a/scripts/skill-eval/run-codex-routing.py b/scripts/skill-eval/run-codex-routing.py index 52335633..40435290 100644 --- a/scripts/skill-eval/run-codex-routing.py +++ b/scripts/skill-eval/run-codex-routing.py @@ -462,8 +462,14 @@ def has_any(*terms: str) -> bool: return make_prediction(["unity-csharp-edit"], "validate_text_edits", ["relative", "newText"]) if has_any("play検証はまだ不要") and has_any(".cs") and has_any("実装したい"): return make_prediction(["unity-csharp-edit"], "write_csharp_file", ["relative", "newText"]) - if has_any("クラス") and has_any("assets/") and has_any("作りたい", "新規作成"): - return make_prediction(["unity-csharp-edit"], "create_class", ["name", "folder"]) + if has_any("コンパイルエラー", "compile error") and has_any("直", "修正", "fix"): + return make_prediction(["unity-csharp-edit"], "apply_csharp_edits", ["files"]) + if ( + has_any("クラス", "monobehaviour", "scriptableobject", "c# script") + and has_any("assets/") + and has_any("作りたい", "新規作成", "create", "write") + ): + return make_prediction(["unity-csharp-edit"], "create_csharp_file", ["relative", "text"]) if has_any("ゲームパッド") and has_any("ボタン"): return make_prediction(["unity-playmode-testing"], "input_gamepad", ["action", "button", "buttonAction"]) if has_any("play") and has_any("space") and has_any("スクリーンショット"): diff --git a/src/tooling/local_tools.rs b/src/tooling/local_tools.rs index cb5e4293..d2b47c14 100644 --- a/src/tooling/local_tools.rs +++ b/src/tooling/local_tools.rs @@ -943,6 +943,24 @@ fn local_create_class(params: &Value) -> Result { return Err(anyhow!("File already exists: {rel_path}")); } + let body = render_class_template(name, namespace, inherits); + + // Write through the same LSP path as `create_csharp_file` so the generated + // class is validated and the post-write pipeline sees an LSP result. + let mut result = local_lsp_write( + "create_csharp_file", + &json!({ + "relative": rel_path, + "text": body, + "overwrite": false + }), + )?; + result["path"] = json!(rel_path); + result["content"] = json!(body); + Ok(result) +} + +fn render_class_template(name: &str, namespace: Option<&str>, inherits: Option<&str>) -> String { let mut body = String::new(); if requires_unityengine_using(inherits) { body.push_str("using UnityEngine;\n\n"); @@ -963,17 +981,7 @@ fn local_create_class(params: &Value) -> Result { body.push_str("}\n"); } - if let Some(parent) = abs_path.parent() { - fs::create_dir_all(parent) - .with_context(|| format!("Failed to create directory: {}", parent.display()))?; - } - fs::write(&abs_path, &body).with_context(|| format!("Failed to write file: {rel_path}"))?; - - Ok(json!({ - "success": true, - "path": rel_path, - "content": body - })) + body } fn project_root() -> Result { @@ -1513,7 +1521,7 @@ mod tests { use super::{ build_snippet, collect_cs_files, extract_symbols_from_text, index_is_ready, index_not_ready_response, maybe_execute_local_tool, normalize_rel_or_abs_path, - normalize_rel_path, path_matches_scope, requires_unityengine_using, + normalize_rel_path, path_matches_scope, render_class_template, requires_unityengine_using, resolve_candidate_project_path, strip_csharp_comments, symbol_name_matches, IndexedFile, SymbolIndex, }; @@ -1829,56 +1837,19 @@ mod tests { } #[test] - fn create_class_generates_simple_class() { - let _guard = env_lock().lock().expect("lock should succeed"); - let tmp = tempfile::tempdir().expect("temp dir should be created"); - std::env::set_var("UNITY_PROJECT_ROOT", tmp.path()); - - let value = maybe_execute_local_tool( - "create_class", - &json!({"name":"EnemyAI","folder":"Assets/Scripts/AI"}), - ) - .expect("tool should be handled") - .expect("create_class should succeed"); - - assert_eq!(value["success"], true); - assert_eq!(value["path"], "Assets/Scripts/AI/EnemyAI.cs"); - let content = value["content"].as_str().expect("content should be string"); + fn create_class_template_generates_simple_class() { + let content = render_class_template("EnemyAI", None, None); assert!(!content.contains("using UnityEngine;")); assert!(content.contains("public class EnemyAI")); - - let file_content = std::fs::read_to_string(tmp.path().join("Assets/Scripts/AI/EnemyAI.cs")) - .expect("file should exist"); - assert_eq!(file_content, content); - - std::env::remove_var("UNITY_PROJECT_ROOT"); } #[test] - fn create_class_with_namespace_and_inherits() { - let _guard = env_lock().lock().expect("lock should succeed"); - let tmp = tempfile::tempdir().expect("temp dir should be created"); - std::env::set_var("UNITY_PROJECT_ROOT", tmp.path()); - - let value = maybe_execute_local_tool( - "create_class", - &json!({ - "name": "Player", - "namespace": "Game.Characters", - "inherits": "MonoBehaviour", - "folder": "Assets/Scripts" - }), - ) - .expect("tool should be handled") - .expect("create_class should succeed"); - - assert_eq!(value["success"], true); - let content = value["content"].as_str().expect("content should be string"); + fn create_class_template_with_namespace_and_inherits() { + let content = + render_class_template("Player", Some("Game.Characters"), Some("MonoBehaviour")); assert!(content.contains("namespace Game.Characters")); assert!(content.contains("using UnityEngine;")); assert!(content.contains("public class Player : MonoBehaviour")); - - std::env::remove_var("UNITY_PROJECT_ROOT"); } #[test] @@ -2125,4 +2096,25 @@ namespace Demo.Game std::env::remove_var("UNITY_PROJECT_ROOT"); std::env::remove_var("UNITY_CLI_LSP_MODE"); } + + #[test] + fn create_class_requires_lsp_and_does_not_write_directly() { + let _guard = env_lock().lock().expect("lock should succeed"); + let tmp = tempfile::tempdir().expect("temp dir should be created"); + std::env::set_var("UNITY_PROJECT_ROOT", tmp.path()); + std::env::set_var("UNITY_CLI_LSP_MODE", "off"); + + let result = maybe_execute_local_tool( + "create_class", + &json!({"name":"EnemyAI","folder":"Assets/Scripts/AI"}), + ) + .expect("tool should be handled"); + + assert!(result.is_err(), "create_class should fail when LSP is off"); + assert!(result.unwrap_err().to_string().contains("requires LSP")); + assert!(!tmp.path().join("Assets/Scripts/AI/EnemyAI.cs").exists()); + + std::env::remove_var("UNITY_PROJECT_ROOT"); + std::env::remove_var("UNITY_CLI_LSP_MODE"); + } } diff --git a/tests/csharp_post_write.rs b/tests/csharp_post_write.rs index 4b3434b1..16a6aa95 100644 --- a/tests/csharp_post_write.rs +++ b/tests/csharp_post_write.rs @@ -241,3 +241,38 @@ fn post_write_tools_use_explicit_endpoint_and_include_compile_results() { assert_eq!(requests[2]["params"]["includeMessages"], true); } } + +#[test] +fn create_class_writes_through_lsp_and_keeps_output_shape() { + let fixture = Fixture::new(); + let response = fixture.call( + "create_class", + &json!({ + "name": "EnemyAI", + "namespace": "Game.AI", + "inherits": "MonoBehaviour", + "folder": "Assets/Scripts/AI" + }), + 1, + ); + assert_eq!(response["success"], true, "{response}"); + assert_eq!(response["backend"], "lsp", "{response}"); + assert_eq!(response["applied"], true); + assert_eq!(response["path"], "Assets/Scripts/AI/EnemyAI.cs"); + assert_eq!( + response["changedFiles"], + json!(["Assets/Scripts/AI/EnemyAI.cs"]) + ); + let content = response["content"].as_str().unwrap(); + assert!(content.contains("using UnityEngine;")); + assert!(content.contains("namespace Game.AI")); + assert!(content.contains("public class EnemyAI : MonoBehaviour")); + let written = fs::read_to_string( + fixture + .root + .path() + .join("project/Assets/Scripts/AI/EnemyAI.cs"), + ) + .unwrap(); + assert_eq!(written, content); +} diff --git a/tests/fixtures/skill-routing/benchmark.jsonl b/tests/fixtures/skill-routing/benchmark.jsonl index 2a7ebc49..b85db987 100644 --- a/tests/fixtures/skill-routing/benchmark.jsonl +++ b/tests/fixtures/skill-routing/benchmark.jsonl @@ -69,7 +69,7 @@ {"id": "SR-069", "expected_skills": ["unity-csharp-edit"], "prompt": "Jumpの後に新規メソッドを追加したい", "expected_tool": "insert_after_symbol", "expected_payload_keys": ["relative", "namePath", "text"], "difficulty": "hard"} {"id": "SR-070", "expected_skills": ["unity-csharp-edit"], "prompt": "不要メンバーを参照チェック付きで削除したい", "expected_tool": "remove_symbol", "expected_payload_keys": ["relative", "namePath", "failOnReferences"], "difficulty": "hard"} {"id": "SR-071", "expected_skills": ["unity-csharp-edit"], "prompt": "newTextの文法だけ先に検証したい", "expected_tool": "validate_text_edits", "expected_payload_keys": ["relative", "newText"], "difficulty": "medium"} -{"id": "SR-072", "expected_skills": ["unity-csharp-edit"], "prompt": "EnemyAIクラスをAssets/Scripts/AIに作りたい", "expected_tool": "create_class", "expected_payload_keys": ["name", "folder"], "difficulty": "easy"} +{"id": "SR-072", "expected_skills": ["unity-csharp-edit"], "prompt": "EnemyAIクラスをAssets/Scripts/AIに作りたい", "expected_tool": "create_csharp_file", "expected_payload_keys": ["relative", "text"], "difficulty": "easy"} {"id": "SR-073", "expected_skills": ["unity-playmode-testing"], "prompt": "Play modeを開始したい", "expected_tool": "play_game", "expected_payload_keys": [], "difficulty": "easy"} {"id": "SR-074", "expected_skills": ["unity-playmode-testing"], "prompt": "Play modeを停止したい", "expected_tool": "stop_game", "expected_payload_keys": [], "difficulty": "easy"} {"id": "SR-075", "expected_skills": ["unity-playmode-testing"], "prompt": "キーボードでspaceを押したい", "expected_tool": "input_keyboard", "expected_payload_keys": ["action", "key"], "difficulty": "easy"} @@ -218,3 +218,8 @@ {"id":"AUD380-06","prompt":"Only create an empty scene called AudioTest in Assets/Scenes/Generated/E2E/. No audio assets or playback setup.","expected_skills":["unity-scene-create"],"expected_tool":"create_scene","expected_payload_keys":["sceneName","path"],"difficulty":"hard"} {"id":"AUD380-07","prompt":"Only enter Play Mode in the existing audio scene. Do not configure its AudioClip or Mixer.","expected_skills":["unity-playmode-testing"],"expected_tool":"play_game","expected_payload_keys":[],"difficulty":"hard"} {"id":"AUD380-08","prompt":"Only read the latest 20 Unity console messages to investigate audio errors; do not change any assets or source settings.","expected_skills":["unity-editor-tools"],"expected_tool":"read_console","expected_payload_keys":["count"],"difficulty":"hard"} +{"id": "CS488-01", "expected_skills": ["unity-csharp-edit"], "prompt": "Assets/Scripts/AIにEnemyAIのMonoBehaviourを作りたい", "expected_tool": "create_csharp_file", "expected_payload_keys": ["relative", "text"], "difficulty": "easy"} +{"id": "CS488-02", "expected_skills": ["unity-csharp-edit"], "prompt": "Create an EnemyAI MonoBehaviour in Assets/Scripts/AI.", "expected_tool": "create_csharp_file", "expected_payload_keys": ["relative", "text"], "difficulty": "easy"} +{"id": "CS488-03", "expected_skills": ["unity-csharp-edit"], "prompt": "Write a C# script that rotates its GameObject every frame and save it as Assets/Scripts/Rotator.cs.", "expected_tool": "create_csharp_file", "expected_payload_keys": ["relative", "text"], "difficulty": "medium"} +{"id": "CS488-04", "expected_skills": ["unity-csharp-edit"], "prompt": "PlayerController.csのコンパイルエラーを直したい", "expected_tool": "apply_csharp_edits", "expected_payload_keys": ["files"], "difficulty": "medium"} +{"id": "CS488-05", "expected_skills": ["unity-csharp-edit"], "prompt": "Fix the compile error in Assets/Scripts/PlayerController.cs.", "expected_tool": "apply_csharp_edits", "expected_payload_keys": ["files"], "difficulty": "medium"} diff --git a/tests/scripts/test_skill_routing.py b/tests/scripts/test_skill_routing.py index ab2dcb16..20f655c7 100644 --- a/tests/scripts/test_skill_routing.py +++ b/tests/scripts/test_skill_routing.py @@ -114,6 +114,21 @@ def test_asset_update_then_play_keeps_existing_route(self): self.assertEqual(prediction["predicted_tool"], "add_input_binding") self.assertEqual(prediction["predicted_skills"][0], "unity-input-system") + def test_csharp_creation_and_compile_fixes_route_to_lsp_write_tools(self): + benchmark = ROOT / "tests/fixtures/skill-routing/benchmark.jsonl" + rows = [row for row in map(json.loads, benchmark.read_text().splitlines()) + if row["id"] == "SR-072" or row["id"].startswith("CS488-")] + self.assertEqual(len(rows), 6) + for row in rows: + with self.subTest(case=row["id"]): + self.assertIn(row["expected_tool"], {"create_csharp_file", "apply_csharp_edits"}) + prediction = routing.route_by_keywords(row["prompt"]) + self.assertIsNotNone(prediction) + self.assertEqual(prediction["predicted_tool"], row["expected_tool"]) + self.assertEqual(prediction["predicted_skills"], row["expected_skills"]) + self.assertEqual(prediction["predicted_payload_keys"], + row["expected_payload_keys"]) + if __name__ == "__main__": unittest.main() From 8d8ec5132a162868e4876b1a39ebd3ecc5f0611b Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 16:18:23 +0900 Subject: [PATCH 23/73] ci(auto-merge): auto-merge reviewed external PRs pinned to the labeled head SHA - labeled `reviewed-safe` by a write+ user (or akiojin) on a non-draft fork PR into develop enables `gh pr merge --auto --merge --match-head-commit` - a push after labeling (synchronize) removes the label and disables auto-merge, so only reviewed commits can land - no fork checkout; gh API calls only; owner/dependabot job unchanged Closes #486 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/README.md | 11 ++ .github/workflows/auto-merge.yml | 89 +++++++++- tests/scripts/test_auto_merge_workflow.py | 190 ++++++++++++++++++++++ 3 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 tests/scripts/test_auto_merge_workflow.py diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 0f93b6a3..711c1706 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -37,3 +37,14 @@ `akiojin` or `dependabot[bot]` into `develop` and for the `develop` -> `main` release PR - merges happen only after the branch-protection required checks pass + - external (fork) PRs into `develop` merge only after a threat review: + 1. a reviewer reads the full diff and confirms nothing in it is a threat + 2. a user with write or higher permission (or `akiojin`) adds the + `reviewed-safe` label to the non-draft PR + 3. the workflow enables auto-merge with + `gh pr merge --auto --merge --match-head-commit `, + so commits pushed after the review are never merged + - a new push to a labeled fork PR (`synchronize`) removes `reviewed-safe` and + disables auto-merge; the PR needs a new review and a new label + - runs under `pull_request_target` but never checks out or runs fork code; + every step only calls the `gh` API diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index bb003205..054a4d94 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -2,7 +2,7 @@ name: Auto Merge PR on: pull_request_target: - types: [opened, synchronize, reopened, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review, labeled] branches: - main - develop @@ -16,6 +16,7 @@ jobs: name: Enable auto-merge runs-on: ubuntu-latest if: | + github.event.action != 'labeled' && github.event.pull_request.draft == false && github.event.pull_request.head.repo.full_name == github.repository && (github.event.pull_request.user.login == 'akiojin' || @@ -58,3 +59,89 @@ jobs: echo "Failed to enable auto-merge after 10 minutes" >&2 exit 1 + + # External (fork) PRs: a write+ reviewer approves the threat review by adding + # `reviewed-safe`. Only the head SHA seen at label time may merge. + # Fork code is never checked out; every step only calls the gh API. + external-reviewed: + name: Enable auto-merge for reviewed external PR + runs-on: ubuntu-latest + if: | + github.event.action == 'labeled' && + github.event.label.name == 'reviewed-safe' && + github.event.pull_request.head.repo.full_name != github.repository && + github.event.pull_request.draft == false && + github.event.pull_request.base.ref == 'develop' + steps: + - name: Verify reviewer and enable pinned auto-merge + env: + GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + ACTOR: ${{ github.event.sender.login }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + LABEL: reviewed-safe + run: | + set -euo pipefail + + revoke() { + echo "$1" >&2 + gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "$LABEL" || true + exit 1 + } + + if [ "$ACTOR" != "akiojin" ]; then + permission=$(gh api "repos/$REPO/collaborators/$ACTOR/permission" --jq .permission || echo "none") + case "$permission" in + admin|maintain|write) ;; + *) revoke "$ACTOR has '$permission' permission; write or higher is required to approve" ;; + esac + fi + + current_sha=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json headRefOid --jq .headRefOid) + if [ "$current_sha" != "$HEAD_SHA" ]; then + revoke "Head moved from $HEAD_SHA to $current_sha after labeling; re-review required" + fi + + for i in $(seq 1 60); do + echo "Attempt $i: enable auto-merge for #$PR_NUMBER at $HEAD_SHA" + + if gh pr merge "$PR_NUMBER" --auto --merge --match-head-commit "$HEAD_SHA" --repo "$REPO"; then + echo "Auto-merge enabled" + exit 0 + fi + + mergeable=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json mergeable --jq .mergeable || echo "UNKNOWN") + if [ "$mergeable" = "CONFLICTING" ]; then + echo "PR has merge conflicts; cannot auto-merge" >&2 + exit 1 + fi + + sleep 10 + done + + echo "Failed to enable auto-merge after 10 minutes" >&2 + exit 1 + + # A push after approval invalidates the review: drop the label and auto-merge. + external-revoke: + name: Revoke review on new external commits + runs-on: ubuntu-latest + if: | + github.event.action == 'synchronize' && + github.event.pull_request.head.repo.full_name != github.repository && + contains(github.event.pull_request.labels.*.name, 'reviewed-safe') + steps: + - name: Remove reviewed-safe and disable auto-merge + env: + GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + LABEL: reviewed-safe + run: | + set -euo pipefail + + gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "$LABEL" + gh pr merge "$PR_NUMBER" --repo "$REPO" --disable-auto \ + || echo "Auto-merge was not enabled" + echo "New commits after review; re-review and re-add $LABEL" diff --git a/tests/scripts/test_auto_merge_workflow.py b/tests/scripts/test_auto_merge_workflow.py new file mode 100644 index 00000000..bdedebf4 --- /dev/null +++ b/tests/scripts/test_auto_merge_workflow.py @@ -0,0 +1,190 @@ +"""Checks .github/workflows/auto-merge.yml (Issue #486). + +The step scripts run against a fake `gh` on PATH, so the permission check, +pinned head SHA and synchronize revocation are exercised without GitHub. +""" + +import os +import stat +import subprocess +import tempfile +import unittest +from pathlib import Path + +import yaml + +ROOT = Path(__file__).resolve().parents[2] +WORKFLOW = ROOT / '.github' / 'workflows' / 'auto-merge.yml' +README = ROOT / '.github' / 'workflows' / 'README.md' + +LABEL = 'reviewed-safe' +SHA = '0123456789abcdef0123456789abcdef01234567' + +# Fake gh: logs every call, answers from FAKE_* environment variables. +FAKE_GH = r'''#!/bin/sh +printf '%s\n' "$*" >> "$FAKE_GH_LOG" +case "$*" in + *collaborators/*/permission*) printf '%s\n' "$FAKE_PERMISSION"; exit 0 ;; + "pr view"*headRefOid*) printf '%s\n' "$FAKE_HEAD_SHA"; exit 0 ;; + "pr view"*mergeable*) printf 'MERGEABLE\n'; exit 0 ;; + "pr merge"*--disable-auto*) exit "${FAKE_DISABLE_EXIT:-0}" ;; + "pr merge"*) exit 0 ;; + "pr edit"*) exit 0 ;; +esac +exit 0 +''' + + +def load_workflow(): + with WORKFLOW.open(encoding='utf-8') as f: + return yaml.safe_load(f) + + +def triggers(workflow): + # PyYAML (YAML 1.1) reads the bare `on` key as True. + return workflow.get('on', workflow.get(True)) + + +def run_job(job, env): + """Run every `run` step of a job with a fake gh; return the gh call log.""" + with tempfile.TemporaryDirectory() as tmp: + tmp_path = Path(tmp) + gh = tmp_path / 'gh' + gh.write_text(FAKE_GH, encoding='utf-8') + gh.chmod(gh.stat().st_mode | stat.S_IEXEC) + log = tmp_path / 'gh.log' + log.touch() + full_env = { + 'PATH': f'{tmp_path}{os.pathsep}{os.environ["PATH"]}', + 'FAKE_GH_LOG': str(log), + 'GH_TOKEN': 'token', + 'REPO': 'akiojin/unity-cli', + 'PR_NUMBER': '481', + 'LABEL': LABEL, + 'HEAD_SHA': SHA, + 'FAKE_HEAD_SHA': SHA, + 'FAKE_PERMISSION': 'write', + 'ACTOR': 'reviewer', + } + full_env.update(env) + code = 0 + for step in job['steps']: + if 'run' not in step: + continue + result = subprocess.run(['bash', '-c', step['run']], env=full_env, + capture_output=True, text=True) + if result.returncode != 0: + code = result.returncode + break + return code, log.read_text(encoding='utf-8').splitlines() + + +class AutoMergeWorkflowStructure(unittest.TestCase): + def setUp(self): + self.workflow = load_workflow() + self.jobs = self.workflow['jobs'] + + def test_triggers_on_labeled_and_synchronize(self): + on = triggers(self.workflow) + types = on['pull_request_target']['types'] + self.assertIn('labeled', types) + self.assertIn('synchronize', types) + + def test_minimal_permissions(self): + self.assertEqual(self.workflow['permissions'], + {'contents': 'write', 'pull-requests': 'write'}) + + def test_never_checks_out_fork_code(self): + for name, job in self.jobs.items(): + for step in job['steps']: + self.assertNotIn('uses', step, f'{name} must only call gh') + + def test_owner_job_keeps_behavior_and_ignores_label_events(self): + cond = self.jobs['auto-merge']['if'] + self.assertIn("github.event.pull_request.head.repo.full_name == github.repository", cond) + self.assertIn("'akiojin'", cond) + self.assertIn("'dependabot[bot]'", cond) + self.assertIn("github.event.action != 'labeled'", cond) + + def test_external_job_conditions(self): + cond = self.jobs['external-reviewed']['if'] + self.assertIn("github.event.action == 'labeled'", cond) + self.assertIn(f"github.event.label.name == '{LABEL}'", cond) + self.assertIn("github.event.pull_request.head.repo.full_name != github.repository", cond) + self.assertIn('github.event.pull_request.draft == false', cond) + self.assertIn("github.event.pull_request.base.ref == 'develop'", cond) + + def test_revoke_job_conditions(self): + cond = self.jobs['external-revoke']['if'] + self.assertIn("github.event.action == 'synchronize'", cond) + self.assertIn("github.event.pull_request.head.repo.full_name != github.repository", cond) + self.assertIn(f"'{LABEL}'", cond) + + def test_external_job_pins_labeled_head_sha(self): + env = self.jobs['external-reviewed']['steps'][0]['env'] + self.assertEqual(env['HEAD_SHA'], '${{ github.event.pull_request.head.sha }}') + self.assertEqual(env['ACTOR'], '${{ github.event.sender.login }}') + + +class ExternalReviewedJob(unittest.TestCase): + def setUp(self): + self.job = load_workflow()['jobs']['external-reviewed'] + + def test_write_permission_enables_pinned_merge(self): + for permission in ('admin', 'maintain', 'write'): + code, calls = run_job(self.job, {'FAKE_PERMISSION': permission}) + self.assertEqual(code, 0, calls) + merges = [c for c in calls if c.startswith('pr merge')] + self.assertEqual(len(merges), 1, calls) + self.assertIn('--auto', merges[0]) + self.assertIn('--merge', merges[0]) + self.assertIn(f'--match-head-commit {SHA}', merges[0]) + + def test_owner_is_trusted_without_permission_lookup(self): + code, calls = run_job(self.job, {'ACTOR': 'akiojin', 'FAKE_PERMISSION': 'none'}) + self.assertEqual(code, 0, calls) + self.assertTrue(any(c.startswith('pr merge') for c in calls), calls) + + def test_insufficient_permission_does_not_merge(self): + for permission in ('read', 'triage', 'none'): + code, calls = run_job(self.job, {'FAKE_PERMISSION': permission}) + self.assertNotEqual(code, 0, calls) + self.assertFalse(any(c.startswith('pr merge') for c in calls), calls) + self.assertTrue(any(c.startswith('pr edit') and '--remove-label' in c + for c in calls), calls) + + def test_head_moved_since_label_does_not_merge(self): + code, calls = run_job(self.job, {'FAKE_HEAD_SHA': 'f' * 40}) + self.assertNotEqual(code, 0, calls) + self.assertFalse(any(c.startswith('pr merge') for c in calls), calls) + self.assertTrue(any('--remove-label' in c for c in calls), calls) + + +class ExternalRevokeJob(unittest.TestCase): + def setUp(self): + self.job = load_workflow()['jobs']['external-revoke'] + + def test_new_push_removes_label_and_disables_auto_merge(self): + code, calls = run_job(self.job, {}) + self.assertEqual(code, 0, calls) + self.assertTrue(any(c.startswith('pr edit') and f'--remove-label {LABEL}' in c + for c in calls), calls) + self.assertTrue(any(c.startswith('pr merge') and '--disable-auto' in c + for c in calls), calls) + + def test_disable_without_auto_merge_still_succeeds(self): + code, calls = run_job(self.job, {'FAKE_DISABLE_EXIT': '1'}) + self.assertEqual(code, 0, calls) + self.assertTrue(any('--remove-label' in c for c in calls), calls) + + +class WorkflowReadme(unittest.TestCase): + def test_documents_external_review_flow(self): + text = README.read_text(encoding='utf-8') + self.assertIn(LABEL, text) + self.assertIn('--match-head-commit', text) + self.assertIn('synchronize', text) + + +if __name__ == '__main__': + unittest.main() From e60b9dab6d3735ffb54eaab5b01b723f68de6383 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 16:29:39 +0900 Subject: [PATCH 24/73] feat(lsp): make LSP the default backend for C# symbol search UNITY_CLI_LSP_MODE now defaults to `auto`. get_symbols / find_symbol / find_refs / build_index prefer the C# LSP and fall back to the local regex index when the LSP is not installed (a detached `lsp install` is started in the background), fails, or does not answer within UNITY_CLI_LSP_AUTO_TIMEOUT_MS (default 10000 ms). Index responses carry `backend: "index"`, `fallbackReason` and `fallbackDetail`. Explicit `off` and `required` keep their behavior. Refs #491 Co-Authored-By: Claude Opus 5.5 --- README.de.md | 3 +- README.es.md | 3 +- README.fr.md | 3 +- README.it.md | 3 +- README.ja.md | 3 +- README.md | 3 +- README.zh.md | 3 +- docs/architecture.md | 8 +- docs/development.md | 44 +++--- src/core/managed_binaries.rs | 1 - src/lsp/client.rs | 287 ++++++++++++++++++++++++++++++++++- src/lsp/mod.rs | 2 +- src/tooling/local_tools.rs | 106 ++++++++++--- 13 files changed, 414 insertions(+), 55 deletions(-) diff --git a/README.de.md b/README.de.md index a1efadc0..315d9b48 100644 --- a/README.de.md +++ b/README.de.md @@ -244,7 +244,8 @@ unity-cli tool call run_tests --json '{"mode":"editmode"}' | `UNITY_CLI_HOST` | Unity Editor Host | `localhost` | | `UNITY_CLI_PORT` | Unity Editor Port | `6400` | | `UNITY_CLI_TIMEOUT_MS` | Command Timeout (ms) | `30000` | -| `UNITY_CLI_LSP_MODE` | LSP Modus (`off` / `auto` / `required`) | `off` | +| `UNITY_CLI_LSP_MODE` | LSP Modus (`off` / `auto` / `required`). `auto` bevorzugt den C# LSP fur die Symbolsuche und fallt auf den lokalen Index zuruck (`backend: "index"`, `fallbackReason`) | `auto` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | Obergrenze (ms), wie lange eine `auto` Symbolsuche auf den LSP wartet, bevor sie auf den lokalen Index zuruckfallt | `10000` | | `UNITY_CLI_TOOLS_ROOT` | Root Verzeichnis fur heruntergeladene Tools | OS default | Legacy MCP Umgebungsvariablen werden nicht unterstutzt. Nutzen Sie nur `UNITY_CLI_*`. diff --git a/README.es.md b/README.es.md index b06cb712..e9a66b67 100644 --- a/README.es.md +++ b/README.es.md @@ -240,7 +240,8 @@ unity-cli tool call run_tests --json '{"mode":"editmode"}' | `UNITY_CLI_HOST` | Host de Unity Editor | `localhost` | | `UNITY_CLI_PORT` | Puerto de Unity Editor | `6400` | | `UNITY_CLI_TIMEOUT_MS` | Timeout del comando (ms) | `30000` | -| `UNITY_CLI_LSP_MODE` | Modo LSP (`off` / `auto` / `required`) | `off` | +| `UNITY_CLI_LSP_MODE` | Modo LSP (`off` / `auto` / `required`). `auto` prefiere el LSP de C# para buscar simbolos y vuelve al indice local (`backend: "index"`, `fallbackReason`) | `auto` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | Limite (ms) que una busqueda de simbolos en `auto` espera al LSP antes de volver al indice local | `10000` | | `UNITY_CLI_TOOLS_ROOT` | Directorio raiz de herramientas descargadas | OS default | No se admiten variables legacy con prefijo MCP. Usa solo `UNITY_CLI_*`. diff --git a/README.fr.md b/README.fr.md index c529d0be..704b7ec0 100644 --- a/README.fr.md +++ b/README.fr.md @@ -241,7 +241,8 @@ unity-cli tool call run_tests --json '{"mode":"editmode"}' | `UNITY_CLI_HOST` | Hote Unity Editor | `localhost` | | `UNITY_CLI_PORT` | Port Unity Editor | `6400` | | `UNITY_CLI_TIMEOUT_MS` | Timeout de commande (ms) | `30000` | -| `UNITY_CLI_LSP_MODE` | Mode LSP (`off` / `auto` / `required`) | `off` | +| `UNITY_CLI_LSP_MODE` | Mode LSP (`off` / `auto` / `required`). `auto` privilegie le LSP C# pour la recherche de symboles et revient a l'index local (`backend: "index"`, `fallbackReason`) | `auto` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | Limite (ms) d'attente du LSP pour une recherche de symboles en `auto` avant le retour a l'index local | `10000` | | `UNITY_CLI_TOOLS_ROOT` | Repertoire racine des outils telecharges | OS default | Les variables legacy prefixees MCP ne sont pas supportees. Utilisez uniquement `UNITY_CLI_*`. diff --git a/README.it.md b/README.it.md index 31bb1fbc..6c7f48b9 100644 --- a/README.it.md +++ b/README.it.md @@ -240,7 +240,8 @@ unity-cli tool call run_tests --json '{"mode":"editmode"}' | `UNITY_CLI_HOST` | Host Unity Editor | `localhost` | | `UNITY_CLI_PORT` | Porta Unity Editor | `6400` | | `UNITY_CLI_TIMEOUT_MS` | Timeout comando (ms) | `30000` | -| `UNITY_CLI_LSP_MODE` | Modalita LSP (`off` / `auto` / `required`) | `off` | +| `UNITY_CLI_LSP_MODE` | Modalita LSP (`off` / `auto` / `required`). `auto` preferisce il LSP C# per la ricerca dei simboli e torna all'indice locale (`backend: "index"`, `fallbackReason`) | `auto` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | Limite (ms) di attesa del LSP per una ricerca simboli in `auto` prima di tornare all'indice locale | `10000` | | `UNITY_CLI_TOOLS_ROOT` | Directory root dei tool scaricati | OS default | Le variabili legacy con prefisso MCP non sono supportate. Usa solo `UNITY_CLI_*`. diff --git a/README.ja.md b/README.ja.md index e8451c8e..ea7e71ab 100644 --- a/README.ja.md +++ b/README.ja.md @@ -241,7 +241,8 @@ unity-cli tool call run_tests --json '{"mode":"editmode"}' | `UNITY_CLI_HOST` | Unity Editor ホスト | `127.0.0.1` | | `UNITY_CLI_PORT` | Unity Editor ポート | `6400` | | `UNITY_CLI_TIMEOUT_MS` | コマンドタイムアウト (ms) | `30000` | -| `UNITY_CLI_LSP_MODE` | LSP モード (`off` / `auto` / `required`) | `off` | +| `UNITY_CLI_LSP_MODE` | LSP モード (`off` / `auto` / `required`)。`auto` はシンボル検索で C# LSP を優先し、使えないときはローカルインデックスに戻る(`backend: "index"`, `fallbackReason`) | `auto` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | `auto` のシンボル検索が LSP を待つ上限 (ms)。超えるとローカルインデックスに戻る | `10000` | | `UNITY_CLI_TOOLS_ROOT` | ダウンロード済みツールのルートディレクトリ | OS 既定 | 旧 MCP 接頭辞の環境変数は非対応です。`UNITY_CLI_*` のみ使用してください。 diff --git a/README.md b/README.md index 418c4cca..88898cbc 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,8 @@ policy, required CI, and skill documentation changes. | `UNITY_CLI_HOST` | Unity Editor host | `127.0.0.1` | | `UNITY_CLI_PORT` | Unity Editor port | `6400` | | `UNITY_CLI_TIMEOUT_MS` | Command timeout (ms) | `30000` | -| `UNITY_CLI_LSP_MODE` | LSP mode (`off` / `auto` / `required`) | `off` | +| `UNITY_CLI_LSP_MODE` | LSP mode (`off` / `auto` / `required`). `auto` prefers the C# LSP for symbol search and falls back to the local index (`backend: "index"`, `fallbackReason`) | `auto` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | Upper bound (ms) for an `auto` symbol search to wait for the LSP before falling back to the local index | `10000` | | `UNITY_CLI_TOOLS_ROOT` | Downloaded tools root directory | OS default | | `UNITY_CLI_NO_AUTO_UPDATE` | Disable background auto-update (`1` to disable) | *(unset)* | diff --git a/README.zh.md b/README.zh.md index fa5ae937..ef5f0c28 100644 --- a/README.zh.md +++ b/README.zh.md @@ -232,7 +232,8 @@ unity-cli tool call run_tests --json '{"mode":"editmode"}' | `UNITY_CLI_HOST` | Unity Editor 主机 | `localhost` | | `UNITY_CLI_PORT` | Unity Editor 端口 | `6400` | | `UNITY_CLI_TIMEOUT_MS` | 命令超时 (ms) | `30000` | -| `UNITY_CLI_LSP_MODE` | LSP 模式 (`off` / `auto` / `required`) | `off` | +| `UNITY_CLI_LSP_MODE` | LSP 模式 (`off` / `auto` / `required`)。`auto` 在符号搜索中优先使用 C# LSP,不可用时回退到本地索引(`backend: "index"`, `fallbackReason`) | `auto` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | `auto` 符号搜索等待 LSP 的上限 (ms),超时后回退到本地索引 | `10000` | | `UNITY_CLI_TOOLS_ROOT` | 已下载工具根目录 | OS 默认 | 不支持旧 MCP 前缀环境变量。请仅使用 `UNITY_CLI_*`。 diff --git a/docs/architecture.md b/docs/architecture.md index 1751ba69..cfdfa403 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -71,7 +71,10 @@ C# ソースコードの静的解析を行う Language Server Protocol 実装で - **役割**: - シンボル検索・参照解析 - インデックスの構築と更新 -- **起動制御**: `UNITY_CLI_LSP_MODE` 環境変数で制御 (`off` | `auto` | `required`) +- **起動制御**: `UNITY_CLI_LSP_MODE` 環境変数で制御 (`off` | `auto` | `required`、既定は `auto`) + - `auto`: `get_symbols` / `find_symbol` / `find_refs` / `build_index` は LSP を優先する。LSP が未インストール(バックグラウンドで `unity-cli lsp install` を起動)、起動失敗、または `UNITY_CLI_LSP_AUTO_TIMEOUT_MS`(既定 10000ms)以内に応答しない場合はローカルインデックスに戻り、結果に `backend: "index"` / `fallbackReason` / `fallbackDetail` を含める + - `off`: 常にローカルの正規表現インデックスを使う(`fallbackReason: "lsp_disabled"`) + - `required`: LSP を必須とし、失敗をそのままエラーにする ## 通信プロトコル @@ -123,7 +126,8 @@ CLI 側 Unity Editor 側 | `UNITY_CLI_HOST` | Unity Editor の接続先ホスト | `127.0.0.1` | | `UNITY_CLI_PORT` | Unity Editor の接続先ポート | `6400` | | `UNITY_CLI_TIMEOUT_MS` | コマンドタイムアウト (ミリ秒) | ― | -| `UNITY_CLI_LSP_MODE` | LSP 起動モード | `off` | +| `UNITY_CLI_LSP_MODE` | LSP 起動モード | `auto` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | `auto` のシンボル検索が LSP を待つ上限 (ミリ秒) | `10000` | | `UNITY_CLI_LSP_COMMAND` | LSP 実行コマンド | ― | | `UNITY_CLI_LSP_BIN` | LSP 実行ファイルパス | ― | | `UNITY_PROJECT_ROOT` | Unity プロジェクトルート | ― | diff --git a/docs/development.md b/docs/development.md index c2301146..d57411cb 100644 --- a/docs/development.md +++ b/docs/development.md @@ -51,15 +51,16 @@ docker run --rm unity-cli-dev dotnet test lsp/Server.Tests.csproj `unity-cli` works with defaults, but these variables are recommended for CI and multi-instance setups. -| Env | Default | Notes | -| ------------------------------- | ---------------: | ---------------------------------------------- | -| `UNITY_PROJECT_ROOT` | auto-detect | Directory containing `Assets/` and `Packages/` | -| `UNITY_CLI_HOST` | `127.0.0.1` | Unity TCP listener host | -| `UNITY_CLI_PORT` | `6400` | Unity TCP listener port | -| `UNITY_CLI_TIMEOUT_MS` | `30000` | Command timeout (ms) | -| `UNITY_CLI_LSP_MODE` | `off` | `off`, `auto`, `required` | -| `UNITY_CLI_UNITYD_IDLE_TIMEOUT` | `600` | Daemon idle timeout (seconds) | -| `UNITY_CLI_TOOLS_ROOT` | platform default | Root directory for downloaded tools | +| Env | Default | Notes | +| ------------------------------- | ---------------: | ----------------------------------------------- | +| `UNITY_PROJECT_ROOT` | auto-detect | Directory containing `Assets/` and `Packages/` | +| `UNITY_CLI_HOST` | `127.0.0.1` | Unity TCP listener host | +| `UNITY_CLI_PORT` | `6400` | Unity TCP listener port | +| `UNITY_CLI_TIMEOUT_MS` | `30000` | Command timeout (ms) | +| `UNITY_CLI_LSP_MODE` | `auto` | `off`, `auto`, `required` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | `10000` | `auto` symbol search wait before index fallback | +| `UNITY_CLI_UNITYD_IDLE_TIMEOUT` | `600` | Daemon idle timeout (seconds) | +| `UNITY_CLI_TOOLS_ROOT` | platform default | Root directory for downloaded tools | Minimal setup: @@ -556,11 +557,12 @@ Windows verification is tracked separately in Issue #308. ### LSP Issues -| Symptom | Fix | -| ---------------------------- | ------------------------------------------ | -| LSP command not found | Run `unity-cli lsp install` and retry | -| LSP timeout | Increase `UNITY_CLI_TIMEOUT_MS` and retry | -| LSP required but unavailable | Use `UNITY_CLI_LSP_MODE=auto` during setup | +| Symptom | Fix | +| ---------------------------------------- | ------------------------------------------------------------------------------------------- | +| LSP command not found | Run `unity-cli lsp install` and retry | +| LSP timeout | Increase `UNITY_CLI_TIMEOUT_MS` and retry | +| LSP required but unavailable | Use `UNITY_CLI_LSP_MODE=auto` during setup | +| Symbol search returns `backend: "index"` | Read `fallbackReason`; run `unity-cli lsp install` or raise `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | ### WSL2/Docker -> Windows Unity @@ -939,7 +941,8 @@ docker run --rm unity-cli-dev dotnet test lsp/Server.Tests.csproj | `UNITY_CLI_HOST` | `127.0.0.1` | Unity TCP リスナーのホスト | | `UNITY_CLI_PORT` | `6400` | Unity TCP リスナーのポート | | `UNITY_CLI_TIMEOUT_MS` | `30000` | コマンドタイムアウト (ms) | -| `UNITY_CLI_LSP_MODE` | `off` | `off`, `auto`, `required` | +| `UNITY_CLI_LSP_MODE` | `auto` | `off`, `auto`, `required` | +| `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | `10000` | `auto` のシンボル検索が LSP を待つ上限 (ms) | | `UNITY_CLI_UNITYD_IDLE_TIMEOUT` | `600` | デーモンアイドルタイムアウト(秒) | | `UNITY_CLI_TOOLS_ROOT` | OS依存既定 | ツール配置ルート | @@ -1212,11 +1215,12 @@ batch / sequence の応答もジェスチャー終了待ちではなく受付結 ### LSP関連 -| 症状 | 対処 | -| ----------------------------- | ------------------------------------------------- | -| LSP実行ファイルが見つからない | `unity-cli lsp install` を実行して再試行 | -| LSPタイムアウト | `UNITY_CLI_TIMEOUT_MS` を延長 | -| 必須LSPモードで失敗 | セットアップ中は `UNITY_CLI_LSP_MODE=auto` を利用 | +| 症状 | 対処 | +| ---------------------------------------- | ------------------------------------------------------------------------------------------------------ | +| LSP実行ファイルが見つからない | `unity-cli lsp install` を実行して再試行 | +| LSPタイムアウト | `UNITY_CLI_TIMEOUT_MS` を延長 | +| 必須LSPモードで失敗 | セットアップ中は `UNITY_CLI_LSP_MODE=auto` を利用 | +| シンボル検索が `backend: "index"` を返す | `fallbackReason` を確認し、`unity-cli lsp install` を実行するか `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` を延長 | ### WSL2/Docker -> Windows Unity diff --git a/src/core/managed_binaries.rs b/src/core/managed_binaries.rs index 31838fec..524b383c 100644 --- a/src/core/managed_binaries.rs +++ b/src/core/managed_binaries.rs @@ -179,7 +179,6 @@ pub fn install_dir() -> Result { install_dir_for(ManagedBinary::CSharpLsp) } -#[cfg(test)] pub fn binary_path() -> Result { binary_path_for(ManagedBinary::CSharpLsp) } diff --git a/src/lsp/client.rs b/src/lsp/client.rs index 5a2d7fc1..56ddc6f2 100644 --- a/src/lsp/client.rs +++ b/src/lsp/client.rs @@ -16,6 +16,8 @@ use crate::lspd; const MAX_HEADER_BYTES: usize = 16 * 1024; const DEFAULT_TIMEOUT_MS: u64 = 60_000; +const DEFAULT_AUTO_TIMEOUT_MS: u64 = 10_000; +const AUTO_INSTALL_MARKER_TTL: Duration = Duration::from_secs(600); #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum LspMode { @@ -78,6 +80,158 @@ pub fn maybe_execute( } } +/// Why a symbol search was answered by the local regex index instead of the LSP. +#[derive(Debug, Clone)] +pub struct LspFallback { + pub reason: &'static str, + pub detail: String, +} + +impl LspFallback { + fn new(reason: &'static str, detail: impl Into) -> Self { + Self { + reason, + detail: detail.into(), + } + } + + /// Marks an index-backed response so callers can tell the LSP was not used. + pub fn annotate(&self, value: &mut Value) { + if let Some(map) = value.as_object_mut() { + map.insert("backend".to_string(), json!("index")); + map.insert("fallbackReason".to_string(), json!(self.reason)); + map.insert("fallbackDetail".to_string(), json!(self.detail)); + } + } +} + +pub enum SearchRoute { + Lsp(Result), + Index(LspFallback), +} + +/// Routes the read-only symbol search tools. `auto` (the default) prefers the +/// LSP but never waits longer than `UNITY_CLI_LSP_AUTO_TIMEOUT_MS`, and never +/// blocks on the first LSP download. +pub fn route_search(tool_name: &str, params: &Value, project_root: &Path) -> SearchRoute { + match lsp_mode() { + LspMode::Off => SearchRoute::Index(LspFallback::new( + "lsp_disabled", + "UNITY_CLI_LSP_MODE=off selects the local symbol index", + )), + LspMode::Required => SearchRoute::Lsp(execute_via_daemon(tool_name, params, project_root)), + LspMode::Auto => match execute_auto(tool_name, params, project_root) { + Ok(value) => SearchRoute::Lsp(Ok(value)), + Err(fallback) => SearchRoute::Index(fallback), + }, + } +} + +fn execute_auto( + tool_name: &str, + params: &Value, + project_root: &Path, +) -> std::result::Result { + let installed = lsp_manager::binary_path() + .map(|path| path.exists()) + .unwrap_or(false); + if !installed { + let detail = match request_background_install() { + Ok(()) => "C# LSP is not installed yet; installing it in the background".to_string(), + Err(error) => { + format!("C# LSP is not installed and the background install failed: {error:#}") + } + }; + return Err(LspFallback::new("lsp_not_installed", detail)); + } + + let tool_name = tool_name.to_string(); + let params = params.clone(); + let project_root = project_root.to_path_buf(); + run_with_timeout(auto_timeout(), move || { + execute_via_daemon(&tool_name, ¶ms, &project_root) + }) +} + +fn run_with_timeout(timeout: Duration, call: F) -> std::result::Result +where + F: FnOnce() -> Result + Send + 'static, +{ + let (sender, receiver) = mpsc::channel(); + thread::spawn(move || { + let _ = sender.send(call()); + }); + match receiver.recv_timeout(timeout) { + Ok(Ok(value)) => Ok(value), + Ok(Err(error)) => Err(LspFallback::new("lsp_unavailable", format!("{error:#}"))), + Err(mpsc::RecvTimeoutError::Timeout) => Err(LspFallback::new( + "lsp_timeout", + format!( + "LSP did not answer within {}ms (UNITY_CLI_LSP_AUTO_TIMEOUT_MS); it keeps warming up in lspd", + timeout.as_millis() + ), + )), + Err(mpsc::RecvTimeoutError::Disconnected) => Err(LspFallback::new( + "lsp_unavailable", + "LSP worker ended without a response", + )), + } +} + +fn auto_timeout() -> Duration { + let millis = env::var("UNITY_CLI_LSP_AUTO_TIMEOUT_MS") + .ok() + .and_then(|value| value.trim().parse::().ok()) + .filter(|value| *value > 0) + .unwrap_or(DEFAULT_AUTO_TIMEOUT_MS); + Duration::from_millis(millis) +} + +fn auto_install_marker() -> Result { + Ok(lsp_manager::install_dir()?.join(".auto-install-requested")) +} + +/// Starts `unity-cli lsp install` detached so the download survives this +/// short-lived CLI process. A marker keeps concurrent calls from racing on the +/// same download file. +fn request_background_install() -> Result<()> { + let marker = auto_install_marker()?; + let fresh = fs_modified_age(&marker).is_some_and(|age| age < AUTO_INSTALL_MARKER_TTL); + if fresh { + return Ok(()); + } + if let Some(parent) = marker.parent() { + std::fs::create_dir_all(parent) + .with_context(|| format!("Failed to create {}", parent.display()))?; + } + std::fs::write(&marker, now_epoch_ms().to_string()) + .with_context(|| format!("Failed to write {}", marker.display()))?; + spawn_background_install() +} + +fn fs_modified_age(path: &Path) -> Option { + let modified = std::fs::metadata(path).ok()?.modified().ok()?; + std::time::SystemTime::now().duration_since(modified).ok() +} + +#[cfg(not(test))] +fn spawn_background_install() -> Result<()> { + let exe = env::current_exe().context("Failed to resolve unity-cli executable")?; + Command::new(exe) + .args(["lsp", "install"]) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .context("Failed to spawn background C# LSP install")?; + Ok(()) +} + +#[cfg(test)] +fn spawn_background_install() -> Result<()> { + Ok(()) +} + fn execute_via_daemon(tool_name: &str, params: &Value, project_root: &Path) -> Result { let _ = lsp_manager::ensure_local(false)?; @@ -1120,12 +1274,13 @@ fn now_epoch_ms() -> u64 { fn lsp_mode() -> LspMode { let raw = env::var("UNITY_CLI_LSP_MODE") .ok() - .unwrap_or_else(|| "off".to_string()) + .unwrap_or_default() + .trim() .to_ascii_lowercase(); match raw.as_str() { "required" => LspMode::Required, - "auto" => LspMode::Auto, + "" | "auto" => LspMode::Auto, _ => LspMode::Off, } } @@ -1408,15 +1563,20 @@ mod tests { use std::process::{Command, Stdio}; #[cfg(unix)] use std::sync::{Mutex, OnceLock}; + #[cfg(unix)] + use std::time::Duration; + #[cfg(unix)] + use super::{ + auto_timeout, execute_direct, lsp_mode, maybe_execute, read_message, reset_cached_session, + route_search, run_with_timeout, LspMode, SearchRoute, + }; use super::{ build_remove_symbol_request, collect_document_symbols, file_uri, get_apply, id_matches, is_retryable_session_error, kind_from_lsp, normalize_lsp_write_result, normalize_rel_path, path_matches_scope, ref_path, require_name_path, require_relative_path, to_project_relative_or_raw, uri_to_rel_path, }; - #[cfg(unix)] - use super::{execute_direct, maybe_execute, read_message, reset_cached_session}; #[cfg(unix)] fn env_lock() -> &'static Mutex<()> { @@ -2028,4 +2188,123 @@ while True: std::env::remove_var("UNITY_CLI_LSP_MODE"); } + + #[cfg(unix)] + #[test] + fn lsp_mode_defaults_to_auto_when_unset() { + let _guard = env_lock().lock().expect("lock should succeed"); + let _mode = EnvVarGuard::set("UNITY_CLI_LSP_MODE", ""); + assert_eq!(lsp_mode(), LspMode::Auto); + std::env::remove_var("UNITY_CLI_LSP_MODE"); + assert_eq!(lsp_mode(), LspMode::Auto); + std::env::set_var("UNITY_CLI_LSP_MODE", "OFF"); + assert_eq!(lsp_mode(), LspMode::Off); + std::env::set_var("UNITY_CLI_LSP_MODE", "Required"); + assert_eq!(lsp_mode(), LspMode::Required); + std::env::set_var("UNITY_CLI_LSP_MODE", "auto"); + assert_eq!(lsp_mode(), LspMode::Auto); + std::env::set_var("UNITY_CLI_LSP_MODE", "bogus"); + assert_eq!(lsp_mode(), LspMode::Off); + } + + #[cfg(unix)] + #[test] + fn auto_timeout_uses_env_override_and_default() { + let _guard = env_lock().lock().expect("lock should succeed"); + let _timeout = EnvVarGuard::set("UNITY_CLI_LSP_AUTO_TIMEOUT_MS", "250"); + assert_eq!(auto_timeout(), Duration::from_millis(250)); + std::env::set_var("UNITY_CLI_LSP_AUTO_TIMEOUT_MS", "0"); + assert_eq!(auto_timeout(), Duration::from_millis(10_000)); + std::env::set_var("UNITY_CLI_LSP_AUTO_TIMEOUT_MS", "nope"); + assert_eq!(auto_timeout(), Duration::from_millis(10_000)); + std::env::remove_var("UNITY_CLI_LSP_AUTO_TIMEOUT_MS"); + assert_eq!(auto_timeout(), Duration::from_millis(10_000)); + } + + #[cfg(unix)] + #[test] + fn run_with_timeout_returns_value_or_times_out() { + let fast = run_with_timeout(Duration::from_secs(5), || Ok(json!({"ok": true}))); + assert_eq!(fast.expect("fast call should succeed")["ok"], true); + + let failing = run_with_timeout(Duration::from_secs(5), || Err(anyhow!("boom"))); + let fallback = failing.expect_err("failing call should fall back"); + assert_eq!(fallback.reason, "lsp_unavailable"); + assert!(fallback.detail.contains("boom")); + + let slow = run_with_timeout(Duration::from_millis(50), || { + std::thread::sleep(Duration::from_millis(500)); + Ok(json!({})) + }); + let fallback = slow.expect_err("slow call should time out"); + assert_eq!(fallback.reason, "lsp_timeout"); + assert!(fallback.detail.contains("50ms")); + } + + #[cfg(unix)] + #[test] + fn route_search_falls_back_to_index_with_reason() { + let _guard = env_lock().lock().expect("lock should succeed"); + let root = tempdir().expect("tempdir should be created"); + let tools = tempdir().expect("tempdir should be created"); + let _tools = EnvVarGuard::set( + "UNITY_CLI_TOOLS_ROOT", + tools + .path() + .to_str() + .expect("tools root path should be valid UTF-8"), + ); + let _skip_updates = EnvVarGuard::set("UNITY_CLI_TEST_SKIP_MANAGED_UPDATE", "1"); + let _mode = EnvVarGuard::set("UNITY_CLI_LSP_MODE", "off"); + let params = json!({"path":"Assets/Scripts/Player.cs"}); + + let SearchRoute::Index(off) = route_search("get_symbols", ¶ms, root.path()) else { + panic!("off mode should use the index"); + }; + assert_eq!(off.reason, "lsp_disabled"); + let mut annotated = json!({"success": true}); + off.annotate(&mut annotated); + assert_eq!(annotated["backend"], "index"); + assert_eq!(annotated["fallbackReason"], "lsp_disabled"); + assert!(annotated["fallbackDetail"] + .as_str() + .expect("detail should be a string") + .contains("UNITY_CLI_LSP_MODE=off")); + + // Default (unset) mode without an installed LSP falls back immediately and + // requests a background install exactly once per marker lifetime. + std::env::remove_var("UNITY_CLI_LSP_MODE"); + let SearchRoute::Index(missing) = route_search("find_symbol", ¶ms, root.path()) else { + panic!("auto mode without LSP should use the index"); + }; + assert_eq!(missing.reason, "lsp_not_installed"); + let marker = super::auto_install_marker().expect("marker path should resolve"); + assert!(marker.exists(), "background install should be requested"); + let first_stamp = fs::read_to_string(&marker).expect("marker should be readable"); + let SearchRoute::Index(again) = route_search("find_symbol", ¶ms, root.path()) else { + panic!("auto mode without LSP should use the index"); + }; + assert_eq!(again.reason, "lsp_not_installed"); + assert_eq!( + fs::read_to_string(&marker).expect("marker should be readable"), + first_stamp, + "a fresh marker must not re-request the install" + ); + + // Installed LSP whose daemon cannot start falls back with the error. + setup_fake_lsp_server(tools.path()); + let _timeout = EnvVarGuard::set("UNITY_CLI_LSP_AUTO_TIMEOUT_MS", "20000"); + let SearchRoute::Index(unavailable) = route_search("find_refs", ¶ms, root.path()) + else { + panic!("auto mode with a broken daemon should use the index"); + }; + assert_eq!(unavailable.reason, "lsp_unavailable"); + + // Required mode keeps surfacing the LSP error instead of falling back. + std::env::set_var("UNITY_CLI_LSP_MODE", "required"); + let SearchRoute::Lsp(result) = route_search("find_refs", ¶ms, root.path()) else { + panic!("required mode should not fall back"); + }; + assert!(result.is_err()); + } } diff --git a/src/lsp/mod.rs b/src/lsp/mod.rs index 061f8243..3db28549 100644 --- a/src/lsp/mod.rs +++ b/src/lsp/mod.rs @@ -1,4 +1,4 @@ pub mod client; pub mod daemon; -pub use client::{execute_direct, maybe_execute}; +pub use client::{execute_direct, maybe_execute, route_search, SearchRoute}; diff --git a/src/tooling/local_tools.rs b/src/tooling/local_tools.rs index cb5e4293..7b23b2c5 100644 --- a/src/tooling/local_tools.rs +++ b/src/tooling/local_tools.rs @@ -70,12 +70,11 @@ pub fn maybe_execute_local_tool(tool_name: &str, params: &Value) -> Option Some(local_read(params)), "search" => Some(local_search(params)), "list_packages" => Some(local_list_packages()), - "get_symbols" => Some(local_get_symbols(params)), - "build_index" => Some(local_build_index(params)), + "get_symbols" | "build_index" | "find_symbol" | "find_refs" => { + Some(local_symbol_search(tool_name, params)) + } "update_index" => Some(local_update_index(params)), "get_index_status" => Some(local_get_index_status()), - "find_symbol" => Some(local_find_symbol(params)), - "find_refs" => Some(local_find_refs(params)), "rename_symbol" => Some(local_lsp_write("rename_symbol", params)), "replace_symbol_body" => Some(local_lsp_write("replace_symbol_body", params)), "insert_before_symbol" => Some(local_lsp_write("insert_before_symbol", params)), @@ -246,12 +245,25 @@ fn local_list_packages() -> Result { })) } -fn local_get_symbols(params: &Value) -> Result { +fn local_symbol_search(tool_name: &str, params: &Value) -> Result { + let index_search: fn(&Value) -> Result = match tool_name { + "get_symbols" => local_get_symbols, + "build_index" => local_build_index, + "find_symbol" => local_find_symbol, + _ => local_find_refs, + }; let root = project_root()?; - if let Some(result) = crate::lsp::maybe_execute("get_symbols", params, &root) { - return result; - } + let fallback = match crate::lsp::route_search(tool_name, params, &root) { + crate::lsp::SearchRoute::Lsp(result) => return result, + crate::lsp::SearchRoute::Index(fallback) => fallback, + }; + let mut value = index_search(params)?; + fallback.annotate(&mut value); + Ok(value) +} +fn local_get_symbols(params: &Value) -> Result { + let root = project_root()?; let path = params .get("path") .and_then(Value::as_str) @@ -276,10 +288,6 @@ fn local_get_symbols(params: &Value) -> Result { fn local_build_index(params: &Value) -> Result { let root = project_root()?; - if let Some(result) = crate::lsp::maybe_execute("build_index", params, &root) { - return result; - } - let exclude_package_cache = params .get("excludePackageCache") .and_then(Value::as_bool) @@ -466,10 +474,6 @@ fn local_update_index(params: &Value) -> Result { fn local_find_symbol(params: &Value) -> Result { let root = project_root()?; - if let Some(result) = crate::lsp::maybe_execute("find_symbol", params, &root) { - return result; - } - let name = params .get("name") .and_then(Value::as_str) @@ -571,10 +575,6 @@ fn local_find_refs(params: &Value) -> Result { .clamp(0, 20) as usize; let root = project_root()?; - if let Some(result) = crate::lsp::maybe_execute("find_refs", params, &root) { - return result; - } - let index = match load_index_if_exists(&root) { Ok(Some(index)) if index_is_ready(&index) => index, Ok(_) => { @@ -1526,6 +1526,28 @@ mod tests { LOCK.get_or_init(|| Mutex::new(())) } + struct ScopedEnv { + key: &'static str, + previous: Option, + } + + impl ScopedEnv { + fn set(key: &'static str, value: &str) -> Self { + let previous = std::env::var_os(key); + std::env::set_var(key, value); + Self { key, previous } + } + } + + impl Drop for ScopedEnv { + fn drop(&mut self) { + match &self.previous { + Some(value) => std::env::set_var(self.key, value), + None => std::env::remove_var(self.key), + } + } + } + fn write_file(path: &Path, content: &str) { if let Some(parent) = path.parent() { std::fs::create_dir_all(parent).expect("parent directory should be created"); @@ -1640,6 +1662,7 @@ mod tests { #[test] fn get_symbols_extracts_class_and_method() { let _guard = env_lock().lock().expect("lock should succeed"); + let _lsp_off = ScopedEnv::set("UNITY_CLI_LSP_MODE", "off"); let tmp = tempfile::tempdir().expect("temp dir should be created"); write_file( &tmp.path().join("Assets/Scripts/Player.cs"), @@ -1651,6 +1674,8 @@ mod tests { maybe_execute_local_tool("get_symbols", &json!({"path":"Assets/Scripts/Player.cs"})) .expect("tool should be handled") .expect("get_symbols should succeed"); + assert_eq!(value["backend"], "index"); + assert_eq!(value["fallbackReason"], "lsp_disabled"); let symbols = value["symbols"] .as_array() @@ -1668,9 +1693,47 @@ mod tests { std::env::remove_var("UNITY_PROJECT_ROOT"); } + #[test] + fn get_symbols_defaults_to_lsp_and_reports_index_fallback() { + let _guard = env_lock().lock().expect("lock should succeed"); + let tmp = tempfile::tempdir().expect("temp dir should be created"); + let tools = tempfile::tempdir().expect("tools dir should be created"); + write_file( + &tmp.path().join("Assets/Scripts/Player.cs"), + "public class Player { public void Jump() {} }\n", + ); + let _root = ScopedEnv::set( + "UNITY_PROJECT_ROOT", + tmp.path().to_str().expect("project root should be UTF-8"), + ); + let _tools = ScopedEnv::set( + "UNITY_CLI_TOOLS_ROOT", + tools.path().to_str().expect("tools root should be UTF-8"), + ); + let previous_mode = std::env::var_os("UNITY_CLI_LSP_MODE"); + std::env::remove_var("UNITY_CLI_LSP_MODE"); + + let value = + maybe_execute_local_tool("get_symbols", &json!({"path":"Assets/Scripts/Player.cs"})) + .expect("tool should be handled") + .expect("get_symbols should fall back to the index"); + + if let Some(mode) = previous_mode { + std::env::set_var("UNITY_CLI_LSP_MODE", mode); + } + assert_eq!(value["backend"], "index"); + assert_eq!(value["fallbackReason"], "lsp_not_installed"); + assert!(value["symbols"] + .as_array() + .expect("symbols should be an array") + .iter() + .any(|symbol| symbol["name"] == "Player")); + } + #[test] fn find_symbol_returns_index_not_ready_before_build() { let _guard = env_lock().lock().expect("lock should succeed"); + let _lsp_off = ScopedEnv::set("UNITY_CLI_LSP_MODE", "off"); let tmp = tempfile::tempdir().expect("temp dir should be created"); write_file( &tmp.path().join("Assets/Scripts/Player.cs"), @@ -1691,6 +1754,7 @@ mod tests { #[test] fn build_index_and_find_symbol_roundtrip() { let _guard = env_lock().lock().expect("lock should succeed"); + let _lsp_off = ScopedEnv::set("UNITY_CLI_LSP_MODE", "off"); let tmp = tempfile::tempdir().expect("temp dir should be created"); write_file( &tmp.path().join("Assets/Scripts/Player.cs"), @@ -1740,6 +1804,7 @@ mod tests { #[test] fn update_index_refreshes_symbol_names() { let _guard = env_lock().lock().expect("lock should succeed"); + let _lsp_off = ScopedEnv::set("UNITY_CLI_LSP_MODE", "off"); let tmp = tempfile::tempdir().expect("temp dir should be created"); let target = tmp.path().join("Assets/Scripts/Player.cs"); write_file(&target, "public class BeforeName {}\n"); @@ -1777,6 +1842,7 @@ mod tests { #[test] fn find_refs_supports_cursor_paging() { let _guard = env_lock().lock().expect("lock should succeed"); + let _lsp_off = ScopedEnv::set("UNITY_CLI_LSP_MODE", "off"); let tmp = tempfile::tempdir().expect("temp dir should be created"); write_file( &tmp.path().join("Assets/Scripts/Player.cs"), From d8d8d763bb49dfcd3ca68680d6b98e03ebf7be14 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 16:55:01 +0900 Subject: [PATCH 25/73] fix(skills): add the LSP write-tool failure fallback to unity-csharp-edit - SKILL.md gains an "LSP Write Failure Fallback" section: when the LSP server fails to start, times out, or rejects an unsupported edit, make the same change with Edit/Write, run refresh_assets and get_compilation_state, and record why LSP was not used in the report - Preferred Flow and lsp-write-safety.md point to the fallback as the only exception to the no-direct-write rule - tests/csharp_edit_skill_fallback.rs asserts the section and its steps Fixes #494 Co-Authored-By: Claude Opus 5.5 --- .../skills/unity-csharp-edit/SKILL.md | 17 +++++- .../references/lsp-write-safety.md | 2 +- tests/csharp_edit_skill_fallback.rs | 55 +++++++++++++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 tests/csharp_edit_skill_fallback.rs diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md index e1fdbd0d..460f6820 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md @@ -4,7 +4,7 @@ description: Implement, fix, and refactor Unity C# code with unity-cli write too allowed-tools: Bash(unity-cli:*), Read, Grep, Glob, Edit, Write metadata: author: akiojin - version: 0.3.1 + version: 0.3.2 category: code triggers: - csharp @@ -50,7 +50,7 @@ Implement Unity C# changes with `unity-cli` as the primary write path. Prefer th ## Preferred Flow -1. Decide the write shape: new file, symbol edit, full-file write, multi-file write, or settings change. Always write `.cs` files through the LSP write tools (`create_csharp_file`, `write_csharp_file`, `apply_csharp_edits`, symbol edits) so the text is validated before it lands; do not hand-write `.cs` files with direct file edits. +1. Decide the write shape: new file, symbol edit, full-file write, multi-file write, or settings change. Always write `.cs` files through the LSP write tools (`create_csharp_file`, `write_csharp_file`, `apply_csharp_edits`, symbol edits) so the text is validated before it lands; do not hand-write `.cs` files with direct file edits unless the LSP write path fails (see LSP Write Failure Fallback). 2. Read only the minimum context with `read`, `get_symbols`, `find_symbol`, or `find_refs`. 3. Preview risky symbol edits with `apply: false`. 4. Apply with `refresh`, `waitForCompile`, and `updateIndex` when later steps depend on clean diagnostics. @@ -64,6 +64,19 @@ unity-cli raw apply_csharp_edits --json '{"files":[{"relative":"Assets/Scripts/I unity-cli raw get_compilation_state --json '{}' ``` +## LSP Write Failure Fallback + +Use this only when an LSP write tool fails: the LSP server fails to start, the call times out, or the tool returns an unsupported-edit error. Retry once if the failure looks transient; do not stop the task. + +1. Make the same change with your own `Edit` (existing file) or `Write` (new file). Keep it identical in scope to the intended LSP write. +2. Refresh and confirm compilation with `unity-cli`: + ```bash + unity-cli raw refresh_assets --json '{}' + unity-cli raw get_compilation_state --json '{}' + ``` + Fix any reported errors before continuing; if the Editor is unreachable, say so and leave compilation unconfirmed. +3. In your work report, state that the LSP path was not used, which tool failed, and why (error code or message). + ## Examples - "Implement dash cooldown in `PlayerController.cs` and update the related tests." diff --git a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/lsp-write-safety.md b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/lsp-write-safety.md index 5ba14019..e2063ec5 100644 --- a/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/lsp-write-safety.md +++ b/.claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/references/lsp-write-safety.md @@ -29,7 +29,7 @@ - Use `create_csharp_file` for every new `.cs` file (classes, `MonoBehaviour`, `ScriptableObject`, interfaces, enums, tests). It validates the text through LSP before writing. - `create_class` (`name`, `folder`, optional `namespace` / `inherits`) is a shortcut that renders an empty class shell and writes it through the same LSP path as `create_csharp_file`. Prefer `create_csharp_file` when the file needs any members. -- Do not create or edit `.cs` files with direct file writes; they skip LSP validation. +- Do not create or edit `.cs` files with direct file writes; they skip LSP validation. The only exception is the `LSP Write Failure Fallback` in `SKILL.md`. - Use `validate_text_edits` when constructing larger manual replacements. ## Compile Error Fixes diff --git a/tests/csharp_edit_skill_fallback.rs b/tests/csharp_edit_skill_fallback.rs new file mode 100644 index 00000000..9935fa8f --- /dev/null +++ b/tests/csharp_edit_skill_fallback.rs @@ -0,0 +1,55 @@ +//! Issue #494: `unity-csharp-edit` must document what to do when the LSP +//! write tools fail, so the agent is never stuck without a write path. + +use std::fs; +use std::path::Path; + +fn skill_text() -> String { + let path = Path::new(env!("CARGO_MANIFEST_DIR")) + .join(".claude-plugin/plugins/unity-cli/skills/unity-csharp-edit/SKILL.md"); + fs::read_to_string(path).unwrap() +} + +fn fallback_section(text: &str) -> &str { + let start = text + .find("## LSP Write Failure Fallback") + .expect("SKILL.md must contain an `## LSP Write Failure Fallback` section"); + let rest = &text[start + 2..]; + let end = rest.find("\n## ").map_or(rest.len(), |i| i + 2); + &text[start..start + end] +} + +#[test] +fn fallback_section_covers_triggers_edit_refresh_compile_and_report() { + let text = skill_text(); + let section = fallback_section(&text); + for needle in [ + "fails to start", + "times out", + "unsupported", + "`Edit`", + "`Write`", + "refresh_assets", + "get_compilation_state", + "report", + ] { + assert!( + section.contains(needle), + "fallback section is missing `{needle}`:\n{section}" + ); + } +} + +#[test] +fn preferred_flow_points_to_the_fallback() { + let text = skill_text(); + let flow_start = text.find("## Preferred Flow").unwrap(); + let flow = &text[flow_start + ..text + .find("## LSP Write Failure Fallback") + .unwrap_or(text.len())]; + assert!( + flow.contains("LSP Write Failure Fallback"), + "Preferred Flow must point to the fallback section" + ); +} From 6031ade3cf771a3999f611d0da5a51252f1bc390 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 17:00:43 +0900 Subject: [PATCH 26/73] fix(lsp): keep write tools on the direct LSP session when the mode is unset The `auto` default from #491 also routed C# write tools through lspd, which downloads managed binaries on start and replaced the fake LSP in tests/csharp_post_write.rs on CI. Only symbol search defaults to `auto`; write tools use lspd only when UNITY_CLI_LSP_MODE is set explicitly. Refs #491 Co-Authored-By: Claude Opus 5.5 --- docs/architecture.md | 1 + src/lsp/client.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/docs/architecture.md b/docs/architecture.md index cfdfa403..dd2af826 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -75,6 +75,7 @@ C# ソースコードの静的解析を行う Language Server Protocol 実装で - `auto`: `get_symbols` / `find_symbol` / `find_refs` / `build_index` は LSP を優先する。LSP が未インストール(バックグラウンドで `unity-cli lsp install` を起動)、起動失敗、または `UNITY_CLI_LSP_AUTO_TIMEOUT_MS`(既定 10000ms)以内に応答しない場合はローカルインデックスに戻り、結果に `backend: "index"` / `fallbackReason` / `fallbackDetail` を含める - `off`: 常にローカルの正規表現インデックスを使う(`fallbackReason: "lsp_disabled"`) - `required`: LSP を必須とし、失敗をそのままエラーにする + - 書き込み系ツール(`write_csharp_file` など)は、未設定時は従来どおり direct LSP セッションを使う。lspd 経由にするのは `auto` / `required` を明示したときだけ ## 通信プロトコル diff --git a/src/lsp/client.rs b/src/lsp/client.rs index 56ddc6f2..6df6a91e 100644 --- a/src/lsp/client.rs +++ b/src/lsp/client.rs @@ -66,6 +66,11 @@ pub fn maybe_execute( return None; } + // Only symbol search defaults to `auto` (see `route_search`); write tools + // keep their direct-session default unless a mode is set explicitly. + if !lsp_mode_is_set() { + return None; + } let mode = lsp_mode(); if mode == LspMode::Off { return None; @@ -1271,6 +1276,10 @@ fn now_epoch_ms() -> u64 { .unwrap_or(0) } +fn lsp_mode_is_set() -> bool { + env::var("UNITY_CLI_LSP_MODE").is_ok_and(|value| !value.trim().is_empty()) +} + fn lsp_mode() -> LspMode { let raw = env::var("UNITY_CLI_LSP_MODE") .ok() @@ -2307,4 +2316,63 @@ while True: }; assert!(result.is_err()); } + + #[cfg(unix)] + #[test] + fn write_tools_keep_direct_session_default_when_mode_is_unset() { + use std::io::{BufRead, Write as _}; + + let _guard = env_lock().lock().expect("lock should succeed"); + let root = tempdir().expect("tempdir should be created"); + let tools = tempdir().expect("tempdir should be created"); + setup_fake_lsp_server(tools.path()); + let _tools = EnvVarGuard::set( + "UNITY_CLI_TOOLS_ROOT", + tools + .path() + .to_str() + .expect("tools root path should be valid UTF-8"), + ); + let _skip_updates = EnvVarGuard::set("UNITY_CLI_TEST_SKIP_MANAGED_UPDATE", "1"); + let _mode = EnvVarGuard::set("UNITY_CLI_LSP_MODE", ""); + + // A fake lspd that answers exactly one request proves which path ran. + let socket = crate::daemon::runtime::DaemonRuntimePaths::new("lspd") + .and_then(|paths| paths.socket_file()) + .expect("lspd socket path should resolve"); + fs::create_dir_all(socket.parent().expect("socket should have a parent")) + .expect("socket parent should be created"); + let _ = fs::remove_file(&socket); + let listener = + std::os::unix::net::UnixListener::bind(&socket).expect("fake lspd should bind"); + let server = std::thread::spawn(move || { + let (mut stream, _) = listener.accept().expect("fake lspd should accept"); + let mut line = String::new(); + BufReader::new(stream.try_clone().expect("stream should clone")) + .read_line(&mut line) + .expect("request should be readable"); + stream + .write_all(b"{\"ok\":true,\"result\":{\"via\":\"lspd\"}}\n") + .expect("response should be written"); + }); + + let params = json!({"relative":"Assets/Scripts/Player.cs","newText":"class P {}"}); + for unset in ["", " "] { + std::env::set_var("UNITY_CLI_LSP_MODE", unset); + assert!( + maybe_execute("write_csharp_file", ¶ms, root.path()).is_none(), + "unset mode must leave writes on the direct LSP session" + ); + } + std::env::remove_var("UNITY_CLI_LSP_MODE"); + assert!(maybe_execute("write_csharp_file", ¶ms, root.path()).is_none()); + + std::env::set_var("UNITY_CLI_LSP_MODE", "auto"); + let via_daemon = maybe_execute("write_csharp_file", ¶ms, root.path()) + .expect("explicit auto should use lspd") + .expect("fake lspd should answer"); + assert_eq!(via_daemon["via"], "lspd"); + server.join().expect("fake lspd should finish"); + let _ = fs::remove_file(&socket); + } } From dc2a71896454e85a9013723407b38374ffa629d8 Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 17:33:39 +0900 Subject: [PATCH 27/73] test(lsp): measure cross-platform write reliability --- .github/workflows/lsp-write-reliability.yml | 98 + .github/workflows/test.yml | 10 + ...0939fca7b98d7e7c99645bb79f1f86f17fd8.jsonl | 1 + ...df697afd2d420395a03aa4a6779f7342ec3d.jsonl | 1 + ...f8ba0093f762fd9b70042c2f343167dee802.jsonl | 1 + ...75ae37f41b44045f9660ac3289785df2a128.jsonl | 1 + ...025504a14533bec43fbd4be7f873f6471672.jsonl | 1 + docs/lsp-write-reliability-windows.json | 2622 +++++++++++++++++ docs/lsp-write-reliability.md | 114 + scripts/lsp-write-reliability.py | 432 +++ tests/fixtures/lsp-write-baseline.json | 29 + tests/scripts/test_lsp_write_reliability.py | 119 + 12 files changed, 3429 insertions(+) create mode 100644 .github/workflows/lsp-write-reliability.yml create mode 100644 .gwt/work/events/41/418c51b4b4dfad2e325a1aeecea90939fca7b98d7e7c99645bb79f1f86f17fd8.jsonl create mode 100644 .gwt/work/events/5f/5fd9170317f93c84d7bd08a61bdadf697afd2d420395a03aa4a6779f7342ec3d.jsonl create mode 100644 .gwt/work/events/90/90c69a6a42a1e0f3e9c8bb72dbfff8ba0093f762fd9b70042c2f343167dee802.jsonl create mode 100644 .gwt/work/events/ba/ba1ba8be7a52c932ed55e5d9484075ae37f41b44045f9660ac3289785df2a128.jsonl create mode 100644 .gwt/work/events/ff/ff71ead878a9d61af6335afed219025504a14533bec43fbd4be7f873f6471672.jsonl create mode 100644 docs/lsp-write-reliability-windows.json create mode 100644 docs/lsp-write-reliability.md create mode 100644 scripts/lsp-write-reliability.py create mode 100644 tests/fixtures/lsp-write-baseline.json create mode 100644 tests/scripts/test_lsp_write_reliability.py diff --git a/.github/workflows/lsp-write-reliability.yml b/.github/workflows/lsp-write-reliability.yml new file mode 100644 index 00000000..0868301f --- /dev/null +++ b/.github/workflows/lsp-write-reliability.yml @@ -0,0 +1,98 @@ +name: LSP Write Reliability + +on: + workflow_call: + inputs: + repetitions: + default: '3' + type: string + schedule: + - cron: '17 2 * * 2' + workflow_dispatch: + inputs: + repetitions: + description: Samples per scenario and installed-LSP condition + default: '20' + type: string + +permissions: + contents: read + +jobs: + measure: + name: LSP Write Reliability (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [windows-latest, macos-latest, ubuntu-latest] + runs-on: ${{ matrix.os }} + timeout-minutes: 120 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@stable + - uses: actions/setup-dotnet@v6 + with: + dotnet-version: '10.0.x' + - uses: actions/setup-python@v7 + with: + python-version: '3.11' + - uses: actions/cache@v6 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-lsp-reliability-${{ hashFiles('Cargo.lock') }} + - name: Build the real CLI + run: cargo build --bin unity-cli + - name: Publish the real LSP for this runner + shell: bash + run: | + rid=$(python -c 'import platform; print({"Windows":"win","Darwin":"osx","Linux":"linux"}[platform.system()] + ("-arm64" if platform.machine().lower() in ("arm64", "aarch64") else "-x64"))') + dotnet publish lsp/Server.csproj -c Release -r "$rid" --self-contained true -o .cache/lsp-reliability-publish + - name: Verify the measurement and regression gate + run: python -B -m unittest discover -s tests/scripts -p test_lsp_write_reliability.py + - name: Measure writes, cold starts, real downloads, and direct-edit differences + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPETITIONS: ${{ inputs.repetitions || (github.event_name == 'schedule' && '20') || '3' }} + run: | + cli=target/debug/unity-cli + if [ "$RUNNER_OS" = Windows ]; then cli="$cli.exe"; fi + python scripts/lsp-write-reliability.py --unity-cli "$cli" \ + --lsp-publish .cache/lsp-reliability-publish --out .cache/lsp-reliability \ + --repetitions "$REPETITIONS" --download-repetitions 1 \ + --baseline tests/fixtures/lsp-write-baseline.json + - name: Upload measured failures as well as successes + if: always() + uses: actions/upload-artifact@v7 + with: + name: lsp-write-reliability-${{ matrix.os }} + path: .cache/lsp-reliability/ + if-no-files-found: error + retention-days: 30 + + report: + name: LSP Write Reliability Report + needs: measure + if: always() + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: '3.11' + - uses: actions/download-artifact@v8 + with: + pattern: lsp-write-reliability-* + path: .cache/reliability-reports + - name: Aggregate every OS without masking missing or failing measurements + run: | + python scripts/lsp-write-reliability.py --merge .cache/reliability-reports/*/results.json --out .cache/combined-reliability + cat .cache/combined-reliability/summary.md >> "$GITHUB_STEP_SUMMARY" + - uses: actions/upload-artifact@v7 + with: + name: lsp-write-reliability-report + path: .cache/combined-reliability/ + if-no-files-found: error diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 139b8957..4d68fb09 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,10 +11,20 @@ permissions: contents: read jobs: + lsp-write-reliability: + uses: ./.github/workflows/lsp-write-reliability.yml + cli-latency: name: CLI Latency (required) + needs: lsp-write-reliability + if: always() runs-on: ubuntu-latest steps: + - name: Require passing LSP write measurements on every OS + env: + RELIABILITY_RESULT: ${{ needs.lsp-write-reliability.result }} + run: test "$RELIABILITY_RESULT" = success + - uses: actions/checkout@v7 - name: Install Rust toolchain diff --git a/.gwt/work/events/41/418c51b4b4dfad2e325a1aeecea90939fca7b98d7e7c99645bb79f1f86f17fd8.jsonl b/.gwt/work/events/41/418c51b4b4dfad2e325a1aeecea90939fca7b98d7e7c99645bb79f1f86f17fd8.jsonl new file mode 100644 index 00000000..4da4bde1 --- /dev/null +++ b/.gwt/work/events/41/418c51b4b4dfad2e325a1aeecea90939fca7b98d7e7c99645bb79f1f86f17fd8.jsonl @@ -0,0 +1 @@ +{"id":"147231ec-66e7-44f9-8a92-142db3422f35","work_item_id":"work-work-issue-490-ce1c1f9a","kind":"done","title":null,"intent":"測定実装を確定し、fresh verification と3 OS CIへ","summary":null,"progress_summary":"19シナリオ/全10ツール/4起動条件の実CLI測定、厳密baseline、既存必須チェックにつながる3OS CI、MarkdownとWindows57試行の証跡を実装。回帰11件とWindows38試行のrunner検証PASS。Rust品質とLinux .NET53件PASS。BOM追加/末尾コメント消失/ScriptableObject using欠落等はPMへ個別登録依頼中。owner ACはCI実測と登録確認後に同期する。","status_category":"done","owner":"Issue #490","next_action":null,"agent_session_id":"c0ac1284-51ea-49d8-82e3-da19507a6ba5","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-490","worktree_path":"E:\\unity-cli\\work\\issue-490","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T08:33:35.161036400Z"} diff --git a/.gwt/work/events/5f/5fd9170317f93c84d7bd08a61bdadf697afd2d420395a03aa4a6779f7342ec3d.jsonl b/.gwt/work/events/5f/5fd9170317f93c84d7bd08a61bdadf697afd2d420395a03aa4a6779f7342ec3d.jsonl new file mode 100644 index 00000000..2f5e2645 --- /dev/null +++ b/.gwt/work/events/5f/5fd9170317f93c84d7bd08a61bdadf697afd2d420395a03aa4a6779f7342ec3d.jsonl @@ -0,0 +1 @@ +{"id":"68858545-e0ec-4227-a28f-668ba32c3397","work_item_id":"work-work-issue-490-ce1c1f9a","kind":"start","title":"test(lsp): measure the reliability of the C# LSP write tools before enforcing them","intent":"Check Board for latest updates","summary":"Codex is running","progress_summary":null,"status_category":"active","owner":"Issue #490","next_action":"Check Board for latest updates","agent_session_id":"c0ac1284-51ea-49d8-82e3-da19507a6ba5","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-490","worktree_path":"E:\\unity-cli\\work\\issue-490","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T07:35:00.887269Z"} diff --git a/.gwt/work/events/90/90c69a6a42a1e0f3e9c8bb72dbfff8ba0093f762fd9b70042c2f343167dee802.jsonl b/.gwt/work/events/90/90c69a6a42a1e0f3e9c8bb72dbfff8ba0093f762fd9b70042c2f343167dee802.jsonl new file mode 100644 index 00000000..230e3fe1 --- /dev/null +++ b/.gwt/work/events/90/90c69a6a42a1e0f3e9c8bb72dbfff8ba0093f762fd9b70042c2f343167dee802.jsonl @@ -0,0 +1 @@ +{"id":"5e77a8aa-a7e2-4c37-818e-ac699afbc8bd","work_item_id":"work-work-issue-490-ce1c1f9a","kind":"update","title":"Issue #490 の受け入れ条件対応","intent":"既存実装と受け入れ条件の監査","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #490","next_action":null,"agent_session_id":"c0ac1284-51ea-49d8-82e3-da19507a6ba5","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-490","worktree_path":"E:\\unity-cli\\work\\issue-490","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T07:37:10.390988600Z"} diff --git a/.gwt/work/events/ba/ba1ba8be7a52c932ed55e5d9484075ae37f41b44045f9660ac3289785df2a128.jsonl b/.gwt/work/events/ba/ba1ba8be7a52c932ed55e5d9484075ae37f41b44045f9660ac3289785df2a128.jsonl new file mode 100644 index 00000000..37cc89a4 --- /dev/null +++ b/.gwt/work/events/ba/ba1ba8be7a52c932ed55e5d9484075ae37f41b44045f9660ac3289785df2a128.jsonl @@ -0,0 +1 @@ +{"id":"acd77777-733b-49b4-ba14-f478f9d87c11","work_item_id":"work-work-issue-490-ce1c1f9a","kind":"update","title":null,"intent":"Windows 実測、既知不具合の厳密な baseline、3 OS CI の検証","summary":null,"progress_summary":"19 シナリオ・全10ツール、4起動条件の実CLI/LSPランナーとCIを実装。測定ロジック回帰7件PASS。Windows実測でBOM追加、末尾コメント喪失、ScriptableObject using欠落を確認し、PMへ個別Issue登録を依頼。","status_category":null,"owner":"Issue #490","next_action":null,"agent_session_id":"c0ac1284-51ea-49d8-82e3-da19507a6ba5","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-490","worktree_path":"E:\\unity-cli\\work\\issue-490","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T08:05:25.880779200Z"} diff --git a/.gwt/work/events/ff/ff71ead878a9d61af6335afed219025504a14533bec43fbd4be7f873f6471672.jsonl b/.gwt/work/events/ff/ff71ead878a9d61af6335afed219025504a14533bec43fbd4be7f873f6471672.jsonl new file mode 100644 index 00000000..1d2da904 --- /dev/null +++ b/.gwt/work/events/ff/ff71ead878a9d61af6335afed219025504a14533bec43fbd4be7f873f6471672.jsonl @@ -0,0 +1 @@ +{"id":"0d9ff232-beeb-4980-a698-8b8722a0b2dc","work_item_id":"work-work-issue-490-ce1c1f9a","kind":"update","title":"C# LSP 書き込み信頼性の測定","intent":"全 AC 監査済み、実 CLI 測定シナリオと CI を実装","summary":null,"progress_summary":"AC-1〜5 は未達。既存は個別/性能テストのみで、OS・起動条件別の成功率/編集差分レポートがない。関連検索で #490 が測定の owner、#488 は実装済み。","status_category":null,"owner":"Issue #490","next_action":null,"agent_session_id":"c0ac1284-51ea-49d8-82e3-da19507a6ba5","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-490","worktree_path":"E:\\unity-cli\\work\\issue-490","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T07:41:02.891169800Z"} diff --git a/docs/lsp-write-reliability-windows.json b/docs/lsp-write-reliability-windows.json new file mode 100644 index 00000000..7ddb563b --- /dev/null +++ b/docs/lsp-write-reliability-windows.json @@ -0,0 +1,2622 @@ +{ + "schema_version": 1, + "os": "Windows", + "rid": "win-x64", + "started_at": "2026-10-13T07:56:21.677570+00:00", + "cli_sha256": "36c6d6ff78e301e9c07fa880628eebdfee2f41c9e11fb524206300b0ea68ee23", + "scope": "Completed warm_indexed slice, initial Windows measurement; other conditions are not represented.", + "source_head": "ef464584543a9d4f692120366b0b485cc6bec43c", + "summary": { + "attempts": 57, + "successes": 6, + "success_rate": 0.10526315789473684, + "failure_types": { + "bom_added": 51, + "text_changed": 6 + }, + "p50_ms": 260.755, + "p95_ms": 293.267, + "direct_p50_ms": 0.596, + "direct_p95_ms": 1.198 + }, + "rows": [ + { + "scenario": "create_class_monobehaviour", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.9078000002773479, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "bbd67e077a1ea2071930829d291635208f148a019060826ffbd182dcb66b6c1d", + "lsp_sha256": "a5709764cc34583026940f58eb1c0f5b6786b067cfabb0169a57ada0417193ed", + "direct_bytes": 60, + "lsp_bytes": 63, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,4 +1,4 @@\n-using UnityEngine;\n+using UnityEngine;\n \n public class Sample : MonoBehaviour\n {\n" + } + ], + "setup_ms": 2726.3216999999713, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "using UnityEngine;\n\npublic class Sample : MonoBehaviour\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"using UnityEngine;\\n\\npublic class Sample : MonoBehaviour\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 277.27239999876474, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_class_monobehaviour", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.9804000001167879, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "bbd67e077a1ea2071930829d291635208f148a019060826ffbd182dcb66b6c1d", + "lsp_sha256": "a5709764cc34583026940f58eb1c0f5b6786b067cfabb0169a57ada0417193ed", + "direct_bytes": 60, + "lsp_bytes": 63, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,4 +1,4 @@\n-using UnityEngine;\n+using UnityEngine;\n \n public class Sample : MonoBehaviour\n {\n" + } + ], + "setup_ms": 2767.2376000009535, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "using UnityEngine;\n\npublic class Sample : MonoBehaviour\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"using UnityEngine;\\n\\npublic class Sample : MonoBehaviour\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 277.41040000000794, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_class_monobehaviour", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 1.0604999988572672, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "bbd67e077a1ea2071930829d291635208f148a019060826ffbd182dcb66b6c1d", + "lsp_sha256": "a5709764cc34583026940f58eb1c0f5b6786b067cfabb0169a57ada0417193ed", + "direct_bytes": 60, + "lsp_bytes": 63, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,4 +1,4 @@\n-using UnityEngine;\n+using UnityEngine;\n \n public class Sample : MonoBehaviour\n {\n" + } + ], + "setup_ms": 2928.5495999993145, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "using UnityEngine;\n\npublic class Sample : MonoBehaviour\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"using UnityEngine;\\n\\npublic class Sample : MonoBehaviour\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 276.7844999998488, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_class_scriptableobject", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 1.0077000006276648, + "failures": [ + "bom_added", + "text_changed" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "9e4068040ddbcd6fd5e13bdec0cccb8834f4d7c50cb83621ba8b1f94006e8114", + "lsp_sha256": "61cc7c4b376b878b0c07bfc7ca64fb4a357bff0b546ed72bb358f9ffeef89f34", + "direct_bytes": 63, + "lsp_bytes": 46, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,5 +1,3 @@\n-using UnityEngine;\n-\n-public class Sample : ScriptableObject\n+public class Sample : ScriptableObject\n {\n }\n" + } + ], + "setup_ms": 2938.434600000619, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "public class Sample : ScriptableObject\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"public class Sample : ScriptableObject\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 274.7672000004968, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_class_scriptableobject", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.8920000000216532, + "failures": [ + "bom_added", + "text_changed" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "9e4068040ddbcd6fd5e13bdec0cccb8834f4d7c50cb83621ba8b1f94006e8114", + "lsp_sha256": "61cc7c4b376b878b0c07bfc7ca64fb4a357bff0b546ed72bb358f9ffeef89f34", + "direct_bytes": 63, + "lsp_bytes": 46, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,5 +1,3 @@\n-using UnityEngine;\n-\n-public class Sample : ScriptableObject\n+public class Sample : ScriptableObject\n {\n }\n" + } + ], + "setup_ms": 2944.0462999991723, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "public class Sample : ScriptableObject\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"public class Sample : ScriptableObject\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 277.60940000007395, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_class_scriptableobject", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.9135000000242144, + "failures": [ + "bom_added", + "text_changed" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "9e4068040ddbcd6fd5e13bdec0cccb8834f4d7c50cb83621ba8b1f94006e8114", + "lsp_sha256": "61cc7c4b376b878b0c07bfc7ca64fb4a357bff0b546ed72bb358f9ffeef89f34", + "direct_bytes": 63, + "lsp_bytes": 46, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,5 +1,3 @@\n-using UnityEngine;\n-\n-public class Sample : ScriptableObject\n+public class Sample : ScriptableObject\n {\n }\n" + } + ], + "setup_ms": 2918.0077000000892, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "public class Sample : ScriptableObject\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"public class Sample : ScriptableObject\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 274.4991999988997, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_class_plain", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 1.0087999999086605, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "c629ef557fa767f4e896d8a91c5ea5f17ab4bd190bd2f7154b70949cde68905b", + "lsp_sha256": "2396be216daf166ada783949e3ce24a74bd439b90959def00decb977835de99b", + "direct_bytes": 24, + "lsp_bytes": 27, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,3 +1,3 @@\n-public class Sample\n+public class Sample\n {\n }\n" + } + ], + "setup_ms": 2953.842999999324, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "public class Sample\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"public class Sample\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 276.31750000000466, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_class_plain", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.9522000000288244, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "c629ef557fa767f4e896d8a91c5ea5f17ab4bd190bd2f7154b70949cde68905b", + "lsp_sha256": "2396be216daf166ada783949e3ce24a74bd439b90959def00decb977835de99b", + "direct_bytes": 24, + "lsp_bytes": 27, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,3 +1,3 @@\n-public class Sample\n+public class Sample\n {\n }\n" + } + ], + "setup_ms": 2966.1285000001953, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "public class Sample\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"public class Sample\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 277.72229999936826, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_class_plain", + "tool": "create_class", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 1.0165999992750585, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "c629ef557fa767f4e896d8a91c5ea5f17ab4bd190bd2f7154b70949cde68905b", + "lsp_sha256": "2396be216daf166ada783949e3ce24a74bd439b90959def00decb977835de99b", + "direct_bytes": 24, + "lsp_bytes": 27, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,3 +1,3 @@\n-public class Sample\n+public class Sample\n {\n }\n" + } + ], + "setup_ms": 2941.6794999997364, + "returncode": 0, + "response": { + "command": "raw create_class", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "content": "public class Sample\n{\n}\n", + "diagnostics": [], + "diffPreview": [], + "path": "Assets/Sample.cs", + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_class\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"content\":\"public class Sample\\n{\\n}\\n\",\"diagnostics\":[],\"diffPreview\":[],\"path\":\"Assets/Sample.cs\",\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 276.1365000005753, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_plain", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.9224999994330574, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "edbe481b5cca42c8e7665f2a02eddba612cd759d03f48a710d6f9ac8f41dcf3e", + "lsp_sha256": "9cd38476c737f80a85845c39b9c6d5cc11e918feb37fb325f615e72f42b0f312", + "direct_bytes": 23, + "lsp_bytes": 26, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {}\n+public class Sample {}\n" + } + ], + "setup_ms": 2924.0387000008923, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 272.0348000002559, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_plain", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.8880000004864996, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "edbe481b5cca42c8e7665f2a02eddba612cd759d03f48a710d6f9ac8f41dcf3e", + "lsp_sha256": "9cd38476c737f80a85845c39b9c6d5cc11e918feb37fb325f615e72f42b0f312", + "direct_bytes": 23, + "lsp_bytes": 26, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {}\n+public class Sample {}\n" + } + ], + "setup_ms": 2954.666300000099, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 272.54480000010517, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_plain", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 1.0884999992413213, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "edbe481b5cca42c8e7665f2a02eddba612cd759d03f48a710d6f9ac8f41dcf3e", + "lsp_sha256": "9cd38476c737f80a85845c39b9c6d5cc11e918feb37fb325f615e72f42b0f312", + "direct_bytes": 23, + "lsp_bytes": 26, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {}\n+public class Sample {}\n" + } + ], + "setup_ms": 2948.2929000005242, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 272.28550000108953, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_monobehaviour", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 1.0600000005069887, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "cdfd3cb55c9b959cf5bcf9f1bb41f5b36eb12fa419acf9cded1138cba4fd700d", + "lsp_sha256": "50b6c9b1e277e77df822088d892da43cf1546524f8305fce72fbbc8b069ec0cf", + "direct_bytes": 58, + "lsp_bytes": 61, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-using UnityEngine;\n+using UnityEngine;\n public class Sample : MonoBehaviour {}\n" + } + ], + "setup_ms": 2937.5804999999673, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 283.6886000004597, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_monobehaviour", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 1.060100001268438, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "cdfd3cb55c9b959cf5bcf9f1bb41f5b36eb12fa419acf9cded1138cba4fd700d", + "lsp_sha256": "50b6c9b1e277e77df822088d892da43cf1546524f8305fce72fbbc8b069ec0cf", + "direct_bytes": 58, + "lsp_bytes": 61, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-using UnityEngine;\n+using UnityEngine;\n public class Sample : MonoBehaviour {}\n" + } + ], + "setup_ms": 2943.190500000128, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 278.33079999982147, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_monobehaviour", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 1.0497000002942514, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "cdfd3cb55c9b959cf5bcf9f1bb41f5b36eb12fa419acf9cded1138cba4fd700d", + "lsp_sha256": "50b6c9b1e277e77df822088d892da43cf1546524f8305fce72fbbc8b069ec0cf", + "direct_bytes": 58, + "lsp_bytes": 61, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-using UnityEngine;\n+using UnityEngine;\n public class Sample : MonoBehaviour {}\n" + } + ], + "setup_ms": 2966.040899998916, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 277.54950000053213, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_scriptableobject", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.9907999992719851, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "fdd183a4d7fcc3118e98d3f62079dff999a0c2310d5de2e98f7cb1cf055b24d2", + "lsp_sha256": "7eba30a7b9514668698fe135a10bf742ada3503fe3540cb1c9050d31e400a3e5", + "direct_bytes": 61, + "lsp_bytes": 64, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-using UnityEngine;\n+using UnityEngine;\n public class Sample : ScriptableObject {}\n" + } + ], + "setup_ms": 2937.8426000002946, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 287.3501000012766, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_scriptableobject", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.9838000005402137, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "fdd183a4d7fcc3118e98d3f62079dff999a0c2310d5de2e98f7cb1cf055b24d2", + "lsp_sha256": "7eba30a7b9514668698fe135a10bf742ada3503fe3540cb1c9050d31e400a3e5", + "direct_bytes": 61, + "lsp_bytes": 64, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-using UnityEngine;\n+using UnityEngine;\n public class Sample : ScriptableObject {}\n" + } + ], + "setup_ms": 2961.0620999992534, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 283.5336999996798, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "create_scriptableobject", + "tool": "create_csharp_file", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 1.154899999164627, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "fdd183a4d7fcc3118e98d3f62079dff999a0c2310d5de2e98f7cb1cf055b24d2", + "lsp_sha256": "7eba30a7b9514668698fe135a10bf742ada3503fe3540cb1c9050d31e400a3e5", + "direct_bytes": 61, + "lsp_bytes": 64, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-using UnityEngine;\n+using UnityEngine;\n public class Sample : ScriptableObject {}\n" + } + ], + "setup_ms": 2949.3394999990414, + "returncode": 0, + "response": { + "command": "raw create_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw create_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 276.03049999925133, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "replace_body", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.5518000016309088, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 3019.1185000003316, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 263.8390000010986, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "replace_body", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.4943999992974568, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 3004.1794999997364, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 257.6360000002751, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "replace_body", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.5726999988837633, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 3012.814800000342, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 255.59340000108932, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.46890000157873146, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2997.1442999994906, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 229.74100000101316, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.48919999971985817, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 3008.276399999886, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 221.43129999858502, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.5059000013716286, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 3010.096699999849, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 223.1549999996787, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "insert_before", + "tool": "insert_before_symbol", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.4769000006490387, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "d69ec0dbd444819d7ab99c2a495a056f641b131bc27815437e5a69c02ac9e736", + "lsp_sha256": "00d2d4dfe04b5d03979eee2ac5bc2ea66329255591a91bd05605dc37d9ead354", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {public int Added;public int Run(){return 1;}}\n+public class Sample {public int Added;public int Run(){return 1;}}\n" + } + ], + "setup_ms": 3062.878800001272, + "returncode": 0, + "response": { + "command": "raw insert_before_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw insert_before_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 264.19560000067577, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "insert_before", + "tool": "insert_before_symbol", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.5049999999755528, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "d69ec0dbd444819d7ab99c2a495a056f641b131bc27815437e5a69c02ac9e736", + "lsp_sha256": "00d2d4dfe04b5d03979eee2ac5bc2ea66329255591a91bd05605dc37d9ead354", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {public int Added;public int Run(){return 1;}}\n+public class Sample {public int Added;public int Run(){return 1;}}\n" + } + ], + "setup_ms": 3026.5687000010075, + "returncode": 0, + "response": { + "command": "raw insert_before_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw insert_before_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 262.19660000060685, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "insert_before", + "tool": "insert_before_symbol", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.4496000001381617, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "d69ec0dbd444819d7ab99c2a495a056f641b131bc27815437e5a69c02ac9e736", + "lsp_sha256": "00d2d4dfe04b5d03979eee2ac5bc2ea66329255591a91bd05605dc37d9ead354", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {public int Added;public int Run(){return 1;}}\n+public class Sample {public int Added;public int Run(){return 1;}}\n" + } + ], + "setup_ms": 3020.2819000005547, + "returncode": 0, + "response": { + "command": "raw insert_before_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw insert_before_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 260.6156000001647, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "insert_after", + "tool": "insert_after_symbol", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.47679999988758937, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "04ee4146423db15d890a6fdc7a66107e933dbad7d335c76b899548c84a276f8a", + "lsp_sha256": "3204a749c2dbfac81557fba80883dea1ece77d9b178e8c4bd560c08221a7d8ab", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {public int Run(){return 1;}public int Added;}\n+public class Sample {public int Run(){return 1;}public int Added;}\n" + } + ], + "setup_ms": 3011.7695999997522, + "returncode": 0, + "response": { + "command": "raw insert_after_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw insert_after_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 260.75479999963136, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "insert_after", + "tool": "insert_after_symbol", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.45679999857384246, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "04ee4146423db15d890a6fdc7a66107e933dbad7d335c76b899548c84a276f8a", + "lsp_sha256": "3204a749c2dbfac81557fba80883dea1ece77d9b178e8c4bd560c08221a7d8ab", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {public int Run(){return 1;}public int Added;}\n+public class Sample {public int Run(){return 1;}public int Added;}\n" + } + ], + "setup_ms": 3019.4062999999005, + "returncode": 0, + "response": { + "command": "raw insert_after_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw insert_after_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 265.448699999979, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "insert_after", + "tool": "insert_after_symbol", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.44750000051863026, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "04ee4146423db15d890a6fdc7a66107e933dbad7d335c76b899548c84a276f8a", + "lsp_sha256": "3204a749c2dbfac81557fba80883dea1ece77d9b178e8c4bd560c08221a7d8ab", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {public int Run(){return 1;}public int Added;}\n+public class Sample {public int Run(){return 1;}public int Added;}\n" + } + ], + "setup_ms": 3007.0403999998234, + "returncode": 0, + "response": { + "command": "raw insert_after_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw insert_after_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 260.5844999998226, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "remove_member", + "tool": "remove_symbol", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.6964000003790716, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "edbe481b5cca42c8e7665f2a02eddba612cd759d03f48a710d6f9ac8f41dcf3e", + "lsp_sha256": "9cd38476c737f80a85845c39b9c6d5cc11e918feb37fb325f615e72f42b0f312", + "direct_bytes": 23, + "lsp_bytes": 26, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {}\n+public class Sample {}\n" + } + ], + "setup_ms": 2998.348700000861, + "returncode": 0, + "response": { + "command": "raw remove_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw remove_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 255.70640000114508, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "remove_member", + "tool": "remove_symbol", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.4540999998425832, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "edbe481b5cca42c8e7665f2a02eddba612cd759d03f48a710d6f9ac8f41dcf3e", + "lsp_sha256": "9cd38476c737f80a85845c39b9c6d5cc11e918feb37fb325f615e72f42b0f312", + "direct_bytes": 23, + "lsp_bytes": 26, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {}\n+public class Sample {}\n" + } + ], + "setup_ms": 3051.758300000074, + "returncode": 0, + "response": { + "command": "raw remove_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw remove_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 252.6543000003585, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "remove_member", + "tool": "remove_symbol", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.5821999984618742, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "edbe481b5cca42c8e7665f2a02eddba612cd759d03f48a710d6f9ac8f41dcf3e", + "lsp_sha256": "9cd38476c737f80a85845c39b9c6d5cc11e918feb37fb325f615e72f42b0f312", + "direct_bytes": 23, + "lsp_bytes": 26, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample {}\n+public class Sample {}\n" + } + ], + "setup_ms": 3032.8964999989694, + "returncode": 0, + "response": { + "command": "raw remove_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw remove_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 253.75359999998182, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "namespace_partial_generic_attributes", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.5580999986705137, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "f2958b4d92901e48bc79cb95602dd97f9acc75094171c71096b130e96354bc43", + "lsp_sha256": "b0ffa3094f22b01473580725d49c4b3766228f1ff3dc56917319a31d5050db91", + "direct_bytes": 121, + "lsp_bytes": 124, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-namespace Demo { [System.Serializable] public partial class Sample { public T Run(){throw new System.Exception();}} }\n+namespace Demo { [System.Serializable] public partial class Sample { public T Run(){throw new System.Exception();}} }\n" + } + ], + "setup_ms": 3042.409299998326, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 261.83640000090236, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "namespace_partial_generic_attributes", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.4955000003974419, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "f2958b4d92901e48bc79cb95602dd97f9acc75094171c71096b130e96354bc43", + "lsp_sha256": "b0ffa3094f22b01473580725d49c4b3766228f1ff3dc56917319a31d5050db91", + "direct_bytes": 121, + "lsp_bytes": 124, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-namespace Demo { [System.Serializable] public partial class Sample { public T Run(){throw new System.Exception();}} }\n+namespace Demo { [System.Serializable] public partial class Sample { public T Run(){throw new System.Exception();}} }\n" + } + ], + "setup_ms": 3037.8657999990537, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 261.2568000004103, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "namespace_partial_generic_attributes", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.4626000009011477, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "f2958b4d92901e48bc79cb95602dd97f9acc75094171c71096b130e96354bc43", + "lsp_sha256": "b0ffa3094f22b01473580725d49c4b3766228f1ff3dc56917319a31d5050db91", + "direct_bytes": 121, + "lsp_bytes": 124, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-namespace Demo { [System.Serializable] public partial class Sample { public T Run(){throw new System.Exception();}} }\n+namespace Demo { [System.Serializable] public partial class Sample { public T Run(){throw new System.Exception();}} }\n" + } + ], + "setup_ms": 3029.089200001181, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 260.2519000010943, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "replace_preserve_comment", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.4487000005610753, + "failures": [ + "bom_added", + "text_changed" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "6c34cfdc6d1551adcc04b467110a0f49dcd57dbd64161f53b2c40f3d3213acb4", + "lsp_sha256": "b325682282a26cf6d3fffbe65624f11f535ccf233915b4f647defb6d3eea891b", + "direct_bytes": 112, + "lsp_bytes": 83, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1 @@\n-public class Sample { public int Run(){return 2;} // 日本語の説明を保持\n-public int Next(){return 3;} }\n+public class Sample { public int Run(){return 2;}public int Next(){return 3;} }\n" + } + ], + "setup_ms": 3028.714800000671, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 262.7495999986422, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "replace_preserve_comment", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.594900000578491, + "failures": [ + "bom_added", + "text_changed" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "6c34cfdc6d1551adcc04b467110a0f49dcd57dbd64161f53b2c40f3d3213acb4", + "lsp_sha256": "b325682282a26cf6d3fffbe65624f11f535ccf233915b4f647defb6d3eea891b", + "direct_bytes": 112, + "lsp_bytes": 83, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1 @@\n-public class Sample { public int Run(){return 2;} // 日本語の説明を保持\n-public int Next(){return 3;} }\n+public class Sample { public int Run(){return 2;}public int Next(){return 3;} }\n" + } + ], + "setup_ms": 3024.2627000006905, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 260.5406000002404, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "replace_preserve_comment", + "tool": "replace_symbol_body", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.5334999987098854, + "failures": [ + "bom_added", + "text_changed" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "6c34cfdc6d1551adcc04b467110a0f49dcd57dbd64161f53b2c40f3d3213acb4", + "lsp_sha256": "b325682282a26cf6d3fffbe65624f11f535ccf233915b4f647defb6d3eea891b", + "direct_bytes": 112, + "lsp_bytes": 83, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1 @@\n-public class Sample { public int Run(){return 2;} // 日本語の説明を保持\n-public int Next(){return 3;} }\n+public class Sample { public int Run(){return 2;}public int Next(){return 3;} }\n" + } + ], + "setup_ms": 2987.321799999336, + "returncode": 0, + "response": { + "command": "raw replace_symbol_body", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [ + "Sample/Run" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw replace_symbol_body\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[\"Sample/Run\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 257.1067999997467, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "rename_multifile", + "tool": "rename_symbol", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 1.1981999996351078, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "8b604ff92426cc52db63d2309c15a04982106e971961f496c1e7f4e4d4d56fc4", + "lsp_sha256": "6dcbae88500610aa7d38e3f641da418e52421ef87902009d7f8ca51294481a20", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-namespace Demo { public partial class Renamed {} }\n+namespace Demo { public partial class Renamed {} }\n" + }, + { + "path": "Assets/Use.cs", + "direct_sha256": "5feab48ffd84735381e60d33891d68cf7cde00ada091203d28cc830af6563a40", + "lsp_sha256": "009564a8d3056d887a37850f104c973de022a7110d8299ecb80383d52f39a4f8", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Use.cs\n+++ lsp/Assets/Use.cs\n@@ -1 +1 @@\n-namespace Demo { public class Consumer { public Renamed Value; } }\n+namespace Demo { public class Consumer { public Renamed Value; } }\n" + } + ], + "setup_ms": 3007.145200001105, + "returncode": 0, + "response": { + "command": "raw rename_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs", + "Assets/Use.cs" + ], + "changedSymbols": [ + "Renamed" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw rename_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\",\"Assets/Use.cs\"],\"changedSymbols\":[\"Renamed\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 293.2671999988088, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "rename_multifile", + "tool": "rename_symbol", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 1.5234000002237735, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "8b604ff92426cc52db63d2309c15a04982106e971961f496c1e7f4e4d4d56fc4", + "lsp_sha256": "6dcbae88500610aa7d38e3f641da418e52421ef87902009d7f8ca51294481a20", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-namespace Demo { public partial class Renamed {} }\n+namespace Demo { public partial class Renamed {} }\n" + }, + { + "path": "Assets/Use.cs", + "direct_sha256": "5feab48ffd84735381e60d33891d68cf7cde00ada091203d28cc830af6563a40", + "lsp_sha256": "009564a8d3056d887a37850f104c973de022a7110d8299ecb80383d52f39a4f8", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Use.cs\n+++ lsp/Assets/Use.cs\n@@ -1 +1 @@\n-namespace Demo { public class Consumer { public Renamed Value; } }\n+namespace Demo { public class Consumer { public Renamed Value; } }\n" + } + ], + "setup_ms": 3012.4161999992793, + "returncode": 0, + "response": { + "command": "raw rename_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs", + "Assets/Use.cs" + ], + "changedSymbols": [ + "Renamed" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw rename_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\",\"Assets/Use.cs\"],\"changedSymbols\":[\"Renamed\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 294.02939999999944, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "rename_multifile", + "tool": "rename_symbol", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 1.3335999992705183, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "8b604ff92426cc52db63d2309c15a04982106e971961f496c1e7f4e4d4d56fc4", + "lsp_sha256": "6dcbae88500610aa7d38e3f641da418e52421ef87902009d7f8ca51294481a20", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-namespace Demo { public partial class Renamed {} }\n+namespace Demo { public partial class Renamed {} }\n" + }, + { + "path": "Assets/Use.cs", + "direct_sha256": "5feab48ffd84735381e60d33891d68cf7cde00ada091203d28cc830af6563a40", + "lsp_sha256": "009564a8d3056d887a37850f104c973de022a7110d8299ecb80383d52f39a4f8", + "direct_bytes": 67, + "lsp_bytes": 70, + "diff": "--- direct/Assets/Use.cs\n+++ lsp/Assets/Use.cs\n@@ -1 +1 @@\n-namespace Demo { public class Consumer { public Renamed Value; } }\n+namespace Demo { public class Consumer { public Renamed Value; } }\n" + } + ], + "setup_ms": 3045.9191000009014, + "returncode": 0, + "response": { + "command": "raw rename_symbol", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs", + "Assets/Use.cs" + ], + "changedSymbols": [ + "Renamed" + ], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw rename_symbol\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\",\"Assets/Use.cs\"],\"changedSymbols\":[\"Renamed\"],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 296.29690000001574, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "unicode_no_bom_crlf", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.5963000003248453, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "dcf3eb1713c010b8259f7d7246f3f557df2f406a6f87331b07219c6966697a3b", + "lsp_sha256": "d2d48c3889d71a6d5b915edfde91ed49a35a4a3b9e48c9fa35596913bc190569", + "direct_bytes": 83, + "lsp_bytes": 86, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-// 日本語コメント 🐈\r\n+// 日本語コメント 🐈\r\n public class Sample { public int Run(){return 2;}}\r\n" + } + ], + "setup_ms": 3057.0062000006146, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 223.1314000000566, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "unicode_no_bom_crlf", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.5143999987922143, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "dcf3eb1713c010b8259f7d7246f3f557df2f406a6f87331b07219c6966697a3b", + "lsp_sha256": "d2d48c3889d71a6d5b915edfde91ed49a35a4a3b9e48c9fa35596913bc190569", + "direct_bytes": 83, + "lsp_bytes": 86, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-// 日本語コメント 🐈\r\n+// 日本語コメント 🐈\r\n public class Sample { public int Run(){return 2;}}\r\n" + } + ], + "setup_ms": 2852.099100000487, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 219.99809999942954, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "unicode_no_bom_crlf", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.5265999989205739, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "dcf3eb1713c010b8259f7d7246f3f557df2f406a6f87331b07219c6966697a3b", + "lsp_sha256": "d2d48c3889d71a6d5b915edfde91ed49a35a4a3b9e48c9fa35596913bc190569", + "direct_bytes": 83, + "lsp_bytes": 86, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,2 +1,2 @@\n-// 日本語コメント 🐈\r\n+// 日本語コメント 🐈\r\n public class Sample { public int Run(){return 2;}}\r\n" + } + ], + "setup_ms": 3080.259300000762, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 220.59280000030412, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "unicode_bom_crlf", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.5582000012509525, + "failures": [], + "differences": [], + "setup_ms": 3098.4207000001334, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 221.45300000011048, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "unicode_bom_crlf", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.5144999995536637, + "failures": [], + "differences": [], + "setup_ms": 3071.7471999996633, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 223.90329999871028, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "unicode_bom_crlf", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.5811000009998679, + "failures": [], + "differences": [], + "setup_ms": 3043.7713999999687, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 223.55900000002293, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "large_3500_lines", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.6112000010034535, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "eaa743feccdbb5e5488cd91d7d78299beade017c47a0ea09e202ea40f4ed1875", + "lsp_sha256": "5cf2f01510d47655d012cbc1c7db081d1073aa96201f48be3ccde767fc6d03a5", + "direct_bytes": 113302, + "lsp_bytes": 113305, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,4 +1,4 @@\n-public class Sample {\n+public class Sample {\n public int Field0 = 0;\n public int Field1 = 1;\n public int Field2 = 2;\n" + } + ], + "setup_ms": 3169.600700000956, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 253.24469999941357, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "large_3500_lines", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.751499999751104, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "eaa743feccdbb5e5488cd91d7d78299beade017c47a0ea09e202ea40f4ed1875", + "lsp_sha256": "5cf2f01510d47655d012cbc1c7db081d1073aa96201f48be3ccde767fc6d03a5", + "direct_bytes": 113302, + "lsp_bytes": 113305, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,4 +1,4 @@\n-public class Sample {\n+public class Sample {\n public int Field0 = 0;\n public int Field1 = 1;\n public int Field2 = 2;\n" + } + ], + "setup_ms": 3092.7720999989106, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 255.7035999998334, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "large_3500_lines", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.5707999989681412, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "eaa743feccdbb5e5488cd91d7d78299beade017c47a0ea09e202ea40f4ed1875", + "lsp_sha256": "5cf2f01510d47655d012cbc1c7db081d1073aa96201f48be3ccde767fc6d03a5", + "direct_bytes": 113302, + "lsp_bytes": 113305, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1,4 +1,4 @@\n-public class Sample {\n+public class Sample {\n public int Field0 = 0;\n public int Field1 = 1;\n public int Field2 = 2;\n" + } + ], + "setup_ms": 3127.936700000646, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 253.46890000037092, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "repair_syntax_error", + "tool": "apply_csharp_edits", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.97980000100506, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "b03ed722922dca9fdfd87c27472e32c8f90643c5c670f156aef519ac36f960a6", + "lsp_sha256": "ba70d71cf92a2900d9361b83a5876a358484ad591d094070c92b4bcf95c736a0", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 1;}}\n+public class Sample { public int Run(){return 1;}}\n" + }, + { + "path": "Assets/Second.cs", + "direct_sha256": "d62a11646bf6465a334da9c80b94badcb52b96ab98f72972a2ad95c7f63ac45a", + "lsp_sha256": "6f373feff72aab117838b78284f5b3fa36fc0d7fb1d3d5617e646a70bf9e2c7b", + "direct_bytes": 42, + "lsp_bytes": 45, + "diff": "--- direct/Assets/Second.cs\n+++ lsp/Assets/Second.cs\n@@ -1 +1 @@\n-public class Second { public int Added; }\n+public class Second { public int Added; }\n" + } + ], + "setup_ms": 3050.6514999997307, + "returncode": 0, + "response": { + "command": "raw apply_csharp_edits", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs", + "Assets/Second.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw apply_csharp_edits\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\",\"Assets/Second.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 241.70750000121188, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "repair_syntax_error", + "tool": "apply_csharp_edits", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.921599999855971, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "b03ed722922dca9fdfd87c27472e32c8f90643c5c670f156aef519ac36f960a6", + "lsp_sha256": "ba70d71cf92a2900d9361b83a5876a358484ad591d094070c92b4bcf95c736a0", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 1;}}\n+public class Sample { public int Run(){return 1;}}\n" + }, + { + "path": "Assets/Second.cs", + "direct_sha256": "d62a11646bf6465a334da9c80b94badcb52b96ab98f72972a2ad95c7f63ac45a", + "lsp_sha256": "6f373feff72aab117838b78284f5b3fa36fc0d7fb1d3d5617e646a70bf9e2c7b", + "direct_bytes": 42, + "lsp_bytes": 45, + "diff": "--- direct/Assets/Second.cs\n+++ lsp/Assets/Second.cs\n@@ -1 +1 @@\n-public class Second { public int Added; }\n+public class Second { public int Added; }\n" + } + ], + "setup_ms": 3459.9058000003424, + "returncode": 0, + "response": { + "command": "raw apply_csharp_edits", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs", + "Assets/Second.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw apply_csharp_edits\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\",\"Assets/Second.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 244.0794999984064, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "repair_syntax_error", + "tool": "apply_csharp_edits", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.9767000010469928, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "b03ed722922dca9fdfd87c27472e32c8f90643c5c670f156aef519ac36f960a6", + "lsp_sha256": "ba70d71cf92a2900d9361b83a5876a358484ad591d094070c92b4bcf95c736a0", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 1;}}\n+public class Sample { public int Run(){return 1;}}\n" + }, + { + "path": "Assets/Second.cs", + "direct_sha256": "d62a11646bf6465a334da9c80b94badcb52b96ab98f72972a2ad95c7f63ac45a", + "lsp_sha256": "6f373feff72aab117838b78284f5b3fa36fc0d7fb1d3d5617e646a70bf9e2c7b", + "direct_bytes": 42, + "lsp_bytes": 45, + "diff": "--- direct/Assets/Second.cs\n+++ lsp/Assets/Second.cs\n@@ -1 +1 @@\n-public class Second { public int Added; }\n+public class Second { public int Added; }\n" + } + ], + "setup_ms": 3057.992500000182, + "returncode": 0, + "response": { + "command": "raw apply_csharp_edits", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs", + "Assets/Second.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw apply_csharp_edits\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\",\"Assets/Second.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 241.2251000005199, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "validate_without_write", + "tool": "validate_text_edits", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.500300000567222, + "failures": [], + "differences": [], + "setup_ms": 3095.0474000001122, + "returncode": 0, + "response": { + "command": "raw validate_text_edits", + "data": { + "backend": "lsp", + "diagnostics": [], + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw validate_text_edits\",\"data\":{\"backend\":\"lsp\",\"diagnostics\":[],\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 206.67649999995774, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "validate_without_write", + "tool": "validate_text_edits", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.601499999902444, + "failures": [], + "differences": [], + "setup_ms": 3048.9940000006754, + "returncode": 0, + "response": { + "command": "raw validate_text_edits", + "data": { + "backend": "lsp", + "diagnostics": [], + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw validate_text_edits\",\"data\":{\"backend\":\"lsp\",\"diagnostics\":[],\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 207.30180000100518, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + }, + { + "scenario": "validate_without_write", + "tool": "validate_text_edits", + "condition": "warm_indexed", + "sample": 2, + "direct_ms": 0.5584999998973217, + "failures": [], + "differences": [], + "setup_ms": 3071.909800000867, + "returncode": 0, + "response": { + "command": "raw validate_text_edits", + "data": { + "backend": "lsp", + "diagnostics": [], + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw validate_text_edits\",\"data\":{\"backend\":\"lsp\",\"diagnostics\":[],\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 207.53160000094795, + "lsp_version": "checkout", + "lsp_sha256": "f8f5ce4a833238e45da4fa4f9c9f0518bd8527b1a8f3ae3f65009345e0f1c944" + } + ] +} diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md new file mode 100644 index 00000000..b394ce79 --- /dev/null +++ b/docs/lsp-write-reliability.md @@ -0,0 +1,114 @@ +# C# LSP 書き込みの信頼性測定(#490) + +直接編集を禁止できる根拠は、現時点では得られていません。BOM なしの +ファイルへの BOM 追加を Windows の実 CLI / 実 LSP で検出しています。 +全 OS の測定結果は `LSP Write Reliability` CI の JSON / Markdown artifact に +保存します。これは禁止を導入する変更ではなく、オーナー判断のための測定です。 + +## 初期測定と修正が必要な不具合 + +2026-10-13 の Windows / checkout LSP / `warm_indexed` 初期測定は +19 シナリオを各 3 回、計 57 試行です。期待バイト列と一致したのは 6 試行 +(10.53%)。BOM あり CRLF の更新と検証のみが一致しました。 +全試行の LSP p50 は 260.755 ms、p95 は 293.267 ms です。 +これは厳密なバイト一致率であり、処理が実行された率や意味的に正しいコードの率ではありません。 + +| 不具合 | 実測 | 禁止前に必要な修正 | +| --- | --- | --- | +| BOM なしのファイルへ BOM を追加 | BOM なしの変更シナリオすべてで EF BB BF を追加 | 既存の BOM / 改行を保存し、新規ファイルの規約を定める | +| `replace_symbol_body` が末尾コメントを消す | 日本語コメントと改行が 3/3 消失し、次のメンバーと連結 | 置換前 Body の末尾 trivia を保持する | +| `create_class` の ScriptableObject 作成が using を欠く | `using UnityEngine` が 3/3 欠落 | 非修飾 ScriptableObject が名前解決できるテンプレートにする | + +生応答とバイト差分は [Windows 初期測定の証跡](lsp-write-reliability-windows.json) に保存しています。 +製品修正は個別の不具合 Issue として PM に登録を依頼しています。 +3 OS / 全起動条件の結論は CI artifact の完成したマトリクスを参照してください。 + +## 再現 + +.NET 10、Rust、Python 3.11 以上を使用します。Unity Editor は不要です。 +リポジトリ直下から、対象 OS の RID に合わせて実行します。 + +```bash +cargo build --bin unity-cli +dotnet publish lsp/Server.csproj -c Release -r win-x64 --self-contained true -o .cache/lsp-reliability-publish +python scripts/lsp-write-reliability.py --unity-cli target/debug/unity-cli.exe --lsp-publish .cache/lsp-reliability-publish --out .cache/lsp-reliability --repetitions 20 --download-repetitions 1 --baseline tests/fixtures/lsp-write-baseline.json +``` + +macOS は `osx-arm64` / `osx-x64`、Linux は `linux-x64` / `linux-arm64` を +指定し、CLI パスから `.exe` を除きます。初回ダウンロードにはネットワーク接続が +必要です。既知の失敗も含めて収集するだけなら `--baseline` の代わりに +`--record-only` を指定します。観測した失敗は、どちらのモードでも失敗のまま保存します。 + +## シナリオと起動条件 + +全 10 ツールを 19 シナリオで測定します。 + +| 作業 | ツール / 入力 | +| --- | --- | +| MonoBehaviour / ScriptableObject / 通常クラスの新規作成 | `create_class` と `create_csharp_file` の各 3 種 | +| メソッド本体の置換 | `replace_symbol_body`、通常・namespace/partial/ジェネリクス/属性・日本語の末尾コメント | +| メンバー追加・削除 | `insert_before_symbol` / `insert_after_symbol` / `remove_symbol` | +| ファイル全体の更新 | `write_csharp_file` | +| 複数ファイルのリネーム | `rename_symbol`、別 namespace の同名型は変更しない | +| 日本語 / 絵文字 / UTF-8 / CRLF | BOM ありとなしの両方で `write_csharp_file` | +| 大きなファイル | 3,502 行、最後のフィールドを更新 | +| 構文エラーの修正・複数ファイル更新 | `apply_csharp_edits` | +| 構文検証のみ | `validate_text_edits`、ディスクが変更されないことも検証 | + +| 条件 | 測定開始時の状態 | +| --- | --- | +| `warm_indexed` | 専用 lspd を起動し、そのプロジェクトで `build_index` を完了済み | +| `daemon_stopped` | LSP はインストール済み、lspd は停止。CLI の自動起動を含む | +| `unindexed` | lspd は起動済み、プロジェクトのインデックスは未構築 | +| `first_download` | LSP 未導入の専用 tools root。CLI が公開 LSP を実際に取得する | + +各シナリオ・各試行で空の専用プロジェクトと tools root を使用します。 +直接編集の oracle は独立した期待バイト列を書き込み、LSP 結果から生成しません。 +大きな入力は `--params-file` を使い、Windows のコマンドライン長制限を避けます。 +Windows の lspd はポート 6421 を共有するため、既存の利用者がいる場合は起動失敗として +記録し、他プロセスを停止しません。Unix は試行ごとの専用ソケットを使用します。 + +## 記録と判定 + +`results.json` に OS / RID / CLI SHA256 / LSP SHA256 と VERSION、試行数、 +成功率、各試行の所要時間、失敗分類、CLI の生応答、期待結果との SHA256・バイト数・ +unified diff を記録します。p50 / p95 は失敗を含む全試行の nearest-rank 値です。 +直接編集はファイル書き込み時間、LSP は CLI 起動・パラメーター読込・LSP 呼び出しを含む +時間です。事前のデーモン起動・インデックス構築は `setup_ms` に分離します。 + +成功には CLI と payload の成功、`backend: lsp`、全 `.cs` ファイルの期待バイト列との +一致が必要です。文字列の見た目が同じでも BOM の追加・除去、改行変換を失敗に数えます。 +`text_changed` は空白の差も含む厳密な差分で、意味的誤編集とは自動的に断定しません。 +`lsp_startup_failure` / `timeout` / `download_failure` / `tool_rejected` / `wrong_backend` / +`other` と、`bom_added` / `bom_removed` / `newlines_changed` / `text_changed` / +`file_set_changed` を分け、複数の原因がある試行は各原因を記録します。 + +初回ダウンロードは公開済み LSP、インデックス構築済み/未構築は checkout の LSP を測ります。 +デーモンの自動起動には LSP 自動更新があるため、この条件の実際の VERSION / SHA256 も +記録して区別します。Unity の AssetDatabase refresh、コンパイル、Editor +インポートの信頼性はこの測定の範囲外です。 + +目安は全シナリオ・全 OS で成功率 99% 以上、誤編集・エンコーディング/改行破壊 0 件です。 +OS / 条件 / シナリオが欠ける結果は `INSUFFICIENT`、失敗がある完全なマトリクスは +`DO NOT ENFORCE` と報告します。少数試行での 100% は将来の 99% の保証にはなりません。 +CI は PR / develop push の各 3 試行、週次と手動実行の既定は各 20 試行です。 +PR / push は `Test` workflow から呼び出します。既存の必須 +`CLI Latency (required)` は全 OS の測定完了を待ち、測定失敗時には明示的に失敗します。 +依存 job の skip が成功扱いになる経路も `if: always()` と結果チェックで防ぎます。 +デーモン停止・初回ダウンロードは各シナリオ 1 試行を別枠で記録します。 +`--cold-repetitions` / `--download-repetitions` で増やせます。 + +既知の不具合は `tests/fixtures/lsp-write-baseline.json` にシナリオ単位で明記します。 +これは合格率を補正する仕組みではありません。既知の失敗はレポート上も失敗です。 +CI は baseline に含まれない失敗を終了コード 1 で拒否します。既知のテキスト差分も +正規化した内容の SHA256 を照合し、別の誤編集を隠しません。修正による失敗の解消は +許可します。baseline の変更は再現証跡と不具合 Issue を伴うレビュー対象です。 +無関係のファイルへの BOM 追加も regression として拒否します。 +再測定を絞る場合は `--scenarios create_plain` のように指定できます。絞った実行は +完全なマトリクスの代わりにならず、レポートの欠けたセル数に反映します。 + +Launch mode: autonomous + +User Verification Result: n/a (autonomous) + +Agent Visual Check: n/a (no UI surface) diff --git a/scripts/lsp-write-reliability.py b/scripts/lsp-write-reliability.py new file mode 100644 index 00000000..b5900742 --- /dev/null +++ b/scripts/lsp-write-reliability.py @@ -0,0 +1,432 @@ +"""Measure real CLI/LSP writes against independent direct-edit byte oracles (#490). + +No Unity Editor is needed: syntax and filesystem editing are the measured surface. +Failure observations are data; an explicit baseline gates *new* checkout regressions. +The initial-download route deliberately measures the published LSP, not a mock. +""" +import argparse +from collections import Counter +from datetime import datetime, timezone +import difflib +import hashlib +import json +import math +import os +from pathlib import Path +import platform +import shutil +import socket +import subprocess +import tempfile +import time + +CONDITIONS = ("warm_indexed", "daemon_stopped", "unindexed", "first_download") +OS_NAMES = ("Windows", "macOS", "Linux") +BOM = b"\xef\xbb\xbf" +CORRUPTION = {"bom_added", "bom_removed", "newlines_changed", "text_changed", "file_set_changed", "wrong_backend"} + + +def scenarios(): + cases = [] + + def add(scenario_name, tool, before, after, **params): + encode = lambda files: {key: value.encode("utf-8") for key, value in files.items()} + cases.append({"id": scenario_name, "tool": tool, "before": encode(before), + "after": encode(after), "params": params}) + + path = "Assets/Sample.cs" + for kind, parent in (("monobehaviour", "MonoBehaviour"), ("scriptableobject", "ScriptableObject"), ("plain", None)): + text = ("using UnityEngine;\n\n" if parent else "") + "public class Sample" + (f" : {parent}" if parent else "") + "\n{\n}\n" + add("create_class_" + kind, "create_class", {}, {path: text}, name="Sample", path=path, **({"inherits": parent} if parent else {})) + for kind, text in ( + ("plain", "public class Sample {}\n"), + ("monobehaviour", "using UnityEngine;\npublic class Sample : MonoBehaviour {}\n"), + ("scriptableobject", "using UnityEngine;\npublic class Sample : ScriptableObject {}\n"), + ): + add("create_" + kind, "create_csharp_file", {}, {path: text}, relative=path, text=text) + original = "public class Sample { public int Run(){return 1;}}\n" + updated = original.replace("return 1;", "return 2;") + add("replace_body", "replace_symbol_body", {path: original}, {path: updated}, relative=path, namePath="Sample/Run", body="{return 2;}") + add("write_file", "write_csharp_file", {path: original}, {path: updated}, relative=path, newText=updated) + # Compact source makes insertion/removal trivia unambiguous to the direct oracle. + member = "public int Added;" + compact = "public class Sample {public int Run(){return 1;}}\n" + add("insert_before", "insert_before_symbol", {path: compact}, {path: compact.replace("public int Run", member + "public int Run")}, relative=path, namePath="Sample/Run", text=member) + add("insert_after", "insert_after_symbol", {path: compact}, {path: compact.replace("return 1;}", "return 1;}" + member)}, relative=path, namePath="Sample/Run", text=member) + add("remove_member", "remove_symbol", {path: compact}, {path: "public class Sample {}\n"}, relative=path, namePath="Sample/Run") + shaped = "namespace Demo { [System.Serializable] public partial class Sample { public T Run(){return default(T);}} }\n" + add("namespace_partial_generic_attributes", "replace_symbol_body", {path: shaped}, {path: shaped.replace("return default(T);", "throw new System.Exception();")}, relative=path, namePath="Sample/Run", body="{throw new System.Exception();}") + commented = "public class Sample { public int Run(){return 1;} // 日本語の説明を保持\npublic int Next(){return 3;} }\n" + add("replace_preserve_comment", "replace_symbol_body", {path: commented}, {path: commented.replace("return 1;", "return 2;")}, relative=path, namePath="Sample/Run", body="{return 2;}") + declaration = "namespace Demo { public partial class Sample {} }\n" + use = "namespace Demo { public class Consumer { public Sample Value; } }\n" + unrelated = "namespace Other { public class Sample {} public class Consumer { public Sample Value; } }\n" + add("rename_multifile", "rename_symbol", {path: declaration, "Assets/Use.cs": use, "Assets/Other.cs": unrelated}, + {path: declaration.replace("Sample", "Renamed"), "Assets/Use.cs": use.replace("Sample", "Renamed"), "Assets/Other.cs": unrelated}, + relative=path, namePath="Sample", newName="Renamed") + for bom in (False, True): + unicode = ("\ufeff" if bom else "") + "// 日本語コメント 🐈\r\n" + original.replace("\n", "\r\n") + new = unicode.replace("return 1;", "return 2;") + # The BOM is a file encoding property, not part of the LSP newText string. + add("unicode_" + ("bom" if bom else "no_bom") + "_crlf", "write_csharp_file", {path: unicode}, {path: new}, relative=path, newText=new.lstrip("\ufeff")) + large = "public class Sample {\n" + "".join(f" public int Field{i} = {i};\n" for i in range(3500)) + "}\n" + large_new = large.replace("Field3499 = 3499", "Field3499 = 42") + add("large_3500_lines", "write_csharp_file", {path: large}, {path: large_new}, relative=path, newText=large_new) + broken = "public class Sample { public int Run(){return 1} }\n" + add("repair_syntax_error", "apply_csharp_edits", {path: broken, "Assets/Second.cs": "public class Second {}\n"}, + {path: original, "Assets/Second.cs": "public class Second { public int Added; }\n"}, + files=[{"relative": path, "newText": original}, {"relative": "Assets/Second.cs", "newText": "public class Second { public int Added; }\n"}]) + add("validate_without_write", "validate_text_edits", {path: original}, {path: original}, relative=path, newText=updated) + return cases + + +def compare_files(expected, actual): + signatures, differences = set(), [] + for name in sorted(set(expected) | set(actual)): + before, after = expected.get(name), actual.get(name) + if before == after: + continue + if before is None or after is None: + signatures.add("file_set_changed") + else: + if before.startswith(BOM) != after.startswith(BOM): + signatures.add("bom_removed" if before.startswith(BOM) else "bom_added") + left, right = before.removeprefix(BOM), after.removeprefix(BOM) + if left.replace(b"\r\n", b"\n") == right.replace(b"\r\n", b"\n"): + if left != right: + signatures.add("newlines_changed") + else: + signatures.add("text_changed") + left_text = (before or b"").decode("utf-8", errors="replace").splitlines(keepends=True) + right_text = (after or b"").decode("utf-8", errors="replace").splitlines(keepends=True) + differences.append({"path": name, "direct_sha256": hashlib.sha256(before).hexdigest() if before is not None else None, + "lsp_sha256": hashlib.sha256(after).hexdigest() if after is not None else None, + "direct_text_sha256": hashlib.sha256(before.removeprefix(BOM).replace(b"\r\n", b"\n")).hexdigest() if before is not None else None, + "lsp_text_sha256": hashlib.sha256(after.removeprefix(BOM).replace(b"\r\n", b"\n")).hexdigest() if after is not None else None, + "direct_bytes": len(before) if before is not None else None, + "lsp_bytes": len(after) if after is not None else None, + "diff": "".join(difflib.unified_diff(left_text, right_text, fromfile="direct/" + name, tofile="lsp/" + name))}) + return sorted(signatures), differences + + +def response_failures(returncode, envelope): + data = envelope.get("data", {}) + if not isinstance(data, dict): + return ["other"] + if data.get("success") is False: + return ["tool_rejected"] + if returncode != 0 or envelope.get("success") is not True or data.get("success") is not True: + return ["other"] + return [] if data.get("backend") == "lsp" else ["wrong_backend"] + + +def summarize(rows): + def percentile(key, fraction): + values = sorted(row[key] for row in rows) + return round(values[max(0, math.ceil(len(values) * fraction) - 1)], 3) if values else None + failures = Counter(failure for row in rows for failure in row["failures"]) + return {"attempts": len(rows), "successes": sum(not row["failures"] for row in rows), + "success_rate": sum(not row["failures"] for row in rows) / len(rows) if rows else 0, + "failure_types": dict(failures), "p50_ms": percentile("elapsed_ms", 0.5), "p95_ms": percentile("elapsed_ms", 0.95), + "direct_p50_ms": percentile("direct_ms", 0.5), "direct_p95_ms": percentile("direct_ms", 0.95)} + + +def regressions(rows, baseline): + result = [] + expected_paths = {case["id"]: {name for name in set(case["before"]) | set(case["after"]) + if case["before"].get(name) != case["after"].get(name)} for case in scenarios()} + for row in rows: + known = baseline.get(row["scenario"], {}) + allowed = known.get("failures", []) if isinstance(known, dict) else known + new = set(row["failures"]) - set(allowed) + if row["scenario"] in expected_paths and any(d["path"] not in expected_paths[row["scenario"]] for d in row.get("differences", [])): + new.add("unexpected_file_difference") + # A known text defect may never mask a different destructive edit. + if "text_changed" in row["failures"]: + hashes = known.get("text_hashes", {}) if isinstance(known, dict) else {} + changes = [d for d in row.get("differences", []) if d.get("direct_text_sha256") != d.get("lsp_text_sha256")] + if not changes or any(hashes.get(d["path"]) != d.get("lsp_text_sha256") for d in changes): + new.add("unexpected_text_difference") + if new: + result.append({"scenario": row["scenario"], "condition": row.get("condition"), "new_failures": sorted(new)}) + return result + + +def markdown(reports): + groups = {} + for report in reports: + for row in report["rows"]: + groups.setdefault((report["os"], row["condition"], row["scenario"]), []).append(row) + missing = [f"{system}/{condition}/{case['id']}" for system in OS_NAMES for condition in CONDITIONS for case in scenarios() + if (system, condition, case["id"]) not in groups] + corrupt = any(CORRUPTION.intersection(row["failures"]) for rows in groups.values() for row in rows) + incomplete = missing or any(report.get("interrupted") or not report.get("finished_at") for report in reports) + qualification = "INSUFFICIENT" if incomplete else "ELIGIBLE" if not corrupt and all(summarize(rows)["success_rate"] >= 0.99 for rows in groups.values()) else "DO NOT ENFORCE" + lines = ["# C# LSP write reliability", "", f"Decision evidence: **{qualification}**.", "", + "直接編集の禁止はオーナー判断です。全シナリオ・全 OS で成功率 99% 以上、誤編集・BOM/改行の破壊 0 件を目安にします。", + "バイト差分がある試行は失敗として数えます。少数サンプルの 100% は将来の 99% の保証ではありません。", + "初回ダウンロードは公開 LSP、warm/unindexed は checkout LSP、自動起動は LSP 更新を含みます。各試行の VERSION/SHA256 を区別します。Unity のコンパイル・refresh は測定範囲外です。", "", + "Launch mode: autonomous", "User Verification Result: n/a (autonomous)", "Agent Visual Check: n/a (no UI surface)", "", + "| OS | Condition | Scenario | Success / attempts | Rate | LSP p50 / p95 ms | Direct p50 / p95 ms | Failure signatures |", + "| --- | --- | --- | --- | --- | --- | --- | --- |"] + for (system, condition, scenario), rows in sorted(groups.items()): + value = summarize(rows) + lines.append(f"| {system} | {condition} | {scenario} | {value['successes']}/{value['attempts']} | {value['success_rate']:.1%} | {value['p50_ms']} / {value['p95_ms']} | {value['direct_p50_ms']} / {value['direct_p95_ms']} | {json.dumps(value['failure_types'])} |") + lines += ["", "## Coverage", "", f"Missing OS/condition/scenario cells: {len(missing)}."] + if missing: + lines.append("Missing operating systems: " + ", ".join(system for system in OS_NAMES if not any(key[0] == system for key in groups))) + lines += ["", "## Defects to fix before enforcement", ""] + defects = sorted({failure for rows in groups.values() for row in rows for failure in row["failures"]}) + lines += ["- " + failure + ": see per-attempt raw response, SHA256 and unified diff in the JSON artifact." for failure in defects] + if not defects: + lines.append("No defects observed in executed samples; unexecuted cells remain unproven.") + return "\n".join(lines) + "\n" + + +def rid(): + system = {"Windows": "win", "Darwin": "osx", "Linux": "linux"}[platform.system()] + architecture = "arm64" if platform.machine().lower() in ("arm64", "aarch64") else "x64" + return system + "-" + architecture + + +def write_files(root, files): + for name, data in files.items(): + path = root / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + + +def snapshot(root): + return {path.relative_to(root).as_posix(): path.read_bytes() for path in root.rglob("*.cs")} + + +def sha256_file(path): + with path.open("rb") as stream: + return hashlib.file_digest(stream, "sha256").hexdigest() + + +def cleanup_trial(directory, root): + if not directory.resolve().is_relative_to(root.resolve()) or directory.resolve() == root.resolve(): + raise RuntimeError("refusing to clean a trial outside the measurement directory") + deadline = time.monotonic() + 10 + while True: + try: + shutil.rmtree(directory) + return + except PermissionError: + # Windows can keep clrjit.dll locked briefly after lspd exits. + if time.monotonic() >= deadline: + raise + time.sleep(0.1) + + +class Trial: + def __init__(self, cli, lsp_publish, root, condition, timeout): + self.cli, self.root, self.condition, self.timeout = cli, root, condition, timeout + self.project = root / "project" + (self.project / "Assets").mkdir(parents=True) + self.tools = root / "tools" + self.env = os.environ.copy() + self.env.update({"UNITY_CLI_TOOLS_ROOT": str(self.tools), "UNITY_CLI_CACHE_ROOT": str(root / "cache"), + "UNITY_CLI_REGISTRY_PATH": str(root / "registry.json"), "UNITY_PROJECT_ROOT": str(self.project), + "UNITY_CLI_LSP_MODE": "required", "UNITY_CLI_NO_AUTO_UPDATE": "1", "UNITY_CLI_LSPD_IDLE_TIMEOUT": "30"}) + # Never silently inherit a switch which disables the real download route. + self.env.pop("UNITY_CLI_TEST_SKIP_MANAGED_UPDATE", None) + install = self.tools / "unity-cli" / rid() + install.mkdir(parents=True) + shutil.copy2(cli, install / cli.name) + (install / "VERSION").write_text("checkout\n", encoding="utf-8") + self.server = self.tools / "csharp-lsp" / rid() / ("server.exe" if os.name == "nt" else "server") + if condition != "first_download": + shutil.copytree(lsp_publish, self.server.parent) + source = self.server.parent / ("Server.exe" if os.name == "nt" else "Server") + if source != self.server and (os.name != "nt" or source.name.lower() != self.server.name.lower()): + shutil.copy2(source, self.server) + self.server.chmod(0o755) + (self.server.parent / "VERSION").write_text("checkout\n", encoding="utf-8") + self.env["UNITY_CLI_TEST_SKIP_MANAGED_UPDATE"] = "1" + self.process = None + self.log = None + + def command(self, args): + return [str(self.cli), "--output", "json", "--project-path", str(self.project), *args] + + def call(self, tool, params): + # --params-file also covers large inputs on Windows without its argv limit. + payload = self.root / "params.json" + payload.write_text(json.dumps(params, ensure_ascii=False), encoding="utf-8") + command = self.command(["raw", tool, "--params-file", str(payload)]) + completed = subprocess.run(command, env=self.env, capture_output=True, timeout=self.timeout) + stdout = completed.stdout.decode("utf-8", errors="replace") + stderr = completed.stderr.decode("utf-8", errors="replace") + try: + envelope = json.loads(stdout) + except ValueError: + envelope = {} + return completed.returncode, envelope, stdout, stderr + + def start(self): + # Windows lspd currently has a host-wide fixed port. Refuse to share it. + if os.name == "nt": + with socket.socket() as probe: + if probe.connect_ex(("127.0.0.1", 6421)) == 0: + raise RuntimeError("lsp_startup_failure: lspd port 6421 already occupied; no process was stopped") + self.log = (self.root / "daemon.log").open("wb") + self.process = subprocess.Popen(self.command(["lspd", "serve"]), env=self.env, stdout=self.log, stderr=subprocess.STDOUT) + deadline = time.monotonic() + 20 + while time.monotonic() < deadline: + if self.process.poll() is not None: + raise RuntimeError("lsp_startup_failure: owned lspd exited: " + (self.root / "daemon.log").read_text(errors="replace")) + completed = subprocess.run(self.command(["lspd", "status"]), env=self.env, capture_output=True, timeout=10) + try: + if json.loads(completed.stdout).get("data", {}).get("running") is True: + return + except ValueError: + pass + time.sleep(0.05) + raise RuntimeError("lsp_startup_failure: owned lspd did not become ready") + + def close(self): + # A PID file in this unique tools root identifies the auto-started daemon. + pid_file = self.tools / "run" / "lspd" / "lspd.pid" + owned = pid_file.exists() + if owned and self.process is not None: + owned = pid_file.read_text().strip() == str(self.process.pid) + if owned: + try: + subprocess.run(self.command(["lspd", "stop"]), env=self.env, capture_output=True, timeout=15) + except subprocess.TimeoutExpired: + pass + if self.process is not None: + try: + self.process.wait(timeout=10) + except subprocess.TimeoutExpired: + self.process.kill() # Only the exact child started by this trial. + self.process.wait(timeout=10) + if self.log is not None: + self.log.close() + + +def measure(cli, lsp_publish, output, condition, case, sample, timeout): + directory = output / "trials" / f"{condition}-{case['id']}-{sample}" + directory.mkdir(parents=True) + trial = Trial(cli, lsp_publish, directory, condition, timeout) + write_files(trial.project, case["before"]) + direct = directory / "direct" + write_files(direct, case["before"]) + started = time.perf_counter() + for name in set(case["before"]) - set(case["after"]): + (direct / name).unlink() + write_files(direct, case["after"]) + direct_ms = (time.perf_counter() - started) * 1000 + row = {"scenario": case["id"], "tool": case["tool"], "condition": condition, "sample": sample, + "direct_ms": direct_ms, "failures": [], "differences": []} + started = time.perf_counter() + try: + if condition in ("warm_indexed", "unindexed"): + trial.start() + elif os.name == "nt": + with socket.socket() as probe: + if probe.connect_ex(("127.0.0.1", 6421)) == 0: + raise RuntimeError("lsp_startup_failure: lspd port 6421 already occupied") + if condition == "warm_indexed": + rc, value, _, error = trial.call("build_index", {}) + if rc or value.get("success") is not True: + raise RuntimeError("lsp_startup_failure: index setup failed: " + error + json.dumps(value)) + row["setup_ms"] = (time.perf_counter() - started) * 1000 + started = time.perf_counter() + params = dict(case["params"]) + if case["tool"] not in ("validate_text_edits", "create_class"): + params["apply"] = True + if case["tool"] in ("create_csharp_file", "write_csharp_file", "apply_csharp_edits"): + params.update({"refresh": False, "waitForCompile": False}) + rc, value, stdout, stderr = trial.call(case["tool"], params) + row.update({"returncode": rc, "response": value, "stdout": stdout, "stderr": stderr}) + row["failures"] = response_failures(rc, value) + error = (stdout + stderr).lower() + if row["failures"]: + if "timeout" in error or "timed out" in error: + row["failures"] = ["timeout"] + elif "failed to start" in error or "failed to spawn" in error or "failed to connect" in error: + row["failures"] = ["lsp_startup_failure"] + elif "manifest" in error or "download" in error: + row["failures"] = ["download_failure"] + except subprocess.TimeoutExpired as error: + row.update({"failures": ["timeout"], "error": str(error)}) + except (RuntimeError, OSError) as error: + row.update({"failures": ["lsp_startup_failure"], "error": str(error)}) + finally: + row["elapsed_ms"] = (time.perf_counter() - started) * 1000 + signatures, row["differences"] = compare_files(snapshot(direct), snapshot(trial.project)) + row["failures"] = sorted(set(row["failures"] + signatures)) + if trial.server.exists(): + row["lsp_version"] = (trial.server.parent / "VERSION").read_text().strip() + row["lsp_sha256"] = sha256_file(trial.server) + trial.close() + # Delete only this generated trial, after resolving its boundary explicitly. + cleanup_trial(directory, output) + return row + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--unity-cli", type=Path) + parser.add_argument("--lsp-publish", type=Path) + parser.add_argument("--out", type=Path, required=True) + parser.add_argument("--repetitions", type=int, default=5) + parser.add_argument("--download-repetitions", type=int, default=1) + parser.add_argument("--cold-repetitions", type=int, default=1) + parser.add_argument("--conditions", default=",".join(CONDITIONS)) + parser.add_argument("--scenarios", help="Comma-separated scenario IDs for a focused recovery run; default: all") + parser.add_argument("--timeout", type=int, default=180) + parser.add_argument("--baseline", type=Path) + parser.add_argument("--record-only", action="store_true", help="Collect failures as evidence without a regression gate") + parser.add_argument("--merge", type=Path, nargs="+", help="Aggregate existing JSON reports; no tests are executed") + args = parser.parse_args() + args.out = args.out.resolve() + args.out.mkdir(parents=True, exist_ok=True) + if args.merge: + reports = [json.loads(path.read_text(encoding="utf-8")) for path in args.merge] + (args.out / "summary.md").write_text(markdown(reports), encoding="utf-8") + return 0 + conditions = args.conditions.split(",") + cases = scenarios() + if args.scenarios: + selected = args.scenarios.split(",") + if any(name not in {case["id"] for case in cases} for name in selected): + parser.error("unknown scenario ID") + cases = [case for case in cases if case["id"] in selected] + if not args.unity_cli or not args.lsp_publish or min(args.repetitions, args.download_repetitions, args.cold_repetitions) < 1 or any(c not in CONDITIONS for c in conditions): + parser.error("supply --unity-cli/--lsp-publish, positive repetitions and valid conditions") + cli, publish = args.unity_cli.resolve(), args.lsp_publish.resolve() + if not cli.is_file() or not (publish / ("Server.exe" if os.name == "nt" else "Server")).is_file(): + parser.error("build the CLI and publish the real LSP for the current RID first") + # Use a short temporary path on Unix for the daemon's Unix socket limit. + reports = {"schema_version": 1, "os": "macOS" if platform.system() == "Darwin" else platform.system(), + "rid": rid(), "started_at": datetime.now(timezone.utc).isoformat(), "cli_sha256": sha256_file(cli), + "runner_sha256": sha256_file(Path(__file__)), + "requested_conditions": conditions, "repetitions": args.repetitions, + "cold_repetitions": args.cold_repetitions, "download_repetitions": args.download_repetitions, + "rows": []} + with tempfile.TemporaryDirectory(prefix="lsp490-") as temp: + for condition in conditions: + count = args.download_repetitions if condition == "first_download" else args.cold_repetitions if condition == "daemon_stopped" else args.repetitions + for case in cases: + for sample in range(count): + row = measure(cli, publish, Path(temp), condition, case, sample, args.timeout) + reports["rows"].append(row) + print(f"{condition}/{case['id']}/{sample}: {','.join(row['failures']) or 'PASS'}", flush=True) + # Persist each measured row so a later abort cannot erase evidence. + (args.out / "results.json").write_text(json.dumps(reports, ensure_ascii=False, indent=2), encoding="utf-8") + reports["summary"] = summarize(reports["rows"]) + baseline = json.loads(args.baseline.read_text(encoding="utf-8")) if args.baseline else {} + reports["regressions"] = regressions(reports["rows"], baseline) + reports["finished_at"] = datetime.now(timezone.utc).isoformat() + (args.out / "results.json").write_text(json.dumps(reports, ensure_ascii=False, indent=2), encoding="utf-8") + (args.out / "summary.md").write_text(markdown([reports]), encoding="utf-8") + print(json.dumps(reports["summary"])) + return 1 if reports["regressions"] and not args.record_only else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/fixtures/lsp-write-baseline.json b/tests/fixtures/lsp-write-baseline.json new file mode 100644 index 00000000..26103c16 --- /dev/null +++ b/tests/fixtures/lsp-write-baseline.json @@ -0,0 +1,29 @@ +{ + "create_class_monobehaviour": ["bom_added"], + "create_class_scriptableobject": { + "failures": ["bom_added", "text_changed"], + "text_hashes": { + "Assets/Sample.cs": "34eedc1cdabfdb43cffc3403e71f8936963c55797ffc0308f43d6a86a2efdecc" + } + }, + "create_class_plain": ["bom_added"], + "create_plain": ["bom_added"], + "create_monobehaviour": ["bom_added"], + "create_scriptableobject": ["bom_added"], + "replace_body": ["bom_added"], + "write_file": ["bom_added"], + "insert_before": ["bom_added"], + "insert_after": ["bom_added"], + "remove_member": ["bom_added"], + "namespace_partial_generic_attributes": ["bom_added"], + "replace_preserve_comment": { + "failures": ["bom_added", "text_changed"], + "text_hashes": { + "Assets/Sample.cs": "215a30f2eaeefdd4d211dd6ada4e5aab889d1a2617366f1343808a9c1540ab68" + } + }, + "rename_multifile": ["bom_added"], + "unicode_no_bom_crlf": ["bom_added"], + "large_3500_lines": ["bom_added"], + "repair_syntax_error": ["bom_added"] +} diff --git a/tests/scripts/test_lsp_write_reliability.py b/tests/scripts/test_lsp_write_reliability.py new file mode 100644 index 00000000..e95f97cc --- /dev/null +++ b/tests/scripts/test_lsp_write_reliability.py @@ -0,0 +1,119 @@ +"""Protect the reliability measurement from false PASS and hidden regressions.""" +import importlib.util +from pathlib import Path +import unittest +from unittest import mock + +ROOT = Path(__file__).resolve().parents[2] +SPEC = importlib.util.spec_from_file_location("reliability", ROOT / "scripts/lsp-write-reliability.py") +reliability = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(reliability) + + +class ReliabilityTests(unittest.TestCase): + def test_scenarios_cover_every_write_tool_and_large_unicode_inputs(self): + cases = reliability.scenarios() + self.assertEqual({case["tool"] for case in cases}, { + "create_csharp_file", "write_csharp_file", "apply_csharp_edits", + "replace_symbol_body", "insert_before_symbol", "insert_after_symbol", + "remove_symbol", "rename_symbol", "validate_text_edits", "create_class", + }) + self.assertGreater(max(data.count(b"\n") for case in cases for data in case["before"].values()), 3000) + self.assertTrue(any(data.startswith(b"\xef\xbb\xbf") and b"\r\n" in data + for case in cases for data in case["before"].values())) + + def test_byte_comparison_distinguishes_bom_newlines_text_and_extra_files(self): + expected = {"Assets/A.cs": "// 日本語\r\nclass A {}\r\n".encode()} + actual = {"Assets/A.cs": b"\xef\xbb\xbf" + expected["Assets/A.cs"].replace(b"\r\n", b"\n"), + "Assets/Unexpected.cs": b"class Extra {}"} + signatures, differences = reliability.compare_files(expected, actual) + self.assertEqual(set(signatures), {"bom_added", "newlines_changed", "file_set_changed"}) + self.assertEqual(len(differences), 2) + self.assertIn("--- direct/", differences[0]["diff"]) + self.assertEqual(reliability.compare_files(expected, expected), ([], [])) + self.assertIn("text_changed", reliability.compare_files(expected, {"Assets/A.cs": b"class Wrong {}"})[0]) + + def test_false_success_or_fallback_is_not_a_successful_lsp_edit(self): + self.assertEqual(reliability.response_failures(0, {"success": True, "data": {"success": False, "backend": "lsp"}}), ["tool_rejected"]) + self.assertEqual(reliability.response_failures(0, {"success": True, "data": {"success": True, "backend": "unity"}}), ["wrong_backend"]) + self.assertEqual(reliability.response_failures(0, {"success": True, "data": {"success": True, "backend": "lsp"}}), []) + + def test_nearest_rank_percentiles_and_rate_include_failed_attempts(self): + rows = [{"elapsed_ms": n, "direct_ms": 1, "failures": [] if n < 100 else ["timeout"]} + for n in range(1, 101)] + summary = reliability.summarize(rows) + self.assertEqual(summary["success_rate"], 0.99) + self.assertEqual(summary["p50_ms"], 50) + self.assertEqual(summary["p95_ms"], 95) + self.assertEqual(summary["failure_types"], {"timeout": 1}) + self.assertEqual(reliability.summarize([])["success_rate"], 0) + + def test_regression_baseline_allows_only_exact_documented_signatures(self): + baseline = {"replace": ["bom_added"]} + self.assertEqual(reliability.regressions([{"scenario": "replace", "failures": ["bom_added"]}], baseline), []) + self.assertTrue(reliability.regressions([{"scenario": "replace", "failures": ["bom_added", "text_changed"]}], baseline)) + self.assertTrue(reliability.regressions([{"scenario": "new", "failures": ["bom_added"]}], baseline)) + self.assertEqual(reliability.regressions([{"scenario": "replace", "failures": []}], baseline), []) + + def test_missing_os_or_condition_never_produces_enforcement_recommendation(self): + report = {"os": "Windows", "rows": [{"scenario": "create_plain", "condition": "warm_indexed", "failures": [], "elapsed_ms": 1, "direct_ms": 1}]} + text = reliability.markdown([report]) + self.assertIn("Windows", text) + self.assertIn("INSUFFICIENT", text) + self.assertIn("macOS", text) + self.assertIn("Linux", text) + + def test_known_text_defect_cannot_mask_a_different_destructive_edit(self): + baseline = {"replace": {"failures": ["text_changed"], "text_hashes": {"Assets/A.cs": "known"}}} + row = {"scenario": "replace", "failures": ["text_changed"], "differences": [ + {"path": "Assets/A.cs", "direct_text_sha256": "expected", "lsp_text_sha256": "known"}]} + self.assertEqual(reliability.regressions([row], baseline), []) + row["differences"][0]["lsp_text_sha256"] = "different-loss" + self.assertTrue(reliability.regressions([row], baseline)) + row["failures"] = [] + self.assertEqual(reliability.regressions([row], baseline), []) + + def test_ci_retains_failures_and_runs_real_lsp_on_all_three_platforms(self): + workflow = (ROOT / ".github/workflows/lsp-write-reliability.yml").read_text(encoding="utf-8") + self.assertIn("os: [windows-latest, macos-latest, ubuntu-latest]", workflow) + self.assertIn("dotnet publish lsp/Server.csproj", workflow) + self.assertIn("--baseline tests/fixtures/lsp-write-baseline.json", workflow) + self.assertIn("if: always()", workflow) + self.assertNotIn("continue-on-error", workflow) + self.assertNotIn("--record-only", workflow) + required = (ROOT / ".github/workflows/test.yml").read_text(encoding="utf-8") + self.assertIn("needs: lsp-write-reliability", required) + self.assertIn('run: test "$RELIABILITY_RESULT" = success', required) + + def test_one_corrupt_edit_prevents_enforcement_even_at_99_percent(self): + reports = [] + for system in reliability.OS_NAMES: + rows = [{"scenario": case["id"], "condition": condition, + "failures": [], "elapsed_ms": 1, "direct_ms": 1} + for condition in reliability.CONDITIONS for case in reliability.scenarios() for _ in range(100)] + reports.append({"os": system, "rows": rows, "finished_at": "2026-10-13T00:00:00Z"}) + self.assertIn("ELIGIBLE", reliability.markdown(reports)) + reports[0]["rows"][0]["failures"] = ["bom_added"] + self.assertIn("DO NOT ENFORCE", reliability.markdown(reports)) + reports[0].pop("finished_at") + self.assertIn("INSUFFICIENT", reliability.markdown(reports)) + + def test_known_bom_defect_cannot_mask_an_unrelated_file_write(self): + row = {"scenario": "rename_multifile", "failures": ["bom_added"], "differences": [{"path": "Assets/Other.cs"}]} + self.assertTrue(reliability.regressions([row], {"rename_multifile": ["bom_added"]})) + row["differences"] = [{"path": "Assets/Sample.cs"}] + self.assertEqual(reliability.regressions([row], {"rename_multifile": ["bom_added"]}), []) + + def test_trial_cleanup_retries_windows_dll_locks_and_rejects_escape(self): + with mock.patch.object(reliability.shutil, "rmtree", side_effect=[PermissionError("DLL still unloading"), None]) as remove: + with mock.patch.object(reliability.time, "sleep"): + reliability.cleanup_trial(ROOT / ".cache/trial", ROOT / ".cache") + self.assertEqual(remove.call_count, 2) + with mock.patch.object(reliability.shutil, "rmtree") as remove: + with self.assertRaises(RuntimeError): + reliability.cleanup_trial(ROOT, ROOT / ".cache") + remove.assert_not_called() + + +if __name__ == "__main__": + unittest.main() From 41574a6c1cd31417ad61e3e6d0d1d7f9b057bf36 Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 17:37:15 +0900 Subject: [PATCH 28/73] test(ci): gate LSP measurements through a required check --- .github/workflows/test.yml | 14 +++++++------- docs/lsp-write-reliability.md | 2 +- tests/scripts/test_lsp_write_reliability.py | 7 +++++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4d68fb09..d90ab2ec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,15 +16,8 @@ jobs: cli-latency: name: CLI Latency (required) - needs: lsp-write-reliability - if: always() runs-on: ubuntu-latest steps: - - name: Require passing LSP write measurements on every OS - env: - RELIABILITY_RESULT: ${{ needs.lsp-write-reliability.result }} - run: test "$RELIABILITY_RESULT" = success - - uses: actions/checkout@v7 - name: Install Rust toolchain @@ -215,8 +208,15 @@ jobs: lsp-test: name: LSP Tests (required) + needs: lsp-write-reliability + if: always() runs-on: ubuntu-latest steps: + - name: Require passing LSP write measurements on every OS + env: + RELIABILITY_RESULT: ${{ needs.lsp-write-reliability.result }} + run: test "$RELIABILITY_RESULT" = success + - uses: actions/checkout@v7 - name: Setup .NET SDK 10 diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md index b394ce79..5d3210bb 100644 --- a/docs/lsp-write-reliability.md +++ b/docs/lsp-write-reliability.md @@ -93,7 +93,7 @@ OS / 条件 / シナリオが欠ける結果は `INSUFFICIENT`、失敗がある `DO NOT ENFORCE` と報告します。少数試行での 100% は将来の 99% の保証にはなりません。 CI は PR / develop push の各 3 試行、週次と手動実行の既定は各 20 試行です。 PR / push は `Test` workflow から呼び出します。既存の必須 -`CLI Latency (required)` は全 OS の測定完了を待ち、測定失敗時には明示的に失敗します。 +`LSP Tests (required)` は全 OS の測定完了を待ち、測定失敗時には明示的に失敗します。 依存 job の skip が成功扱いになる経路も `if: always()` と結果チェックで防ぎます。 デーモン停止・初回ダウンロードは各シナリオ 1 試行を別枠で記録します。 `--cold-repetitions` / `--download-repetitions` で増やせます。 diff --git a/tests/scripts/test_lsp_write_reliability.py b/tests/scripts/test_lsp_write_reliability.py index e95f97cc..c08eed54 100644 --- a/tests/scripts/test_lsp_write_reliability.py +++ b/tests/scripts/test_lsp_write_reliability.py @@ -82,8 +82,11 @@ def test_ci_retains_failures_and_runs_real_lsp_on_all_three_platforms(self): self.assertNotIn("continue-on-error", workflow) self.assertNotIn("--record-only", workflow) required = (ROOT / ".github/workflows/test.yml").read_text(encoding="utf-8") - self.assertIn("needs: lsp-write-reliability", required) - self.assertIn('run: test "$RELIABILITY_RESULT" = success', required) + lsp_job = required.split(" lsp-test:\n", 1)[1].split(" rust-coverage:\n", 1)[0] + self.assertIn("name: LSP Tests (required)", lsp_job) + self.assertIn("needs: lsp-write-reliability", lsp_job) + self.assertIn("if: always()", lsp_job) + self.assertIn('run: test "$RELIABILITY_RESULT" = success', lsp_job) def test_one_corrupt_edit_prevents_enforcement_even_at_99_percent(self): reports = [] From 61cbc6d02f06f04433e528ea54d61e7b15de04dc Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 17:48:49 +0900 Subject: [PATCH 29/73] chore(work): record issue 490 PR handoff --- ...bb8fc275fa3131e26a7fbeb99949367b6d7fe8cfc07fbf9457fa491.jsonl | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gwt/work/events/18/18d3bf1a6bb8fc275fa3131e26a7fbeb99949367b6d7fe8cfc07fbf9457fa491.jsonl diff --git a/.gwt/work/events/18/18d3bf1a6bb8fc275fa3131e26a7fbeb99949367b6d7fe8cfc07fbf9457fa491.jsonl b/.gwt/work/events/18/18d3bf1a6bb8fc275fa3131e26a7fbeb99949367b6d7fe8cfc07fbf9457fa491.jsonl new file mode 100644 index 00000000..8baa9676 --- /dev/null +++ b/.gwt/work/events/18/18d3bf1a6bb8fc275fa3131e26a7fbeb99949367b6d7fe8cfc07fbf9457fa491.jsonl @@ -0,0 +1 @@ +{"id":"a395a6a6-71cd-4296-a592-067f751dc3cc","work_item_id":"work-work-issue-490-ce1c1f9a","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"done","owner":null,"next_action":null,"agent_session_id":"c0ac1284-51ea-49d8-82e3-da19507a6ba5","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-490","worktree_path":"E:\\unity-cli\\work\\issue-490","pr_number":497,"pr_url":"https://github.com/akiojin/unity-cli/pull/497","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T08:46:22.603682700Z"} From 3834adeeb7035479d749213a5016851a5eb9f5f9 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 17:55:04 +0900 Subject: [PATCH 30/73] fix(test): tolerate case-insensitive LSP server aliases in the reliability runner macOS runners resolve Server and server to the same file, so copying the published binary onto its own alias raised shutil.SameFileError and the macOS measurement job failed before any trial ran. Co-Authored-By: Claude Opus 5.5 --- scripts/lsp-write-reliability.py | 11 ++++++++--- tests/scripts/test_lsp_write_reliability.py | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/scripts/lsp-write-reliability.py b/scripts/lsp-write-reliability.py index b5900742..dbc131b6 100644 --- a/scripts/lsp-write-reliability.py +++ b/scripts/lsp-write-reliability.py @@ -220,6 +220,13 @@ def cleanup_trial(directory, root): time.sleep(0.1) +def install_server_alias(source, target): + # macOS / Windows filesystems are usually case-insensitive: Server and server are one file. + if target.exists() and target.samefile(source): + return + shutil.copy2(source, target) + + class Trial: def __init__(self, cli, lsp_publish, root, condition, timeout): self.cli, self.root, self.condition, self.timeout = cli, root, condition, timeout @@ -239,9 +246,7 @@ def __init__(self, cli, lsp_publish, root, condition, timeout): self.server = self.tools / "csharp-lsp" / rid() / ("server.exe" if os.name == "nt" else "server") if condition != "first_download": shutil.copytree(lsp_publish, self.server.parent) - source = self.server.parent / ("Server.exe" if os.name == "nt" else "Server") - if source != self.server and (os.name != "nt" or source.name.lower() != self.server.name.lower()): - shutil.copy2(source, self.server) + install_server_alias(self.server.parent / ("Server.exe" if os.name == "nt" else "Server"), self.server) self.server.chmod(0o755) (self.server.parent / "VERSION").write_text("checkout\n", encoding="utf-8") self.env["UNITY_CLI_TEST_SKIP_MANAGED_UPDATE"] = "1" diff --git a/tests/scripts/test_lsp_write_reliability.py b/tests/scripts/test_lsp_write_reliability.py index c08eed54..8c309fa0 100644 --- a/tests/scripts/test_lsp_write_reliability.py +++ b/tests/scripts/test_lsp_write_reliability.py @@ -33,6 +33,25 @@ def test_byte_comparison_distinguishes_bom_newlines_text_and_extra_files(self): self.assertEqual(reliability.compare_files(expected, expected), ([], [])) self.assertIn("text_changed", reliability.compare_files(expected, {"Assets/A.cs": b"class Wrong {}"})[0]) + def test_server_alias_tolerates_case_insensitive_filesystems(self): + import os, tempfile + with tempfile.TemporaryDirectory() as temp: + source = Path(temp) / "Server" + source.write_bytes(b"binary") + alias = Path(temp) / "server" + if not alias.exists(): + # Case-sensitive filesystems: a hard link stands in for macOS / Windows aliasing. + os.link(source, alias) + reliability.install_server_alias(source, alias) + self.assertEqual(alias.read_bytes(), b"binary") + with tempfile.TemporaryDirectory() as temp: + source = Path(temp) / "Server" + source.write_bytes(b"binary") + target = Path(temp) / "sub" / "server" + target.parent.mkdir() + reliability.install_server_alias(source, target) + self.assertEqual(target.read_bytes(), b"binary") + def test_false_success_or_fallback_is_not_a_successful_lsp_edit(self): self.assertEqual(reliability.response_failures(0, {"success": True, "data": {"success": False, "backend": "lsp"}}), ["tool_rejected"]) self.assertEqual(reliability.response_failures(0, {"success": True, "data": {"success": True, "backend": "unity"}}), ["wrong_backend"]) From 96e64877fc115b41da37465968c2a29829debffd Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 17:58:44 +0900 Subject: [PATCH 31/73] test(lsp): handle case-insensitive executable aliases --- scripts/lsp-write-reliability.py | 11 ++++++++--- tests/scripts/test_lsp_write_reliability.py | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/scripts/lsp-write-reliability.py b/scripts/lsp-write-reliability.py index b5900742..9c67420d 100644 --- a/scripts/lsp-write-reliability.py +++ b/scripts/lsp-write-reliability.py @@ -220,6 +220,13 @@ def cleanup_trial(directory, root): time.sleep(0.1) +def prepare_server_executable(source, target): + # macOS commonly aliases Server and server on a case-insensitive volume. + if not target.exists() or not source.samefile(target): + shutil.copy2(source, target) + target.chmod(0o755) + + class Trial: def __init__(self, cli, lsp_publish, root, condition, timeout): self.cli, self.root, self.condition, self.timeout = cli, root, condition, timeout @@ -240,9 +247,7 @@ def __init__(self, cli, lsp_publish, root, condition, timeout): if condition != "first_download": shutil.copytree(lsp_publish, self.server.parent) source = self.server.parent / ("Server.exe" if os.name == "nt" else "Server") - if source != self.server and (os.name != "nt" or source.name.lower() != self.server.name.lower()): - shutil.copy2(source, self.server) - self.server.chmod(0o755) + prepare_server_executable(source, self.server) (self.server.parent / "VERSION").write_text("checkout\n", encoding="utf-8") self.env["UNITY_CLI_TEST_SKIP_MANAGED_UPDATE"] = "1" self.process = None diff --git a/tests/scripts/test_lsp_write_reliability.py b/tests/scripts/test_lsp_write_reliability.py index c08eed54..ae70ad4e 100644 --- a/tests/scripts/test_lsp_write_reliability.py +++ b/tests/scripts/test_lsp_write_reliability.py @@ -1,6 +1,7 @@ """Protect the reliability measurement from false PASS and hidden regressions.""" import importlib.util from pathlib import Path +import tempfile import unittest from unittest import mock @@ -117,6 +118,19 @@ def test_trial_cleanup_retries_windows_dll_locks_and_rejects_escape(self): reliability.cleanup_trial(ROOT, ROOT / ".cache") remove.assert_not_called() + def test_server_alias_on_case_insensitive_filesystem_is_not_copied(self): + with tempfile.TemporaryDirectory() as temp: + source, target = Path(temp) / "published", Path(temp) / "runtime" + source.write_bytes(b"server") + # Hard links reproduce Server/server identity on macOS on every OS. + target.hardlink_to(source) + reliability.prepare_server_executable(source, target) + self.assertTrue(source.samefile(target)) + self.assertEqual(target.read_bytes(), b"server") + target.unlink() + reliability.prepare_server_executable(source, target) + self.assertEqual(target.read_bytes(), b"server") + if __name__ == "__main__": unittest.main() From 90f8f1bf18cd3b3bc80187573d2ce2e0e3b66900 Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 18:08:08 +0900 Subject: [PATCH 32/73] docs(lsp): link registered reliability defects --- docs/lsp-write-reliability.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md index 5d3210bb..a5d16d12 100644 --- a/docs/lsp-write-reliability.md +++ b/docs/lsp-write-reliability.md @@ -15,12 +15,12 @@ | 不具合 | 実測 | 禁止前に必要な修正 | | --- | --- | --- | -| BOM なしのファイルへ BOM を追加 | BOM なしの変更シナリオすべてで EF BB BF を追加 | 既存の BOM / 改行を保存し、新規ファイルの規約を定める | -| `replace_symbol_body` が末尾コメントを消す | 日本語コメントと改行が 3/3 消失し、次のメンバーと連結 | 置換前 Body の末尾 trivia を保持する | -| `create_class` の ScriptableObject 作成が using を欠く | `using UnityEngine` が 3/3 欠落 | 非修飾 ScriptableObject が名前解決できるテンプレートにする | +| [#498: BOM なしのファイルへ BOM を追加](https://github.com/akiojin/unity-cli/issues/498) | BOM なしの変更シナリオすべてで EF BB BF を追加 | 既存の BOM / 改行を保存し、新規ファイルの規約を定める | +| [#499: `replace_symbol_body` が末尾コメントを消す](https://github.com/akiojin/unity-cli/issues/499) | 日本語コメントと改行が 3/3 消失し、次のメンバーと連結 | 置換前 Body の末尾 trivia を保持する | +| [#500: `create_class` の ScriptableObject 作成が using を欠く](https://github.com/akiojin/unity-cli/issues/500) | `using UnityEngine` が 3/3 欠落 | 非修飾 ScriptableObject が名前解決できるテンプレートにする | 生応答とバイト差分は [Windows 初期測定の証跡](lsp-write-reliability-windows.json) に保存しています。 -製品修正は個別の不具合 Issue として PM に登録を依頼しています。 +製品修正は上記の個別不具合 Issue に登録済みです。 3 OS / 全起動条件の結論は CI artifact の完成したマトリクスを参照してください。 ## 再現 From c6b442e2d0f230059a5cdc274506d255ed3b30fb Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 18:16:15 +0900 Subject: [PATCH 33/73] fix(lsp): keep trailing comments when replace_symbol_body replaces a method body replace_symbol_body swapped the method body for a freshly parsed block without carrying over the old body's trivia, so a trailing comment and newline after `}` were dropped and the next member was joined onto the same line. Carry the leading/trailing trivia of the replaced body (or of the expression body and its semicolon) onto the new block. Refs #499 Co-Authored-By: Claude Opus 5.5 --- lsp/EditServiceTests.cs | 37 +++++++++++++++++++++++++++++++ lsp/Server.Core/LspEditService.cs | 6 +++++ 2 files changed, 43 insertions(+) diff --git a/lsp/EditServiceTests.cs b/lsp/EditServiceTests.cs index aaa2109f..75488b17 100644 --- a/lsp/EditServiceTests.cs +++ b/lsp/EditServiceTests.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Text; using System.Text.Json; using System.Threading.Tasks; using UnityCli.Lsp.Core; @@ -163,4 +164,40 @@ public async Task RemoveSymbolAsync_PreviewsWithReferenceCheckWithoutReenteringF } } } + + [Theory] + [InlineData( + "public class Sample { public int Run(){return 1;} // 日本語の説明を保持\npublic int Next(){return 3;} }\n", + "public class Sample { public int Run(){return 2;} // 日本語の説明を保持\npublic int Next(){return 3;} }\n")] + [InlineData( + "public class Sample {\r\n // leading\r\n public int Run()\r\n {\r\n return 1;\r\n } /* tail */\r\n public int Next() => 3;\r\n}\r\n", + "public class Sample {\r\n // leading\r\n public int Run()\r\n {return 2;} /* tail */\r\n public int Next() => 3;\r\n}\r\n")] + [InlineData( + "public class Sample { public int Run() => 1; // expr\npublic int Next(){return 3;} }\n", + "public class Sample { public int Run() {return 2;} // expr\npublic int Next(){return 3;} }\n")] + public async Task ReplaceSymbolBodyAsync_PreservesTrailingTriviaOfReplacedBody(string original, string expected) + { + var root = Path.Combine(Path.GetTempPath(), "unity-cli-replace-body-" + Path.GetRandomFileName()); + Directory.CreateDirectory(Path.Combine(root, "Assets")); + var scriptPath = Path.Combine(root, "Assets", "Sample.cs"); + await File.WriteAllBytesAsync(scriptPath, Encoding.UTF8.GetBytes(original)); + try + { + var service = new LspEditService(root, new LspFileLockProvider()); + + var result = await service.ReplaceSymbolBodyAsync("Assets/Sample.cs", "Sample/Run", "{return 2;}", apply: true); + + using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); + Assert.True(response.RootElement.GetProperty("applied").GetBoolean()); + // The UTF-8 BOM written on save is tracked separately (#498); compare the text bytes after it. + var bytes = await File.ReadAllBytesAsync(scriptPath); + var preamble = Encoding.UTF8.GetPreamble(); + var body = bytes.AsSpan().StartsWith(preamble) ? bytes[preamble.Length..] : bytes; + Assert.Equal(Encoding.UTF8.GetBytes(expected), body); + } + finally + { + Directory.Delete(root, recursive: true); + } + } } diff --git a/lsp/Server.Core/LspEditService.cs b/lsp/Server.Core/LspEditService.cs index 1756888e..84778a1a 100644 --- a/lsp/Server.Core/LspEditService.cs +++ b/lsp/Server.Core/LspEditService.cs @@ -538,6 +538,12 @@ public async Task ReplaceSymbolBodyAsync(string relative, string namePat var (_, last) = FindNodeByNamePath(root, normalizedPath); if (last is not MethodDeclarationSyntax method) return EditResult(false, false, reason: "symbol_not_found"); var block = ParseBlock(bodyText); + // keep the trivia around the replaced body (e.g. a trailing comment and the newline after `}`) + var (leading, trailing) = method.Body is { } oldBody + ? (oldBody.GetLeadingTrivia(), oldBody.GetTrailingTrivia()) + : (method.ExpressionBody?.GetLeadingTrivia() ?? default, + method.SemicolonToken.TrailingTrivia); + block = block.WithLeadingTrivia(leading).WithTrailingTrivia(trailing); // handle expression-bodied to block conversion var m2 = method.WithExpressionBody(null).WithSemicolonToken(default).WithBody(block); var newRoot = root.ReplaceNode(method, m2); From 1a5291e5c7b1d47603a99722ee555b6ebf07a0f8 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 18:24:54 +0900 Subject: [PATCH 34/73] fix(lsp): add using UnityEngine to ScriptableObject classes from create_class create_class only emitted `using UnityEngine;` for MonoBehaviour, so an unqualified ScriptableObject base did not resolve and Unity failed to compile the generated class. Treat ScriptableObject like MonoBehaviour; fully qualified bases still get no using. Refs #500 Co-Authored-By: Claude Opus 5.5 --- src/tooling/local_tools.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/tooling/local_tools.rs b/src/tooling/local_tools.rs index 564dd6a6..54c869e6 100644 --- a/src/tooling/local_tools.rs +++ b/src/tooling/local_tools.rs @@ -898,7 +898,10 @@ async fn poll_compile_state(config: &RuntimeConfig) -> Result { } fn requires_unityengine_using(inherits: Option<&str>) -> bool { - matches!(inherits.map(str::trim), Some("MonoBehaviour")) + matches!( + inherits.map(str::trim), + Some("MonoBehaviour" | "ScriptableObject") + ) } fn local_create_class(params: &Value) -> Result { @@ -2126,12 +2129,26 @@ namespace Demo.Game } #[test] - fn requires_unityengine_using_only_for_monobehaviour() { + fn requires_unityengine_using_for_unqualified_unityengine_bases() { assert!(requires_unityengine_using(Some("MonoBehaviour"))); - assert!(!requires_unityengine_using(Some("ScriptableObject"))); + assert!(requires_unityengine_using(Some("ScriptableObject"))); + assert!(requires_unityengine_using(Some(" ScriptableObject "))); + assert!(!requires_unityengine_using(Some( + "UnityEngine.ScriptableObject" + ))); + assert!(!requires_unityengine_using(Some("BaseService"))); assert!(!requires_unityengine_using(None)); } + #[test] + fn create_class_template_scriptableobject_resolves_unityengine() { + let content = render_class_template("Sample", None, Some("ScriptableObject")); + assert_eq!( + content, + "using UnityEngine;\n\npublic class Sample : ScriptableObject\n{\n}\n" + ); + } + #[test] fn lsp_write_tools_require_lsp_mode() { let _guard = env_lock().lock().expect("lock should succeed"); From c2b47040fe59137e838f4a6b8d8e6f66b12605c4 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 18:38:57 +0900 Subject: [PATCH 35/73] test(lsp): gate the ScriptableObject template fix and sample cold starts PR #502 fixed the missing using UnityEngine in create_class, so the baseline no longer tolerates text_changed for that scenario. Cold-start and first-download conditions now take three samples per scenario on PRs so every cell reports a rate instead of a single observation. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/lsp-write-reliability.yml | 11 ++++++++++- tests/fixtures/lsp-write-baseline.json | 7 +------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/lsp-write-reliability.yml b/.github/workflows/lsp-write-reliability.yml index 0868301f..21e516f8 100644 --- a/.github/workflows/lsp-write-reliability.yml +++ b/.github/workflows/lsp-write-reliability.yml @@ -6,6 +6,9 @@ on: repetitions: default: '3' type: string + cold_repetitions: + default: '3' + type: string schedule: - cron: '17 2 * * 2' workflow_dispatch: @@ -14,6 +17,10 @@ on: description: Samples per scenario and installed-LSP condition default: '20' type: string + cold_repetitions: + description: Samples per scenario for daemon_stopped and first_download + default: '5' + type: string permissions: contents: read @@ -57,12 +64,14 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPETITIONS: ${{ inputs.repetitions || (github.event_name == 'schedule' && '20') || '3' }} + COLD_REPETITIONS: ${{ inputs.cold_repetitions || (github.event_name == 'schedule' && '5') || '3' }} run: | cli=target/debug/unity-cli if [ "$RUNNER_OS" = Windows ]; then cli="$cli.exe"; fi python scripts/lsp-write-reliability.py --unity-cli "$cli" \ --lsp-publish .cache/lsp-reliability-publish --out .cache/lsp-reliability \ - --repetitions "$REPETITIONS" --download-repetitions 1 \ + --repetitions "$REPETITIONS" --cold-repetitions "$COLD_REPETITIONS" \ + --download-repetitions "$COLD_REPETITIONS" \ --baseline tests/fixtures/lsp-write-baseline.json - name: Upload measured failures as well as successes if: always() diff --git a/tests/fixtures/lsp-write-baseline.json b/tests/fixtures/lsp-write-baseline.json index 26103c16..9b6dc4e1 100644 --- a/tests/fixtures/lsp-write-baseline.json +++ b/tests/fixtures/lsp-write-baseline.json @@ -1,11 +1,6 @@ { "create_class_monobehaviour": ["bom_added"], - "create_class_scriptableobject": { - "failures": ["bom_added", "text_changed"], - "text_hashes": { - "Assets/Sample.cs": "34eedc1cdabfdb43cffc3403e71f8936963c55797ffc0308f43d6a86a2efdecc" - } - }, + "create_class_scriptableobject": ["bom_added"], "create_class_plain": ["bom_added"], "create_plain": ["bom_added"], "create_monobehaviour": ["bom_added"], From e4d44063cb14e7228f4a3270ff778a71a30ad53e Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 18:43:58 +0900 Subject: [PATCH 36/73] test(ci): bound PR cold samples and budget weekly measurements --- .github/workflows/lsp-write-reliability.yml | 7 ++++--- docs/lsp-write-reliability.md | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lsp-write-reliability.yml b/.github/workflows/lsp-write-reliability.yml index 21e516f8..385a1a57 100644 --- a/.github/workflows/lsp-write-reliability.yml +++ b/.github/workflows/lsp-write-reliability.yml @@ -7,7 +7,7 @@ on: default: '3' type: string cold_repetitions: - default: '3' + default: '1' type: string schedule: - cron: '17 2 * * 2' @@ -33,7 +33,8 @@ jobs: matrix: os: [windows-latest, macos-latest, ubuntu-latest] runs-on: ${{ matrix.os }} - timeout-minutes: 120 + # Windows cold starts take about 46s each; weekly 20/5 samples need > 2h. + timeout-minutes: 240 steps: - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable @@ -64,7 +65,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPETITIONS: ${{ inputs.repetitions || (github.event_name == 'schedule' && '20') || '3' }} - COLD_REPETITIONS: ${{ inputs.cold_repetitions || (github.event_name == 'schedule' && '5') || '3' }} + COLD_REPETITIONS: ${{ inputs.cold_repetitions || (github.event_name == 'schedule' && '5') || '1' }} run: | cli=target/debug/unity-cli if [ "$RUNNER_OS" = Windows ]; then cli="$cli.exe"; fi diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md index a5d16d12..4c9d5063 100644 --- a/docs/lsp-write-reliability.md +++ b/docs/lsp-write-reliability.md @@ -95,7 +95,10 @@ CI は PR / develop push の各 3 試行、週次と手動実行の既定は各 PR / push は `Test` workflow から呼び出します。既存の必須 `LSP Tests (required)` は全 OS の測定完了を待ち、測定失敗時には明示的に失敗します。 依存 job の skip が成功扱いになる経路も `if: always()` と結果チェックで防ぎます。 -デーモン停止・初回ダウンロードは各シナリオ 1 試行を別枠で記録します。 +デーモン停止・初回ダウンロードは PR / push で各シナリオ 1 試行、 +週次・手動の既定は各 5 試行を別枠で記録します。Windows の実測では +コールド起動が約 46 秒 / 試行のため、PR の全条件測定は約 35 分かかります。 +週次・手動の多試行を完了できるよう測定 job の上限は 240 分です。 `--cold-repetitions` / `--download-repetitions` で増やせます。 既知の不具合は `tests/fixtures/lsp-write-baseline.json` にシナリオ単位で明記します。 From 190602e18936f1972c09e381b946bf4c8ddfc223 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 18:44:01 +0900 Subject: [PATCH 37/73] test(lsp): enforce the trailing-comment fix on the checkout LSP PR #503 fixed replace_symbol_body in the checkout LSP, so warm and unindexed rows must no longer drop the trailing comment. The cold-start and first-download rows still run the released 0.18.1 LSP, which lacks the fix; a published-only baseline entry keeps exactly that known diff tolerated for rows proven to run a released build. Co-Authored-By: Claude Opus 5.5 --- scripts/lsp-write-reliability.py | 3 +++ tests/fixtures/lsp-write-baseline.json | 9 ++++++--- tests/scripts/test_lsp_write_reliability.py | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/scripts/lsp-write-reliability.py b/scripts/lsp-write-reliability.py index dbc131b6..d26a92f6 100644 --- a/scripts/lsp-write-reliability.py +++ b/scripts/lsp-write-reliability.py @@ -137,6 +137,9 @@ def regressions(rows, baseline): if case["before"].get(name) != case["after"].get(name)} for case in scenarios()} for row in rows: known = baseline.get(row["scenario"], {}) + # Released LSP builds may lag a checkout fix; only rows proven to run one use that exception. + if isinstance(known, dict) and "published" in known and row.get("lsp_version") not in (None, "checkout"): + known = known["published"] allowed = known.get("failures", []) if isinstance(known, dict) else known new = set(row["failures"]) - set(allowed) if row["scenario"] in expected_paths and any(d["path"] not in expected_paths[row["scenario"]] for d in row.get("differences", [])): diff --git a/tests/fixtures/lsp-write-baseline.json b/tests/fixtures/lsp-write-baseline.json index 9b6dc4e1..3c6cf991 100644 --- a/tests/fixtures/lsp-write-baseline.json +++ b/tests/fixtures/lsp-write-baseline.json @@ -12,9 +12,12 @@ "remove_member": ["bom_added"], "namespace_partial_generic_attributes": ["bom_added"], "replace_preserve_comment": { - "failures": ["bom_added", "text_changed"], - "text_hashes": { - "Assets/Sample.cs": "215a30f2eaeefdd4d211dd6ada4e5aab889d1a2617366f1343808a9c1540ab68" + "failures": ["bom_added"], + "published": { + "failures": ["bom_added", "text_changed"], + "text_hashes": { + "Assets/Sample.cs": "215a30f2eaeefdd4d211dd6ada4e5aab889d1a2617366f1343808a9c1540ab68" + } } }, "rename_multifile": ["bom_added"], diff --git a/tests/scripts/test_lsp_write_reliability.py b/tests/scripts/test_lsp_write_reliability.py index 8c309fa0..781b2d11 100644 --- a/tests/scripts/test_lsp_write_reliability.py +++ b/tests/scripts/test_lsp_write_reliability.py @@ -92,6 +92,22 @@ def test_known_text_defect_cannot_mask_a_different_destructive_edit(self): row["failures"] = [] self.assertEqual(reliability.regressions([row], baseline), []) + def test_published_lsp_exception_never_relaxes_the_checkout_gate(self): + # A fix merged into the checkout LSP stays enforced even before it is released. + baseline = {"replace": {"failures": ["bom_added"], "published": { + "failures": ["bom_added", "text_changed"], "text_hashes": {"Assets/A.cs": "known"}}}} + known = [{"path": "Assets/A.cs", "direct_text_sha256": "expected", "lsp_text_sha256": "known"}] + published = {"scenario": "replace", "lsp_version": "0.18.1", "failures": ["bom_added", "text_changed"], "differences": known} + self.assertEqual(reliability.regressions([published], baseline), []) + checkout = dict(published, lsp_version="checkout") + self.assertTrue(reliability.regressions([checkout], baseline)) + missing = dict(published) + del missing["lsp_version"] + self.assertTrue(reliability.regressions([missing], baseline)) + other = dict(published, differences=[dict(known[0], lsp_text_sha256="different-loss")]) + self.assertTrue(reliability.regressions([other], baseline)) + self.assertEqual(reliability.regressions([dict(checkout, failures=["bom_added"], differences=[])], baseline), []) + def test_ci_retains_failures_and_runs_real_lsp_on_all_three_platforms(self): workflow = (ROOT / ".github/workflows/lsp-write-reliability.yml").read_text(encoding="utf-8") self.assertIn("os: [windows-latest, macos-latest, ubuntu-latest]", workflow) From 18bc3b8849690349b88c45144e0fb4fcceb890ff Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 18:45:32 +0900 Subject: [PATCH 38/73] test(lsp): reject fixed comment loss in checkout measurements --- docs/lsp-write-reliability.md | 2 ++ scripts/lsp-write-reliability.py | 2 ++ tests/fixtures/lsp-write-baseline.json | 4 ++++ tests/scripts/test_lsp_write_reliability.py | 13 +++++++++++++ 4 files changed, 21 insertions(+) diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md index 4c9d5063..fee7c269 100644 --- a/docs/lsp-write-reliability.md +++ b/docs/lsp-write-reliability.md @@ -106,6 +106,8 @@ PR / push は `Test` workflow から呼び出します。既存の必須 CI は baseline に含まれない失敗を終了コード 1 で拒否します。既知のテキスト差分も 正規化した内容の SHA256 を照合し、別の誤編集を隠しません。修正による失敗の解消は 許可します。baseline の変更は再現証跡と不具合 Issue を伴うレビュー対象です。 +#499 のコメント喪失修正は checkout 条件で回帰を拒否します。公開 LSP を使う +コールド条件では、修正前 VERSION の既知のテキスト SHA256 だけを許容します。 無関係のファイルへの BOM 追加も regression として拒否します。 再測定を絞る場合は `--scenarios create_plain` のように指定できます。絞った実行は 完全なマトリクスの代わりにならず、レポートの欠けたセル数に反映します。 diff --git a/scripts/lsp-write-reliability.py b/scripts/lsp-write-reliability.py index dbc131b6..ddb66a86 100644 --- a/scripts/lsp-write-reliability.py +++ b/scripts/lsp-write-reliability.py @@ -137,6 +137,8 @@ def regressions(rows, baseline): if case["before"].get(name) != case["after"].get(name)} for case in scenarios()} for row in rows: known = baseline.get(row["scenario"], {}) + if isinstance(known, dict): + known = known.get("conditions", {}).get(row.get("condition"), known) allowed = known.get("failures", []) if isinstance(known, dict) else known new = set(row["failures"]) - set(allowed) if row["scenario"] in expected_paths and any(d["path"] not in expected_paths[row["scenario"]] for d in row.get("differences", [])): diff --git a/tests/fixtures/lsp-write-baseline.json b/tests/fixtures/lsp-write-baseline.json index 9b6dc4e1..1ae64106 100644 --- a/tests/fixtures/lsp-write-baseline.json +++ b/tests/fixtures/lsp-write-baseline.json @@ -13,6 +13,10 @@ "namespace_partial_generic_attributes": ["bom_added"], "replace_preserve_comment": { "failures": ["bom_added", "text_changed"], + "conditions": { + "warm_indexed": ["bom_added"], + "unindexed": ["bom_added"] + }, "text_hashes": { "Assets/Sample.cs": "215a30f2eaeefdd4d211dd6ada4e5aab889d1a2617366f1343808a9c1540ab68" } diff --git a/tests/scripts/test_lsp_write_reliability.py b/tests/scripts/test_lsp_write_reliability.py index 8c309fa0..944cf96c 100644 --- a/tests/scripts/test_lsp_write_reliability.py +++ b/tests/scripts/test_lsp_write_reliability.py @@ -1,5 +1,6 @@ """Protect the reliability measurement from false PASS and hidden regressions.""" import importlib.util +import json from pathlib import Path import unittest from unittest import mock @@ -92,6 +93,18 @@ def test_known_text_defect_cannot_mask_a_different_destructive_edit(self): row["failures"] = [] self.assertEqual(reliability.regressions([row], baseline), []) + def test_fixed_checkout_comment_loss_is_rejected_but_known_release_is_measured(self): + baseline = json.loads((ROOT / "tests/fixtures/lsp-write-baseline.json").read_text(encoding="utf-8")) + known = baseline["replace_preserve_comment"]["text_hashes"]["Assets/Sample.cs"] + row = {"scenario": "replace_preserve_comment", "failures": ["bom_added", "text_changed"], + "differences": [{"path": "Assets/Sample.cs", "direct_text_sha256": "expected", "lsp_text_sha256": known}]} + for condition in ("daemon_stopped", "first_download"): + row["condition"] = condition + self.assertEqual(reliability.regressions([row], baseline), []) + for condition in ("warm_indexed", "unindexed"): + row["condition"] = condition + self.assertTrue(reliability.regressions([row], baseline)) + def test_ci_retains_failures_and_runs_real_lsp_on_all_three_platforms(self): workflow = (ROOT / ".github/workflows/lsp-write-reliability.yml").read_text(encoding="utf-8") self.assertIn("os: [windows-latest, macos-latest, ubuntu-latest]", workflow) From 18be4b1d3ffb2a243eb9691a86deacecd87fcc94 Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 18:50:54 +0900 Subject: [PATCH 39/73] test(lsp): pin known published defects to the measured release --- docs/lsp-write-reliability.md | 3 ++- scripts/lsp-write-reliability.py | 7 ++++--- tests/fixtures/lsp-write-baseline.json | 1 + tests/scripts/test_lsp_write_reliability.py | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md index 8b92ce12..2ced8102 100644 --- a/docs/lsp-write-reliability.md +++ b/docs/lsp-write-reliability.md @@ -107,7 +107,8 @@ CI は baseline に含まれない失敗を終了コード 1 で拒否します 正規化した内容の SHA256 を照合し、別の誤編集を隠しません。修正による失敗の解消は 許可します。baseline の変更は再現証跡と不具合 Issue を伴うレビュー対象です。 Issue #499 のコメント喪失修正は checkout 条件で回帰を拒否します。公開 LSP を使う -コールド条件では、修正前 VERSION の既知のテキスト SHA256 だけを許容します。 +コールド条件では、実測した公開版 `0.18.1` の既知のテキスト SHA256 だけを +許容します。VERSION 不明・checkout・後続の公開版にはこの例外を適用しません。 無関係のファイルへの BOM 追加も regression として拒否します。 再測定を絞る場合は `--scenarios create_plain` のように指定できます。絞った実行は 完全なマトリクスの代わりにならず、レポートの欠けたセル数に反映します。 diff --git a/scripts/lsp-write-reliability.py b/scripts/lsp-write-reliability.py index d26a92f6..85893f54 100644 --- a/scripts/lsp-write-reliability.py +++ b/scripts/lsp-write-reliability.py @@ -137,9 +137,10 @@ def regressions(rows, baseline): if case["before"].get(name) != case["after"].get(name)} for case in scenarios()} for row in rows: known = baseline.get(row["scenario"], {}) - # Released LSP builds may lag a checkout fix; only rows proven to run one use that exception. - if isinstance(known, dict) and "published" in known and row.get("lsp_version") not in (None, "checkout"): - known = known["published"] + # An old release exception cannot hide a checkout or future-release regression. + published = known.get("published", {}) if isinstance(known, dict) else {} + if row.get("lsp_version") in published.get("versions", []): + known = published allowed = known.get("failures", []) if isinstance(known, dict) else known new = set(row["failures"]) - set(allowed) if row["scenario"] in expected_paths and any(d["path"] not in expected_paths[row["scenario"]] for d in row.get("differences", [])): diff --git a/tests/fixtures/lsp-write-baseline.json b/tests/fixtures/lsp-write-baseline.json index 3c6cf991..228d4a6c 100644 --- a/tests/fixtures/lsp-write-baseline.json +++ b/tests/fixtures/lsp-write-baseline.json @@ -14,6 +14,7 @@ "replace_preserve_comment": { "failures": ["bom_added"], "published": { + "versions": ["0.18.1"], "failures": ["bom_added", "text_changed"], "text_hashes": { "Assets/Sample.cs": "215a30f2eaeefdd4d211dd6ada4e5aab889d1a2617366f1343808a9c1540ab68" diff --git a/tests/scripts/test_lsp_write_reliability.py b/tests/scripts/test_lsp_write_reliability.py index 781b2d11..fdc45eb4 100644 --- a/tests/scripts/test_lsp_write_reliability.py +++ b/tests/scripts/test_lsp_write_reliability.py @@ -95,6 +95,7 @@ def test_known_text_defect_cannot_mask_a_different_destructive_edit(self): def test_published_lsp_exception_never_relaxes_the_checkout_gate(self): # A fix merged into the checkout LSP stays enforced even before it is released. baseline = {"replace": {"failures": ["bom_added"], "published": { + "versions": ["0.18.1"], "failures": ["bom_added", "text_changed"], "text_hashes": {"Assets/A.cs": "known"}}}} known = [{"path": "Assets/A.cs", "direct_text_sha256": "expected", "lsp_text_sha256": "known"}] published = {"scenario": "replace", "lsp_version": "0.18.1", "failures": ["bom_added", "text_changed"], "differences": known} @@ -104,6 +105,7 @@ def test_published_lsp_exception_never_relaxes_the_checkout_gate(self): missing = dict(published) del missing["lsp_version"] self.assertTrue(reliability.regressions([missing], baseline)) + self.assertTrue(reliability.regressions([dict(published, lsp_version="0.18.2")], baseline)) other = dict(published, differences=[dict(known[0], lsp_text_sha256="different-loss")]) self.assertTrue(reliability.regressions([other], baseline)) self.assertEqual(reliability.regressions([dict(checkout, failures=["bom_added"], differences=[])], baseline), []) From a07409ffb762e42cdf5e088b482de99569908d3e Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 18:53:03 +0900 Subject: [PATCH 40/73] fix(lsp): wait for a live auto-started lspd instead of failing after 5 seconds The lspd auto-start polled ping for a fixed 5 seconds and discarded the daemon's stderr, so a slow cold start failed C# writes with a bare "lspd failed to start within timeout". - Wait up to UNITY_CLI_LSPD_START_TIMEOUT_MS (default 60000) while the startup process is alive; fail at once when it exits (unless a concurrent caller's daemon already answers) - Kill a timed-out startup process and report the limit, the time waited, and the lspd.log location - Send the daemon's stderr to lspd.log in the lspd runtime dir Closes #501 Co-Authored-By: Claude Opus 5.5 --- docs/architecture.md | 1 + src/lsp/daemon.rs | 225 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 207 insertions(+), 19 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index dd2af826..a65f82b6 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -129,6 +129,7 @@ CLI 側 Unity Editor 側 | `UNITY_CLI_TIMEOUT_MS` | コマンドタイムアウト (ミリ秒) | ― | | `UNITY_CLI_LSP_MODE` | LSP 起動モード | `auto` | | `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` | `auto` のシンボル検索が LSP を待つ上限 (ミリ秒) | `10000` | +| `UNITY_CLI_LSPD_START_TIMEOUT_MS` | lspd 自動起動で `ping` 応答を待つ上限 (ミリ秒)。起動プロセスが途中で終了した場合は待たずに失敗し、エラーに待ち時間と `lspd.log` の場所を含める | `60000` | | `UNITY_CLI_LSP_COMMAND` | LSP 実行コマンド | ― | | `UNITY_CLI_LSP_BIN` | LSP 実行ファイルパス | ― | | `UNITY_PROJECT_ROOT` | Unity プロジェクトルート | ― | diff --git a/src/lsp/daemon.rs b/src/lsp/daemon.rs index 17f00cda..fbe6a682 100644 --- a/src/lsp/daemon.rs +++ b/src/lsp/daemon.rs @@ -3,7 +3,7 @@ use std::fs; use std::io::ErrorKind; use std::io::{BufRead, BufReader, Write}; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Child, Command, Stdio}; use std::thread; use std::time::{Duration, Instant}; @@ -15,6 +15,10 @@ use crate::daemon::runtime::DaemonRuntimePaths; use crate::lsp_manager; const DAEMON_IDLE_TIMEOUT_SECS: u64 = 600; +/// Upper bound for an auto-started lspd to answer `ping`. A cold start on a +/// busy machine has been measured at more than 12 seconds, so the wait is +/// generous; a startup process that exits fails immediately instead. +const DAEMON_START_TIMEOUT_MS: u64 = 60_000; #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] @@ -131,27 +135,80 @@ pub fn start_background() -> Result { let _ = lsp_manager::ensure_latest_lsp_for_daemon()?; let exe = daemon_command_path()?; - Command::new(&exe) - .arg("lspd") - .arg("serve") - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn() - .context("Failed to spawn lspd background process")?; - - let deadline = Instant::now() + Duration::from_secs(5); - while Instant::now() < deadline { - if ping().is_ok() { - return Ok(json!({ - "success": true, - "running": true - })); + let log_path = log_file_path()?; + if let Some(parent) = log_path.parent() { + fs::create_dir_all(parent) + .with_context(|| format!("Failed to create daemon directory: {}", parent.display()))?; + } + let log = fs::OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + .with_context(|| format!("Failed to open lspd log: {}", log_path.display()))?; + let mut child = crate::daemon::spawn::spawn_detached( + Command::new(&exe) + .arg("lspd") + .arg("serve") + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::from(log)), + ) + .context("Failed to spawn lspd background process")?; + + wait_until_ready(&mut child, daemon_start_timeout(), &log_path, || { + ping().is_ok() + })?; + // Reap the daemon if it exits while this process is still alive. + thread::spawn(move || { + let _ = child.wait(); + }); + Ok(json!({ + "success": true, + "running": true + })) +} + +/// Polls `ready` until it succeeds, the startup process exits, or `timeout` +/// elapses. A timed-out startup process is killed so it cannot linger. +fn wait_until_ready( + child: &mut Child, + timeout: Duration, + log_path: &Path, + mut ready: impl FnMut() -> bool, +) -> Result<()> { + let started = Instant::now(); + loop { + if ready() { + return Ok(()); + } + if let Some(status) = child + .try_wait() + .context("Failed to inspect lspd startup process")? + { + // A concurrent auto-start may have won the listener; its daemon + // is serving even though this startup process exited. + if ready() { + return Ok(()); + } + return Err(anyhow!( + "lspd exited during startup ({status}) after {} ms; see {}", + started.elapsed().as_millis(), + log_path.display() + )); + } + if started.elapsed() >= timeout { + let _ = child.kill(); + let _ = child.wait(); + return Err(anyhow!( + "lspd failed to start within {} ms (waited {} ms); see {} \ + (set UNITY_CLI_LSPD_START_TIMEOUT_MS to wait longer)", + timeout.as_millis(), + started.elapsed().as_millis(), + log_path.display() + )); } thread::sleep(Duration::from_millis(100)); } - - Err(anyhow!("lspd failed to start within timeout")) } pub fn stop() -> Result { @@ -509,6 +566,20 @@ fn daemon_idle_timeout_secs() -> u64 { .unwrap_or(DAEMON_IDLE_TIMEOUT_SECS) } +fn daemon_start_timeout() -> Duration { + Duration::from_millis( + env::var("UNITY_CLI_LSPD_START_TIMEOUT_MS") + .ok() + .and_then(|v| v.parse::().ok()) + .filter(|v| *v > 0) + .unwrap_or(DAEMON_START_TIMEOUT_MS), + ) +} + +fn log_file_path() -> Result { + Ok(DaemonRuntimePaths::new("lspd")?.dir()?.join("lspd.log")) +} + fn pid_file_path() -> Result { DaemonRuntimePaths::new("lspd")?.pid_file() } @@ -1088,6 +1159,122 @@ mod tests { assert!(!socket.exists(), "socket file should be cleaned up"); } + fn exiting_child(code: i32) -> std::process::Child { + #[cfg(unix)] + let mut command = Command::new("sh"); + #[cfg(unix)] + command.args(["-c", &format!("exit {code}")]); + #[cfg(windows)] + let mut command = Command::new("cmd"); + #[cfg(windows)] + command.args(["/C", &format!("exit {code}")]); + command.spawn().expect("exiting child should spawn") + } + + fn sleeping_child() -> std::process::Child { + #[cfg(unix)] + let mut command = Command::new("sleep"); + #[cfg(unix)] + command.arg("30"); + #[cfg(windows)] + let mut command = Command::new("ping"); + #[cfg(windows)] + command.args(["-n", "30", "127.0.0.1"]); + command + .stdout(Stdio::null()) + .spawn() + .expect("sleeping child should spawn") + } + + #[test] + fn wait_until_ready_fails_immediately_when_startup_process_exits() { + let log = Path::new("/tmp/lspd-test.log"); + let mut child = exiting_child(3); + let started = Instant::now(); + let error = wait_until_ready(&mut child, Duration::from_secs(30), log, || false) + .expect_err("an exited startup process must fail"); + assert!(started.elapsed() < Duration::from_secs(10)); + let message = error.to_string(); + assert!(message.contains("exited during startup"), "{message}"); + assert!(message.contains(&log.display().to_string()), "{message}"); + } + + #[test] + fn wait_until_ready_reports_waited_time_and_log_on_timeout() { + let log = Path::new("/tmp/lspd-test.log"); + let mut child = sleeping_child(); + let error = wait_until_ready(&mut child, Duration::from_millis(300), log, || false) + .expect_err("a daemon that never answers must time out"); + let message = error.to_string(); + assert!(message.contains("within 300 ms"), "{message}"); + assert!(message.contains("waited"), "{message}"); + assert!(message.contains(&log.display().to_string()), "{message}"); + assert!( + child + .try_wait() + .expect("child should be inspectable") + .is_some(), + "a timed-out startup process must not be left running" + ); + } + + #[test] + fn wait_until_ready_keeps_polling_while_the_daemon_is_alive() { + let log = Path::new("/tmp/lspd-test.log"); + let mut child = sleeping_child(); + let mut probes = 0; + wait_until_ready(&mut child, Duration::from_secs(30), log, || { + probes += 1; + probes >= 5 + }) + .expect("a live daemon that answers late should be accepted"); + assert_eq!(probes, 5); + let _ = child.kill(); + let _ = child.wait(); + } + + #[test] + fn wait_until_ready_accepts_a_daemon_started_by_a_concurrent_caller() { + let log = Path::new("/tmp/lspd-test.log"); + let mut child = exiting_child(1); + let _ = child.wait(); + let mut probes = 0; + wait_until_ready(&mut child, Duration::from_secs(30), log, || { + probes += 1; + probes >= 2 + }) + .expect("an exited loser of a startup race should accept the running daemon"); + } + + #[test] + fn daemon_start_timeout_uses_env_override() { + let _guard = env_lock() + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + std::env::remove_var("UNITY_CLI_LSPD_START_TIMEOUT_MS"); + assert_eq!(daemon_start_timeout(), Duration::from_secs(60)); + + let _env = EnvVarGuard::set("UNITY_CLI_LSPD_START_TIMEOUT_MS", "1500"); + assert_eq!(daemon_start_timeout(), Duration::from_millis(1500)); + + drop(_env); + let _invalid = EnvVarGuard::set("UNITY_CLI_LSPD_START_TIMEOUT_MS", "0"); + assert_eq!(daemon_start_timeout(), Duration::from_secs(60)); + } + + #[test] + fn daemon_log_lives_in_the_lspd_runtime_dir() { + let _guard = env_lock() + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + let (_tools_root, _env) = prepare_tools_root(); + let log = log_file_path().expect("log path should resolve"); + let dir = DaemonRuntimePaths::new("lspd") + .and_then(|paths| paths.dir()) + .expect("runtime dir should resolve"); + assert_eq!(log, dir.join("lspd.log")); + } + #[test] fn daemon_idle_timeout_uses_env_override() { let _guard = env_lock() From b5a4059f6cd01865ad6d183991d88db5c26fddf8 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 19:04:44 +0900 Subject: [PATCH 41/73] test(ci): take three cold-start samples per cell for the #490 report The report needs a rate for every OS x start condition x scenario cell. The reliability workflow is not on the default branch yet, so dispatch is unavailable; this one PR run collects the samples and the report commit restores the single-sample PR default. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d90ab2ec..84f86926 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,6 +13,9 @@ permissions: jobs: lsp-write-reliability: uses: ./.github/workflows/lsp-write-reliability.yml + # Temporary for the #490 report: several cold samples per cell. Revert to the default after. + with: + cold_repetitions: '3' cli-latency: name: CLI Latency (required) From 877aadd89931822f5dea099e1c764f8c98576b15 Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 19:22:26 +0900 Subject: [PATCH 42/73] test(ci): isolate repeated cold samples to the initial report --- .github/workflows/test.yml | 4 ++-- docs/lsp-write-reliability.md | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 84f86926..9d84c8a1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,9 +13,9 @@ permissions: jobs: lsp-write-reliability: uses: ./.github/workflows/lsp-write-reliability.yml - # Temporary for the #490 report: several cold samples per cell. Revert to the default after. + # Initial #490 report takes several cold samples; develop and routine PRs use one. with: - cold_repetitions: '3' + cold_repetitions: ${{ github.head_ref == 'work/issue-490' && '3' || '1' }} cli-latency: name: CLI Latency (required) diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md index 2ced8102..8ac233df 100644 --- a/docs/lsp-write-reliability.md +++ b/docs/lsp-write-reliability.md @@ -99,6 +99,8 @@ PR / push は `Test` workflow から呼び出します。既存の必須 週次・手動の既定は各 5 試行を別枠で記録します。Windows の実測では コールド起動が約 46 秒 / 試行のため、PR の全条件測定は約 35 分かかります。 週次・手動の多試行を完了できるよう測定 job の上限は 240 分です。 +初回の `work/issue-490` PR のレポートだけは各コールド条件を 3 試行に増やし、 +各セルの反復測定を記録します。develop と通常の PR では自動的に 1 試行へ戻ります。 `--cold-repetitions` / `--download-repetitions` で増やせます。 既知の不具合は `tests/fixtures/lsp-write-baseline.json` にシナリオ単位で明記します。 From 626c1e5ad178c212d25fff8f02441c8b7b6e3b88 Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 20:53:36 +0900 Subject: [PATCH 43/73] fix(lsp): bound Windows daemon connection retries Use the existing unityd 100ms loopback connection deadline for lspd, with missing/running daemon regression tests and real Windows timing evidence. Refs #504. --- ...426ef0946a2da923b2d96fff2a533ba123f1.jsonl | 1 + ...d90d5824daa8fbf7b07a0a13c3cd6fcf7341.jsonl | 1 + ...1a69f92f36d306270df41f5c2fbd4f12fa9c.jsonl | 1 + ...7d4eaa3e0dfb51962b6782b74a847b438dc1.jsonl | 1 + docs/verification/issue-504/README.md | 70 ++ docs/verification/issue-504/after.json | 597 ++++++++++++++++++ docs/verification/issue-504/before.json | 193 ++++++ docs/verification/issue-504/check-evidence.py | 28 + src/lsp/daemon.rs | 76 ++- 9 files changed, 959 insertions(+), 9 deletions(-) create mode 100644 .gwt/work/events/2e/2ee3c747145cdff3740985cdc077426ef0946a2da923b2d96fff2a533ba123f1.jsonl create mode 100644 .gwt/work/events/a4/a446bced7269a52c5c357c9dd849d90d5824daa8fbf7b07a0a13c3cd6fcf7341.jsonl create mode 100644 .gwt/work/events/cb/cbb6fd086b6e0ac48784a806749d1a69f92f36d306270df41f5c2fbd4f12fa9c.jsonl create mode 100644 .gwt/work/events/e1/e127649332e27225ca5dc363608f7d4eaa3e0dfb51962b6782b74a847b438dc1.jsonl create mode 100644 docs/verification/issue-504/README.md create mode 100644 docs/verification/issue-504/after.json create mode 100644 docs/verification/issue-504/before.json create mode 100644 docs/verification/issue-504/check-evidence.py diff --git a/.gwt/work/events/2e/2ee3c747145cdff3740985cdc077426ef0946a2da923b2d96fff2a533ba123f1.jsonl b/.gwt/work/events/2e/2ee3c747145cdff3740985cdc077426ef0946a2da923b2d96fff2a533ba123f1.jsonl new file mode 100644 index 00000000..58679f2a --- /dev/null +++ b/.gwt/work/events/2e/2ee3c747145cdff3740985cdc077426ef0946a2da923b2d96fff2a533ba123f1.jsonl @@ -0,0 +1 @@ +{"id":"89ce584b-b926-498f-a6fb-6bf905037f49","work_item_id":"work-work-issue-504-10f6aa4a","kind":"start","title":"fix(lsp): cut the 43-second wait before the first C# write on Windows when lspd is not running","intent":"Check Board for latest updates","summary":"Codex is running","progress_summary":null,"status_category":"active","owner":"Issue #504","next_action":"Check Board for latest updates","agent_session_id":"04108877-9f1d-4de6-859d-a4bbad4605b7","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-504","worktree_path":"E:\\unity-cli\\work\\issue-504","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T11:34:29.435000400Z"} diff --git a/.gwt/work/events/a4/a446bced7269a52c5c357c9dd849d90d5824daa8fbf7b07a0a13c3cd6fcf7341.jsonl b/.gwt/work/events/a4/a446bced7269a52c5c357c9dd849d90d5824daa8fbf7b07a0a13c3cd6fcf7341.jsonl new file mode 100644 index 00000000..0de855a4 --- /dev/null +++ b/.gwt/work/events/a4/a446bced7269a52c5c357c9dd849d90d5824daa8fbf7b07a0a13c3cd6fcf7341.jsonl @@ -0,0 +1 @@ +{"id":"ec40077f-e57c-473f-b22d-60ccabb788a2","work_item_id":"work-work-issue-504-10f6aa4a","kind":"update","title":"Windows の C# 初回書き込み待機を短縮","intent":"AC-1〜3 未達、TCP 接続待機の原因確認","summary":null,"progress_summary":"全受入条件を監査。既存実装の修正と Windows 改善の証跡はありません。","status_category":null,"owner":"Issue #504","next_action":null,"agent_session_id":"04108877-9f1d-4de6-859d-a4bbad4605b7","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-504","worktree_path":"E:\\unity-cli\\work\\issue-504","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T11:37:35.601557300Z"} diff --git a/.gwt/work/events/cb/cbb6fd086b6e0ac48784a806749d1a69f92f36d306270df41f5c2fbd4f12fa9c.jsonl b/.gwt/work/events/cb/cbb6fd086b6e0ac48784a806749d1a69f92f36d306270df41f5c2fbd4f12fa9c.jsonl new file mode 100644 index 00000000..cdeed495 --- /dev/null +++ b/.gwt/work/events/cb/cbb6fd086b6e0ac48784a806749d1a69f92f36d306270df41f5c2fbd4f12fa9c.jsonl @@ -0,0 +1 @@ +{"id":"2cadaff0-9129-49fa-b82b-f7a6ac3482c7","work_item_id":"work-work-issue-504-10f6aa4a","kind":"update","title":"Issue #504 の受入条件を充足","intent":"受入条件と既存実装の監査","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #504","next_action":null,"agent_session_id":"04108877-9f1d-4de6-859d-a4bbad4605b7","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-504","worktree_path":"E:\\unity-cli\\work\\issue-504","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T11:35:57.236479500Z"} diff --git a/.gwt/work/events/e1/e127649332e27225ca5dc363608f7d4eaa3e0dfb51962b6782b74a847b438dc1.jsonl b/.gwt/work/events/e1/e127649332e27225ca5dc363608f7d4eaa3e0dfb51962b6782b74a847b438dc1.jsonl new file mode 100644 index 00000000..e1c639df --- /dev/null +++ b/.gwt/work/events/e1/e127649332e27225ca5dc363608f7d4eaa3e0dfb51962b6782b74a847b438dc1.jsonl @@ -0,0 +1 @@ +{"id":"77355af4-c7c0-4f75-8e8b-c6a0d3615ee6","work_item_id":"work-work-issue-504-10f6aa4a","kind":"done","title":"Windows の C# 初回書き込み待機を短縮","intent":"実装と計測証跡を確定し、正式検証・PR・必須 CI へ","summary":null,"progress_summary":"全ACの変更前監査、原因記録、RED/GREEN、Windows実測を完了。cold p50 13.183s→5.518s、Rust 全テスト・clippy・skills lint と Linux C# 56テストがPASS。未変更C#のWindows URI失敗2件はPMへ別件報告。User Verification Result: n/a (autonomous)。PRのWindows計測でAC-3を確認し自動マージまで継続。","status_category":"done","owner":"Issue #504","next_action":null,"agent_session_id":"04108877-9f1d-4de6-859d-a4bbad4605b7","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-504","worktree_path":"E:\\unity-cli\\work\\issue-504","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T11:53:34.685101600Z"} diff --git a/docs/verification/issue-504/README.md b/docs/verification/issue-504/README.md new file mode 100644 index 00000000..f61c9f2a --- /dev/null +++ b/docs/verification/issue-504/README.md @@ -0,0 +1,70 @@ +# Issue #504 — Windows lspd cold-start latency + +Launch mode: autonomous + +User Verification Result: n/a (autonomous) + +Agent Visual Check: n/a (no UI surface) + +## Cause and regression proof + +The Windows client used `TcpStream::connect` without a connection deadline. +The initial tool request, status check, stale-file cleanup probes and readiness +polling repeatedly waited for Windows TCP retries when lspd was absent. +The ten-second read/write timeouts were set only after connecting. + +On Windows 11, a closed loopback port took 2025ms to reject a connection; +a 100ms deadline returned in 110ms. The new production-path regression test +failed before the fix after 2.027s, while the running-listener test passed. +Both tests passed after the fix in 0.11s total. + +Use the same 100ms local connection deadline as unityd. This limits only the +TCP handshake; daemon startup and tool response deadlines remain independent. +Tests use ephemeral ports, avoiding the shared Windows lspd port 6421. + +## Measured results + +The same Windows host and measurement runner used a real CLI and LSP. +`before.json` and `after.json` retain hashes, responses, differences and timings. + +| Condition / write_file | Before n / p50 / p95 (ms) | After n / p50 / p95 (ms) | +| --- | --- | --- | +| daemon_stopped | 3 / 13183.299 / 15134.534 | 5 / 5517.880 / 9375.031 | +| first_download | — | 3 / 6632.017 / 7675.544 | +| warm_indexed | — | 2 / 216.366 / 220.186 | +| unindexed | — | 2 / 712.967 / 719.874 | + +The original CI report in #504 measured about 43 seconds on its Windows host. +The local baseline differs; the PR's existing three-OS LSP Write Reliability +workflow supplies a separate CI comparison. Local cold-start p50 is below 10s. + +All twelve after-fix tool calls returned a successful LSP edit. Published LSP +0.18.1 still added a BOM (#498); byte equality therefore failed in every sample. +These defects remain in the JSON and are accepted only by the existing +version-scoped regression baseline. This report proves latency improvement, +not qualification for prohibiting direct editing. + +## Reproduce + +```bash +cargo test --bin unity-cli lsp::daemon::tests::tcp_connect -- --test-threads=1 +cargo build --bin unity-cli +dotnet publish lsp/Server.csproj -c Release -r win-x64 --self-contained true -o .cache/lsp-reliability-publish +python -B scripts/lsp-write-reliability.py --unity-cli target/debug/unity-cli.exe --lsp-publish .cache/lsp-reliability-publish --out .cache/issue-504-verified --conditions daemon_stopped --scenarios write_file --cold-repetitions 5 --baseline tests/fixtures/lsp-write-baseline.json +python -B docs/verification/issue-504/check-evidence.py .cache/issue-504-verified/results.json +``` + +The evidence checker requires at least three completed Windows cold samples, +successful real LSP responses, no new write defect, and p50 strictly below 10s. + +## Unrelated baseline check + +An additional Windows `dotnet test lsp/Server.Tests.csproj` run produced +54 passes and two failures in the existing +`RequestRouterTests.SymbolQueries_RespectAssetsScopeBeforeScanningPackages` +theory (`workspace/symbol` and `unitycli/referencesByName`): both returned an +empty array instead of `Asset.cs`. No C# source changed in this fix. +`Uri2Path` in `LspRequestRouter.cs` strips `file://` from the test's standard +`file:///C:/...` URI, leaving a Windows path starting with `/C:/...`. +This separate finding was reported to the PM. The full C# suite is verified on +Linux, matching the repository's required `LSP Tests` CI environment. diff --git a/docs/verification/issue-504/after.json b/docs/verification/issue-504/after.json new file mode 100644 index 00000000..55722b1b --- /dev/null +++ b/docs/verification/issue-504/after.json @@ -0,0 +1,597 @@ +{ + "schema_version": 1, + "os": "Windows", + "rid": "win-x64", + "started_at": "2026-10-13T11:44:34.733438+00:00", + "cli_sha256": "37d014406f92518c1b5a019d4ff6e7d4646bcc1f6c1c7ddbd5ddb2150a901ca8", + "runner_sha256": "21d102a80b2be31514117df4e7f10d252a6320c5e6fe4254da4295b08c26898d", + "requested_conditions": [ + "daemon_stopped", + "warm_indexed", + "unindexed", + "first_download" + ], + "repetitions": 2, + "cold_repetitions": 5, + "download_repetitions": 3, + "rows": [ + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "daemon_stopped", + "sample": 0, + "direct_ms": 0.4454000008990988, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2023.329300001933, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 6411.945699997887, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "daemon_stopped", + "sample": 1, + "direct_ms": 0.5148999989614822, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2032.4424999998882, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 5262.767399999575, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "daemon_stopped", + "sample": 2, + "direct_ms": 0.49109999963548034, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2022.2695999982534, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 5517.880100000184, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "daemon_stopped", + "sample": 3, + "direct_ms": 0.9161999987554736, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2054.629099999147, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 9375.031100000342, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "daemon_stopped", + "sample": 4, + "direct_ms": 0.5122000002302229, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2045.9140999992087, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 5283.347100001265, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 0, + "direct_ms": 0.46749999819439836, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2958.607499997015, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 216.36579999903915, + "lsp_version": "checkout", + "lsp_sha256": "cb04b88cff09ced980c422499010b6986a0af00f8e3473c17b6350c74b1428b9" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "warm_indexed", + "sample": 1, + "direct_ms": 0.450999999884516, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2975.8909000011045, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 220.18570000000182, + "lsp_version": "checkout", + "lsp_sha256": "cb04b88cff09ced980c422499010b6986a0af00f8e3473c17b6350c74b1428b9" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "unindexed", + "sample": 0, + "direct_ms": 0.45089999912306666, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2272.84729999883, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 712.9674999996496, + "lsp_version": "checkout", + "lsp_sha256": "cb04b88cff09ced980c422499010b6986a0af00f8e3473c17b6350c74b1428b9" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "unindexed", + "sample": 1, + "direct_ms": 0.4530000005615875, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2268.4746000013547, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 719.8742000000493, + "lsp_version": "checkout", + "lsp_sha256": "cb04b88cff09ced980c422499010b6986a0af00f8e3473c17b6350c74b1428b9" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "first_download", + "sample": 0, + "direct_ms": 0.4700999998021871, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2020.7783000005293, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 6356.362900001841, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "first_download", + "sample": 1, + "direct_ms": 0.5388999998103827, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2017.9347999983293, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 7675.544499998068, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "first_download", + "sample": 2, + "direct_ms": 0.4291000004741363, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2031.0315000024275, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 6632.016700001259, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + } + ], + "summary": { + "attempts": 12, + "successes": 0, + "success_rate": 0.0, + "failure_types": { + "bom_added": 12 + }, + "p50_ms": 5283.347, + "p95_ms": 9375.031, + "direct_p50_ms": 0.467, + "direct_p95_ms": 0.916 + }, + "regressions": [], + "finished_at": "2026-10-13T11:46:02.271422+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-504/before.json b/docs/verification/issue-504/before.json new file mode 100644 index 00000000..67753944 --- /dev/null +++ b/docs/verification/issue-504/before.json @@ -0,0 +1,193 @@ +{ + "schema_version": 1, + "os": "Windows", + "rid": "win-x64", + "started_at": "2026-10-13T11:38:57.334878+00:00", + "cli_sha256": "380e45c77eafce19fc82f35cade8f18073f9621bb3596250a4ebf89859080117", + "runner_sha256": "21d102a80b2be31514117df4e7f10d252a6320c5e6fe4254da4295b08c26898d", + "requested_conditions": [ + "daemon_stopped" + ], + "repetitions": 5, + "cold_repetitions": 3, + "download_repetitions": 1, + "rows": [ + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "daemon_stopped", + "sample": 0, + "direct_ms": 0.4284999995434191, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2042.874300001131, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 15134.534499997244, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "daemon_stopped", + "sample": 1, + "direct_ms": 0.44689999776892364, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2026.9910999995773, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 13183.299099997384, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + }, + { + "scenario": "write_file", + "tool": "write_csharp_file", + "condition": "daemon_stopped", + "sample": 2, + "direct_ms": 0.45089999912306666, + "failures": [ + "bom_added" + ], + "differences": [ + { + "path": "Assets/Sample.cs", + "direct_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_sha256": "0a376c7da796e5991b0510d7f09bfb751199bb5d4702c07a61ac84cb74ecf34e", + "direct_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "lsp_text_sha256": "908fcb643b9e33e9f39a7a2c816f90d968c11209a0d79441e6a7ce197e2d3cfa", + "direct_bytes": 51, + "lsp_bytes": 54, + "diff": "--- direct/Assets/Sample.cs\n+++ lsp/Assets/Sample.cs\n@@ -1 +1 @@\n-public class Sample { public int Run(){return 2;}}\n+public class Sample { public int Run(){return 2;}}\n" + } + ], + "setup_ms": 2033.2515000009153, + "returncode": 0, + "response": { + "command": "raw write_csharp_file", + "data": { + "applied": true, + "backend": "lsp", + "changedFiles": [ + "Assets/Sample.cs" + ], + "changedSymbols": [], + "diagnostics": [], + "diffPreview": [], + "reason": null, + "success": true + }, + "errors": [], + "success": true, + "warnings": [] + }, + "stdout": "{\"command\":\"raw write_csharp_file\",\"data\":{\"applied\":true,\"backend\":\"lsp\",\"changedFiles\":[\"Assets/Sample.cs\"],\"changedSymbols\":[],\"diagnostics\":[],\"diffPreview\":[],\"reason\":null,\"success\":true},\"errors\":[],\"success\":true,\"warnings\":[]}\n", + "stderr": "", + "elapsed_ms": 13125.072800001362, + "lsp_version": "0.18.1", + "lsp_sha256": "255da253cca997a38c2ee4d9daefe1ce843e1ff901c411dbef350b6280291927" + } + ], + "summary": { + "attempts": 3, + "successes": 0, + "success_rate": 0.0, + "failure_types": { + "bom_added": 3 + }, + "p50_ms": 13183.299, + "p95_ms": 15134.534, + "direct_p50_ms": 0.447, + "direct_p95_ms": 0.451 + }, + "regressions": [ + { + "scenario": "write_file", + "condition": "daemon_stopped", + "new_failures": [ + "bom_added" + ] + }, + { + "scenario": "write_file", + "condition": "daemon_stopped", + "new_failures": [ + "bom_added" + ] + }, + { + "scenario": "write_file", + "condition": "daemon_stopped", + "new_failures": [ + "bom_added" + ] + } + ], + "finished_at": "2026-10-13T11:39:47.394484+00:00" +} \ No newline at end of file diff --git a/docs/verification/issue-504/check-evidence.py b/docs/verification/issue-504/check-evidence.py new file mode 100644 index 00000000..df000c93 --- /dev/null +++ b/docs/verification/issue-504/check-evidence.py @@ -0,0 +1,28 @@ +"""Check the Windows cold-start latency AC without hiding write failures.""" +import importlib.util +import json +from pathlib import Path +import sys + +ROOT = Path(__file__).resolve().parents[3] +SPEC = importlib.util.spec_from_file_location("reliability", ROOT / "scripts/lsp-write-reliability.py") +reliability = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(reliability) + +report_path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).with_name("after.json") +report = json.loads(report_path.read_text(encoding="utf-8")) +assert report["os"] == "Windows" and report["rid"] == "win-x64" +assert report.get("finished_at"), "measurement is incomplete" +rows = [row for row in report["rows"] + if row["condition"] == "daemon_stopped" and row["scenario"] == "write_file"] +assert len(rows) >= 3, "at least three independent cold starts are required" +assert len({row["sample"] for row in rows}) == len(rows), "duplicate samples" +for row in rows: + assert row["returncode"] == 0 and not reliability.response_failures(row["returncode"], row["response"]) +baseline = json.loads((ROOT / "tests/fixtures/lsp-write-baseline.json").read_text(encoding="utf-8")) +assert not reliability.regressions(rows, baseline), "a new write defect must not count as a latency pass" +summary = reliability.summarize(rows) +assert summary["p50_ms"] < 10_000, f"Windows daemon_stopped p50 exceeds the AC: {summary}" +print(f"PASS: Windows daemon_stopped/write_file n={len(rows)}, " + f"p50={summary['p50_ms']}ms, p95={summary['p95_ms']}ms; " + f"recorded write defects={summary['failure_types']}") diff --git a/src/lsp/daemon.rs b/src/lsp/daemon.rs index fbe6a682..be21df81 100644 --- a/src/lsp/daemon.rs +++ b/src/lsp/daemon.rs @@ -542,18 +542,29 @@ fn connect_client() -> Result { #[cfg(not(unix))] { - let stream = std::net::TcpStream::connect(("127.0.0.1", daemon_port())) - .context("Failed to connect to lspd TCP endpoint")?; - stream - .set_read_timeout(Some(Duration::from_secs(10))) - .context("Failed to set lspd read timeout")?; - stream - .set_write_timeout(Some(Duration::from_secs(10))) - .context("Failed to set lspd write timeout")?; - Ok(stream) + connect_tcp_client(daemon_port()) } } +#[cfg(not(unix))] +fn connect_tcp_client(port: u16) -> Result { + // A closed loopback port takes seconds to fail on Windows. Startup probes + // must return promptly so auto-start can spawn/poll lspd without TCP retries. + // Match unityd's connection deadline; RPC timeouts remain independent. + let stream = std::net::TcpStream::connect_timeout( + &std::net::SocketAddr::from(([127, 0, 0, 1], port)), + Duration::from_millis(100), + ) + .context("Failed to connect to lspd TCP endpoint")?; + stream + .set_read_timeout(Some(Duration::from_secs(10))) + .context("Failed to set lspd read timeout")?; + stream + .set_write_timeout(Some(Duration::from_secs(10))) + .context("Failed to set lspd write timeout")?; + Ok(stream) +} + fn is_would_block(error: &std::io::Error) -> bool { error.kind() == std::io::ErrorKind::WouldBlock } @@ -637,6 +648,53 @@ mod tests { use std::io::{BufRead, BufReader}; use tempfile::tempdir; + #[cfg(not(unix))] + #[test] + fn tcp_connect_without_a_daemon_returns_promptly() { + let listener = std::net::TcpListener::bind(("127.0.0.1", 0)).unwrap(); + let port = listener.local_addr().unwrap().port(); + drop(listener); + + let started = Instant::now(); + let error = connect_tcp_client(port).expect_err("no daemon is listening"); + assert!(error + .to_string() + .contains("Failed to connect to lspd TCP endpoint")); + assert!( + started.elapsed() < Duration::from_secs(1), + "a missing local daemon must not wait for Windows TCP retries: {:?}", + started.elapsed() + ); + } + + #[cfg(not(unix))] + #[test] + fn tcp_connect_to_a_running_daemon_preserves_io_timeouts_and_responses() { + let listener = std::net::TcpListener::bind(("127.0.0.1", 0)).unwrap(); + let mut client = connect_tcp_client(listener.local_addr().unwrap().port()).unwrap(); + assert_eq!( + client.read_timeout().unwrap(), + Some(Duration::from_secs(10)) + ); + assert_eq!( + client.write_timeout().unwrap(), + Some(Duration::from_secs(10)) + ); + + let (mut server, _) = listener.accept().unwrap(); + server + .set_read_timeout(Some(Duration::from_secs(1))) + .unwrap(); + client.write_all(b"{\"type\":\"ping\"}\n").unwrap(); + let mut request = String::new(); + BufReader::new(&mut server).read_line(&mut request).unwrap(); + assert_eq!(request, "{\"type\":\"ping\"}\n"); + server.write_all(b"{\"ok\":true}\n").unwrap(); + let mut response = String::new(); + BufReader::new(client).read_line(&mut response).unwrap(); + assert_eq!(response, "{\"ok\":true}\n"); + } + fn env_lock() -> &'static std::sync::Mutex<()> { crate::test_env::env_lock() } From b3c032d8141a7837a15dc07ca28d8f519f55f192 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 20:56:52 +0900 Subject: [PATCH 44/73] fix(lsp): keep the original BOM and newlines when C# LSP write tools save a file Every LSP write saved with Encoding.UTF8, which always emits a UTF-8 BOM, so BOM-less files gained one and new files were created with one. - Read existing files once into text plus their on-disk format (encoding/BOM and single newline convention) and write back with it - Normalize given/inserted text to the file's newline convention; mixed conventions are left untouched - New files from create_csharp_file / create_class are UTF-8 without BOM Refs #498 Co-Authored-By: Claude Opus 5.5 --- docs/tools.md | 6 ++ lsp/EditServiceTests.cs | 6 +- lsp/Server.Core/LspEditService.cs | 45 +++++---- lsp/Server.Core/LspSourceFile.cs | 67 +++++++++++++ lsp/SourceFileFormatTests.cs | 157 ++++++++++++++++++++++++++++++ 5 files changed, 255 insertions(+), 26 deletions(-) create mode 100644 lsp/Server.Core/LspSourceFile.cs create mode 100644 lsp/SourceFileFormatTests.cs diff --git a/docs/tools.md b/docs/tools.md index c0402509..cade5edb 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -369,6 +369,12 @@ python3 scripts/e2e-prefab.py --launch --editmode --versions 6000.3.25f1,2022.3. | `apply_csharp_edits` | Apply structured C# source edits | | `create_class` | Create a C# class | +The C# write tools keep the file encoding of an existing file: its byte order +mark (present or absent) and, when the file uses a single newline convention +(LF or CRLF), that convention for the whole saved text. New files from +`create_csharp_file` and `create_class` are UTF-8 without a BOM and keep the +newlines of the given text. + `hot_reload` changes the body of existing methods while Play Mode keeps running (scene, objects and field values are preserved; the `.cs` file on disk is not modified). Prerequisites: the optional FastScriptReload 1.8.0 package installed diff --git a/lsp/EditServiceTests.cs b/lsp/EditServiceTests.cs index 75488b17..2f955732 100644 --- a/lsp/EditServiceTests.cs +++ b/lsp/EditServiceTests.cs @@ -189,11 +189,7 @@ public async Task ReplaceSymbolBodyAsync_PreservesTrailingTriviaOfReplacedBody(s using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); Assert.True(response.RootElement.GetProperty("applied").GetBoolean()); - // The UTF-8 BOM written on save is tracked separately (#498); compare the text bytes after it. - var bytes = await File.ReadAllBytesAsync(scriptPath); - var preamble = Encoding.UTF8.GetPreamble(); - var body = bytes.AsSpan().StartsWith(preamble) ? bytes[preamble.Length..] : bytes; - Assert.Equal(Encoding.UTF8.GetBytes(expected), body); + Assert.Equal(Encoding.UTF8.GetBytes(expected), await File.ReadAllBytesAsync(scriptPath)); } finally { diff --git a/lsp/Server.Core/LspEditService.cs b/lsp/Server.Core/LspEditService.cs index 84778a1a..cc299e22 100644 --- a/lsp/Server.Core/LspEditService.cs +++ b/lsp/Server.Core/LspEditService.cs @@ -35,7 +35,7 @@ public async Task RenameByNamePathAsync(string relative, string namePath var handle = await AcquireFileLockAsync(full); try { - var text = await File.ReadAllTextAsync(full); + var (text, format) = await LspSourceFile.ReadAsync(full); var tree = CSharpSyntaxTree.ParseText(text); var root = await tree.GetRootAsync(); var normalizedNamePath = NormalizeNamePath(namePath); @@ -147,7 +147,7 @@ public async Task RenameByNamePathAsync(string relative, string namePath if (newText == text) return EditResult(false, false, reason: "no_change"); if (apply) { - await File.WriteAllTextAsync(full, newText, Encoding.UTF8); + await LspSourceFile.WriteAsync(full, newText, format); return EditResult( true, true, @@ -169,6 +169,7 @@ public async Task RenameByNamePathAsync(string relative, string namePath var rewrittenFullText = newRoot.ToFullString(); var updatedFiles = new Dictionary(StringComparer.OrdinalIgnoreCase) { [full] = rewrittenFullText }; var originalByFile = new Dictionary(StringComparer.OrdinalIgnoreCase) { [full] = text }; + var formatByFile = new Dictionary(StringComparer.OrdinalIgnoreCase) { [full] = format }; void TrackRenameChanges(string file, string originalSrc, SyntaxNode currentRoot) { var tokens = currentRoot.DescendantTokens().Where(tk => tk.IsKind(SyntaxKind.IdentifierToken) && tk.ValueText == oldName).ToArray(); @@ -221,7 +222,8 @@ void TrackRenameChanges(string file, string originalSrc, SyntaxNode currentRoot) var fileHandle = await AcquireFileLockAsync(file); try { - var src = await File.ReadAllTextAsync(file); + var (src, fileFormat) = await LspSourceFile.ReadAsync(file); + formatByFile[file] = fileFormat; var t = CSharpSyntaxTree.ParseText(src); var r = await t.GetRootAsync(); TrackRenameChanges(file, src, r); @@ -255,7 +257,7 @@ void TrackRenameChanges(string file, string originalSrc, SyntaxNode currentRoot) locks.Add(await AcquireFileLockAsync(file)); } foreach (var kv in updatedFiles) - await File.WriteAllTextAsync(kv.Key, kv.Value, Encoding.UTF8); + await LspSourceFile.WriteAsync(kv.Key, kv.Value, formatByFile[kv.Key]); } finally { @@ -371,8 +373,8 @@ public async Task WriteCSharpFileAsync(string relative, string newText, var handle = await AcquireFileLockAsync(full); try { - var original = await File.ReadAllTextAsync(full); - var updated = MaybeFormatText(newText ?? string.Empty, format); + var (original, fileFormat) = await LspSourceFile.ReadAsync(full); + var updated = fileFormat.ApplyNewlines(MaybeFormatText(newText ?? string.Empty, format)); var diagnostics = validate ? CollectSyntaxDiagnostics(updated).Cast().ToArray() : Array.Empty(); if (validate && HasErrorDiagnostics(diagnostics.Cast>())) { @@ -393,7 +395,7 @@ public async Task WriteCSharpFileAsync(string relative, string newText, reason: "preview_only"); } - await File.WriteAllTextAsync(full, updated, Encoding.UTF8); + await LspSourceFile.WriteAsync(full, updated, fileFormat); return EditResult( true, true, @@ -412,8 +414,8 @@ public async Task CreateCSharpFileAsync(string relative, string text, bo var exists = File.Exists(full); if (exists && !overwrite) return EditResult(false, false, reason: "file_exists"); - var original = exists ? await File.ReadAllTextAsync(full) : string.Empty; - var normalizedText = MaybeFormatText(text ?? string.Empty, format); + var (original, fileFormat) = exists ? await LspSourceFile.ReadAsync(full) : (string.Empty, LspSourceFileFormat.NewFile); + var normalizedText = fileFormat.ApplyNewlines(MaybeFormatText(text ?? string.Empty, format)); var diagnostics = validate ? CollectSyntaxDiagnostics(normalizedText).Cast().ToArray() : Array.Empty(); if (validate && HasErrorDiagnostics(diagnostics.Cast>())) { @@ -435,7 +437,7 @@ public async Task CreateCSharpFileAsync(string relative, string text, bo } Directory.CreateDirectory(Path.GetDirectoryName(full)!); - await File.WriteAllTextAsync(full, normalizedText, Encoding.UTF8); + await LspSourceFile.WriteAsync(full, normalizedText, fileFormat); return EditResult( true, true, @@ -447,6 +449,7 @@ public async Task ApplyCSharpEditsAsync(JsonElement files, bool validate { var desired = new Dictionary(StringComparer.OrdinalIgnoreCase); var originals = new Dictionary(StringComparer.OrdinalIgnoreCase); + var formats = new Dictionary(StringComparer.OrdinalIgnoreCase); var diagnostics = new List(); foreach (var item in files.EnumerateArray()) @@ -463,8 +466,8 @@ public async Task ApplyCSharpEditsAsync(JsonElement files, bool validate return EditResult(false, false, reason: "duplicate_path"); } - originals[full] = await File.ReadAllTextAsync(full); - var formatted = MaybeFormatText(newText, format); + (originals[full], formats[full]) = await LspSourceFile.ReadAsync(full); + var formatted = formats[full].ApplyNewlines(MaybeFormatText(newText, format)); desired[full] = formatted; if (validate) { @@ -513,7 +516,7 @@ public async Task ApplyCSharpEditsAsync(JsonElement files, bool validate } foreach (var file in changed) { - await File.WriteAllTextAsync(file, desired[file], Encoding.UTF8); + await LspSourceFile.WriteAsync(file, desired[file], formats[file]); } } finally @@ -532,7 +535,7 @@ public async Task ReplaceSymbolBodyAsync(string relative, string namePat var handle = await AcquireFileLockAsync(full); try { - var text = await File.ReadAllTextAsync(full); + var (text, format) = await LspSourceFile.ReadAsync(full); var tree = CSharpSyntaxTree.ParseText(text); var root = await tree.GetRootAsync(); var (_, last) = FindNodeByNamePath(root, normalizedPath); @@ -551,7 +554,7 @@ public async Task ReplaceSymbolBodyAsync(string relative, string namePat if (newText == text) return EditResult(false, false, reason: "no_change"); if (apply) { - await File.WriteAllTextAsync(full, newText, Encoding.UTF8); + await LspSourceFile.WriteAsync(full, newText, format); return EditResult( true, true, @@ -580,7 +583,7 @@ public async Task InsertAroundSymbolAsync(string relative, string namePa var handle = await AcquireFileLockAsync(full); try { - var original = await File.ReadAllTextAsync(full); + var (original, format) = await LspSourceFile.ReadAsync(full); var tree = CSharpSyntaxTree.ParseText(original); var root = await tree.GetRootAsync(); var (_, last) = FindNodeByNamePath(root, normalizedPath); @@ -595,7 +598,7 @@ public async Task InsertAroundSymbolAsync(string relative, string namePa if (newText0 == original) return EditResult(false, false, reason: "no_change"); if (apply) { - await File.WriteAllTextAsync(full, newText0, Encoding.UTF8); + await LspSourceFile.WriteAsync(full, newText0, format); return EditResult( true, true, @@ -633,7 +636,7 @@ public async Task InsertAroundSymbolAsync(string relative, string namePa if (newText1 == original) return EditResult(false, false, reason: "no_change"); if (apply) { - await File.WriteAllTextAsync(full, newText1, Encoding.UTF8); + await LspSourceFile.WriteAsync(full, newText1, format); return EditResult( true, true, @@ -652,7 +655,7 @@ public async Task InsertAroundSymbolAsync(string relative, string namePa if (newText == original) return EditResult(false, false, reason: "no_change"); if (apply) { - await File.WriteAllTextAsync(full, newText, Encoding.UTF8); + await LspSourceFile.WriteAsync(full, newText, format); return EditResult( true, true, @@ -863,7 +866,7 @@ public async Task RemoveSymbolAsync(string relative, string namePath, bo try { // Locate target declaration first - var original = await File.ReadAllTextAsync(full); + var (original, format) = await LspSourceFile.ReadAsync(full); var tree0 = CSharpSyntaxTree.ParseText(original); var root0 = await tree0.GetRootAsync(); var (_, targetNode) = FindNodeByNamePath(root0, normalizedPath); @@ -948,7 +951,7 @@ void CollectReferences(string file, SyntaxNode syntaxRoot) changedFiles: new[] { NormalizeRelative(relative) }, changedSymbols: new[] { normalizedPath }); } - await File.WriteAllTextAsync(full, newText, Encoding.UTF8); + await LspSourceFile.WriteAsync(full, newText, format); return EditResult( true, true, diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs new file mode 100644 index 00000000..5520f563 --- /dev/null +++ b/lsp/Server.Core/LspSourceFile.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace UnityCli.Lsp.Core; + +/// +/// On-disk shape of a C# source file that LSP writes must keep: the encoding (and whether it +/// carries a BOM) and the newline convention. New files are UTF-8 without a BOM. +/// +public readonly record struct LspSourceFileFormat(Encoding Encoding, string? NewLine) +{ + private static readonly Encoding Utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); + + public static LspSourceFileFormat NewFile { get; } = new(Utf8NoBom, null); + + public static LspSourceFileFormat Detect(byte[] bytes) => Decode(bytes).Format; + + public static (string Text, LspSourceFileFormat Format) Decode(byte[] bytes) + { + var encoding = DetectEncoding(bytes); + var preamble = encoding.GetPreamble().Length; + var text = encoding.GetString(bytes, preamble, bytes.Length - preamble); + return (text, new LspSourceFileFormat(encoding, DetectNewLine(text))); + } + + /// Rewrites line breaks to the file's convention; mixed or unknown conventions are left as given. + public string ApplyNewlines(string text) + { + if (NewLine is null) return text; + var lf = text.Replace("\r\n", "\n"); + return NewLine == "\n" ? lf : lf.Replace("\n", NewLine); + } + + private static Encoding DetectEncoding(byte[] b) + { + if (b.Length >= 3 && b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF) return new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); + if (b.Length >= 4 && b[0] == 0xFF && b[1] == 0xFE && b[2] == 0 && b[3] == 0) return new UTF32Encoding(bigEndian: false, byteOrderMark: true); + if (b.Length >= 2 && b[0] == 0xFF && b[1] == 0xFE) return new UnicodeEncoding(bigEndian: false, byteOrderMark: true); + if (b.Length >= 2 && b[0] == 0xFE && b[1] == 0xFF) return new UnicodeEncoding(bigEndian: true, byteOrderMark: true); + return Utf8NoBom; + } + + private static string? DetectNewLine(string text) + { + int crlf = 0, lf = 0; + for (var i = 0; i < text.Length; i++) + { + if (text[i] != '\n') continue; + if (i > 0 && text[i - 1] == '\r') crlf++; + else lf++; + } + if (crlf > 0 && lf == 0) return "\r\n"; + if (lf > 0 && crlf == 0) return "\n"; + return null; + } +} + +public static class LspSourceFile +{ + public static async Task<(string Text, LspSourceFileFormat Format)> ReadAsync(string path) + => LspSourceFileFormat.Decode(await File.ReadAllBytesAsync(path)); + + public static Task WriteAsync(string path, string text, LspSourceFileFormat format) + => File.WriteAllTextAsync(path, format.ApplyNewlines(text), format.Encoding); +} diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs new file mode 100644 index 00000000..91cc028a --- /dev/null +++ b/lsp/SourceFileFormatTests.cs @@ -0,0 +1,157 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using UnityCli.Lsp.Core; +using Xunit; + +public sealed class SourceFileFormatTests +{ + private const string Original = "public class Sample\n{\n public int Run() { return 1; }\n}\n"; + + public static TheoryData ExistingFileEdits() + { + var data = new TheoryData(); + foreach (var operation in new[] { "write", "apply", "replace_body", "insert_before", "insert_after", "remove", "rename" }) + foreach (var bom in new[] { false, true }) + foreach (var newline in new[] { "\n", "\r\n" }) + { + data.Add(operation, bom, newline); + } + return data; + } + + [Theory] + [MemberData(nameof(ExistingFileEdits))] + public async Task ExistingFileEdits_KeepTheOriginalBomAndNewlines(string operation, bool bom, string newline) + { + var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); + Directory.CreateDirectory(Path.Combine(root, "Assets")); + var scriptPath = Path.Combine(root, "Assets", "Sample.cs"); + await File.WriteAllBytesAsync(scriptPath, Encode(Original, bom, newline)); + try + { + var service = new LspEditService(root, new LspFileLockProvider()); + // Inputs always use LF so a CRLF file also proves newline preservation. + const string written = "public class Sample\n{\n public int Run() { return 2; }\n}\n"; + using var files = JsonDocument.Parse(JsonSerializer.Serialize(new[] { new { relative = "Assets/Sample.cs", newText = written } })); + var (result, expected) = operation switch + { + "write" => (await service.WriteCSharpFileAsync("Assets/Sample.cs", written, true, true, false), written), + "apply" => (await service.ApplyCSharpEditsAsync(files.RootElement, true, true, false), written), + "replace_body" => (await service.ReplaceSymbolBodyAsync("Assets/Sample.cs", "Sample/Run", "{ return 2; }", true), written), + "insert_before" => (await service.InsertAroundSymbolAsync("Assets/Sample.cs", "Sample/Run", "public int Added;\n", false, true), + "public class Sample\n{\npublic int Added;\n public int Run() { return 1; }\n}\n"), + "insert_after" => (await service.InsertAroundSymbolAsync("Assets/Sample.cs", "Sample/Run", "public int Added;\n", true, true), + "public class Sample\n{\n public int Run() { return 1; }\npublic int Added;\n}\n"), + "remove" => (await service.RemoveSymbolAsync("Assets/Sample.cs", "Sample/Run", true, false, false), + // KeepExteriorTrivia leaves the member's indentation and line break behind. + "public class Sample\n{\n \n}\n"), + _ => (await service.RenameByNamePathAsync("Assets/Sample.cs", "Sample/Run", "Execute", true), + Original.Replace("Run", "Execute")), + }; + + using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); + Assert.True(response.RootElement.GetProperty("applied").GetBoolean(), response.RootElement.ToString()); + Assert.Equal(Encode(expected, bom, newline), await File.ReadAllBytesAsync(scriptPath)); + } + finally + { + Directory.Delete(root, recursive: true); + } + } + + [Fact] + public async Task RenameAcrossFiles_KeepsEachFileFormat() + { + var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); + Directory.CreateDirectory(Path.Combine(root, "Assets")); + const string declaration = "namespace Demo\n{\n public partial class Sample {}\n}\n"; + const string use = "namespace Demo\n{\n public class Consumer { public Sample Value; }\n}\n"; + await File.WriteAllBytesAsync(Path.Combine(root, "Assets", "Sample.cs"), Encode(declaration, true, "\r\n")); + await File.WriteAllBytesAsync(Path.Combine(root, "Assets", "Use.cs"), Encode(use, false, "\n")); + try + { + var service = new LspEditService(root, new LspFileLockProvider()); + + var result = await service.RenameByNamePathAsync("Assets/Sample.cs", "Sample", "Renamed", true); + + using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); + Assert.True(response.RootElement.GetProperty("applied").GetBoolean(), response.RootElement.ToString()); + Assert.Equal(Encode(declaration.Replace("Sample", "Renamed"), true, "\r\n"), + await File.ReadAllBytesAsync(Path.Combine(root, "Assets", "Sample.cs"))); + Assert.Equal(Encode(use.Replace("Sample", "Renamed"), false, "\n"), + await File.ReadAllBytesAsync(Path.Combine(root, "Assets", "Use.cs"))); + } + finally + { + Directory.Delete(root, recursive: true); + } + } + + [Theory] + [InlineData("public class Sample {}\n")] + [InlineData("using UnityEngine;\r\npublic class Sample : MonoBehaviour {}\r\n")] + public async Task CreateCSharpFile_WritesUtf8WithoutBomAndKeepsGivenNewlines(string text) + { + var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); + Directory.CreateDirectory(root); + try + { + var service = new LspEditService(root, new LspFileLockProvider()); + + var result = await service.CreateCSharpFileAsync("Assets/Sample.cs", text, false, true, true, false); + + using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); + Assert.True(response.RootElement.GetProperty("applied").GetBoolean(), response.RootElement.ToString()); + Assert.Equal(Encoding.UTF8.GetBytes(text), await File.ReadAllBytesAsync(Path.Combine(root, "Assets", "Sample.cs"))); + } + finally + { + Directory.Delete(root, recursive: true); + } + } + + [Fact] + public async Task WriteCSharpFile_TreatsANewlineOnlyDifferenceAsNoChange() + { + var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); + Directory.CreateDirectory(Path.Combine(root, "Assets")); + var scriptPath = Path.Combine(root, "Assets", "Sample.cs"); + await File.WriteAllBytesAsync(scriptPath, Encode(Original, true, "\r\n")); + try + { + var service = new LspEditService(root, new LspFileLockProvider()); + + var result = await service.WriteCSharpFileAsync("Assets/Sample.cs", Original, true, true, false); + + using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); + Assert.Equal("no_change", response.RootElement.GetProperty("reason").GetString()); + Assert.Equal(Encode(Original, true, "\r\n"), await File.ReadAllBytesAsync(scriptPath)); + } + finally + { + Directory.Delete(root, recursive: true); + } + } + + [Theory] + [InlineData("a\r\nb\nc\n", "x\ny\n", "x\ny\n")] + [InlineData("single line", "x\r\ny\n", "x\r\ny\n")] + [InlineData("a\r\nb\r\n", "x\ny\r\nz\rw", "x\r\ny\r\nz\rw")] + [InlineData("a\nb\n", "x\r\ny\n", "x\ny\n")] + public void ApplyNewlines_OnlyRewritesWhenTheOriginalUsesOneConvention(string original, string text, string expected) + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes(original)); + + Assert.Equal(expected, format.ApplyNewlines(text)); + } + + private static byte[] Encode(string lfText, bool bom, string newline) + { + var body = Encoding.UTF8.GetBytes(lfText.Replace("\n", newline)); + return bom ? Encoding.UTF8.GetPreamble().Concat(body).ToArray() : body; + } +} From 923e25577b24183c976efa9d1925a1a16adbe91a Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 21:03:33 +0900 Subject: [PATCH 45/73] docs(lsp): report the three-OS reliability matrix and the enforcement verdict The report now carries every OS x start condition x scenario cell from CI run 38380911276 (three samples each, cold starts included), the run ID and capture time, the DO NOT ENFORCE verdict with its evidence, and the defect list (#498, #499, #500, #501, #504). The temporary three-sample cold setting for PR runs is reverted. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test.yml | 3 - docs/lsp-write-reliability.md | 182 ++++++++++++++++++++++++++++++---- 2 files changed, 163 insertions(+), 22 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 84f86926..d90ab2ec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,9 +13,6 @@ permissions: jobs: lsp-write-reliability: uses: ./.github/workflows/lsp-write-reliability.yml - # Temporary for the #490 report: several cold samples per cell. Revert to the default after. - with: - cold_repetitions: '3' cli-latency: name: CLI Latency (required) diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md index 2ced8102..b3c3a012 100644 --- a/docs/lsp-write-reliability.md +++ b/docs/lsp-write-reliability.md @@ -1,27 +1,87 @@ # C# LSP 書き込みの信頼性測定(#490) -直接編集を禁止できる根拠は、現時点では得られていません。BOM なしの -ファイルへの BOM 追加を Windows の実 CLI / 実 LSP で検出しています。 -全 OS の測定結果は `LSP Write Reliability` CI の JSON / Markdown artifact に -保存します。これは禁止を導入する変更ではなく、オーナー判断のための測定です。 +## 結論: 現時点では直接編集を禁止できない(DO NOT ENFORCE) -## 初期測定と修正が必要な不具合 +3 OS × 4 開始条件 × 19 シナリオの全セルを各 3 試行、計 684 試行測定しました。 +期待バイト列と一致したのは各 OS とも 228 試行中 24 試行(10.5%)です。 +目安(全シナリオ・全 OS で成功率 99% 以上、誤編集・エンコーディング/改行の破壊 0 件)を +どの OS・どの開始条件でも満たしていません。オーナーの最終判断のための測定であり、 +この PR は禁止を導入しません。 -2026-10-13 の Windows / checkout LSP / `warm_indexed` 初期測定は -19 シナリオを各 3 回、計 57 試行です。期待バイト列と一致したのは 6 試行 -(10.53%)。BOM あり CRLF の更新と検証のみが一致しました。 -全試行の LSP p50 は 260.755 ms、p95 は 293.267 ms です。 -これは厳密なバイト一致率であり、処理が実行された率や意味的に正しいコードの率ではありません。 +根拠は次のとおりです。 -| 不具合 | 実測 | 禁止前に必要な修正 | -| --- | --- | --- | -| [#498: BOM なしのファイルへ BOM を追加](https://github.com/akiojin/unity-cli/issues/498) | BOM なしの変更シナリオすべてで EF BB BF を追加 | 既存の BOM / 改行を保存し、新規ファイルの規約を定める | -| [#499: `replace_symbol_body` が末尾コメントを消す](https://github.com/akiojin/unity-cli/issues/499) | 日本語コメントと改行が 3/3 消失し、次のメンバーと連結 | 置換前 Body の末尾 trivia を保持する | -| [#500: `create_class` の ScriptableObject 作成が using を欠く](https://github.com/akiojin/unity-cli/issues/500) | `using UnityEngine` が 3/3 欠落 | 非修飾 ScriptableObject が名前解決できるテンプレートにする | +1. **BOM の付加(#498)**: BOM なしのファイルを扱う 17 シナリオすべてで、3 OS・4 条件・全試行に + UTF-8 BOM(EF BB BF)が付きました(各 OS 204 件)。直接編集では起きない差分が + ほぼ全ファイルに入ります。一致したのは BOM あり CRLF の更新と、ファイルを変更しない + 構文検証の 2 シナリオだけです。 +2. **コメントの消失(#499)**: `replace_symbol_body` が末尾コメントと改行を消し、次のメンバーと + 連結していました。checkout の LSP では #503 で修正済みで、`warm_indexed` / `unindexed` + では 3 OS とも再発していません。ただし利用者が実際に取得する公開版 LSP `0.18.1` + (`daemon_stopped` / `first_download`)では 3 OS とも 3/3 で再現します。 + 次のリリースまで、エージェントの実環境ではコードを壊す誤編集が残ります。 +3. **ScriptableObject の `using` 欠落(#500)**: #502 で修正済みです。この測定では + 全 OS・全条件で再発していません(残る差分は BOM のみ)。 +4. **コールド起動の遅さと失敗(#501 / #504)**: デーモン停止中の最初の呼び出しは + macOS / Linux で p50 約 3〜4 秒、Windows で p50 約 13 秒でした。先行の run + 38372615105 では Windows が約 43 秒でした。macOS のローカル実行では、自動起動の + 5 秒待ちを超えて編集が行われない試行が 1 件ありました(#501)。 -生応答とバイト差分は [Windows 初期測定の証跡](lsp-write-reliability-windows.json) に保存しています。 -製品修正は上記の個別不具合 Issue に登録済みです。 -3 OS / 全起動条件の結論は CI artifact の完成したマトリクスを参照してください。 +禁止を再検討できる条件は、#498 の修正と、#499 の修正を含む LSP の公開です。 +checkout の LSP を使う 2 条件では BOM 以外の失敗がないため、#498 を直せば全シナリオが一致する見込みです。 +その後に週次の多試行測定(各 20 試行、コールド各 5 試行)で 99% 以上を確認してください。 +少数試行での 100% は将来の 99% を保証しません。 + +## 測定データの出典 + +| 項目 | 値 | +| --- | --- | +| CI run | [38380911276](https://github.com/akiojin/unity-cli/actions/runs/38380911276)(`Test` workflow、PR #497) | +| 測定対象 | `b5a4059f`(develop の #502 / #503 を取り込み済み) | +| 取得日時 | 2026-10-13 10:05〜10:44 UTC(artifact 取得: 2026-10-13) | +| RID | `win-x64` / `osx-arm64` / `linux-x64`(GitHub-hosted `*-latest`) | +| 試行数 | 各セル 3 試行(コールド条件も 3 試行) | +| LSP | `warm_indexed` / `unindexed` は checkout、`daemon_stopped` / `first_download` は公開版 `0.18.1` | +| 回帰ゲート | 3 OS とも baseline 外の失敗 0 件 | + +CI artifact(`results.json` の生応答と diff)は保存期間 30 日で失われます。 +本文の表がこのレポートの一次資料です。Windows の初期測定の生データは +[lsp-write-reliability-windows.json](lsp-write-reliability-windows.json) に残しています。 + +## OS × 開始条件 + +一致率は期待バイト列と完全に一致した試行の割合です。処理が実行された率や、 +意味的に正しいコードの率ではありません。p50 / p95 は失敗を含む全試行の値です。 + +| OS | 開始条件 | 一致 / 試行 | 一致率 | LSP p50 / p95 ms | 直接編集 p50 / p95 ms | 失敗の種類(件数) | +| --- | --- | ---: | ---: | ---: | ---: | --- | +| Windows | `warm_indexed` | 6/57 | 10.5% | 273 / 297 | 0.50 / 1.23 | bom_added 51 | +| Windows | `daemon_stopped` | 6/57 | 10.5% | 12,929 / 13,338 | 0.56 / 1.27 | bom_added 51, text_changed 3 | +| Windows | `unindexed` | 6/57 | 10.5% | 512 / 560 | 0.62 / 1.21 | bom_added 51 | +| Windows | `first_download` | 6/57 | 10.5% | 13,453 / 14,443 | 0.55 / 1.32 | bom_added 51, text_changed 3 | +| Windows | **全条件** | 24/228 | 10.5% | 578 / 13,636 | 0.55 / 1.23 | bom_added 204, text_changed 6 | +| macOS | `warm_indexed` | 6/57 | 10.5% | 328 / 435 | 0.40 / 2.43 | bom_added 51 | +| macOS | `daemon_stopped` | 6/57 | 10.5% | 3,257 / 4,759 | 0.33 / 1.17 | bom_added 51, text_changed 3 | +| macOS | `unindexed` | 6/57 | 10.5% | 468 / 558 | 0.27 / 1.78 | bom_added 51 | +| macOS | `first_download` | 6/57 | 10.5% | 3,878 / 4,610 | 1.02 / 49.19 | bom_added 51, text_changed 3 | +| macOS | **全条件** | 24/228 | 10.5% | 569 / 4,231 | 0.37 / 19.87 | bom_added 204, text_changed 6 | +| Linux | `warm_indexed` | 6/57 | 10.5% | 242 / 259 | 0.07 / 0.10 | bom_added 51 | +| Linux | `daemon_stopped` | 6/57 | 10.5% | 3,631 / 3,778 | 0.06 / 0.10 | bom_added 51, text_changed 3 | +| Linux | `unindexed` | 6/57 | 10.5% | 354 / 391 | 0.06 / 0.09 | bom_added 51 | +| Linux | `first_download` | 6/57 | 10.5% | 4,045 / 4,281 | 0.07 / 0.11 | bom_added 51, text_changed 3 | +| Linux | **全条件** | 24/228 | 10.5% | 416 / 4,145 | 0.06 / 0.10 | bom_added 204, text_changed 6 | + +## 禁止前に直すべき不具合 + +| Issue | 状態 | 実測 | 代表的な差分 | +| --- | --- | --- | --- | +| [#498](https://github.com/akiojin/unity-cli/issues/498) BOM の付加 | 未修正 | 3 OS × 4 条件で BOM なしの 17 シナリオ全試行 | 先頭に `EF BB BF` が付く | +| [#499](https://github.com/akiojin/unity-cli/issues/499) 末尾コメントの消失 | checkout で修正済み、公開版 `0.18.1` は未修正 | コールド 2 条件 × 3 OS で 3/3 | `public int Run(){return 2;} // 日本語の説明を保持` → `public int Run(){return 2;}public int Next(){return 3;} }` | +| [#500](https://github.com/akiojin/unity-cli/issues/500) ScriptableObject の `using` 欠落 | 修正済み(#502) | 再発 0 件 | (修正前)`using UnityEngine;` が出力されない | +| [#501](https://github.com/akiojin/unity-cli/issues/501) lspd 自動起動の 5 秒タイムアウト | 未修正 | macOS ローカル 19 試行中 1 件 | `lspd failed to start within timeout`、編集なし | +| [#504](https://github.com/akiojin/unity-cli/issues/504) Windows のコールド起動 | 未修正 | Windows p50 約 13 秒(先行 run では約 43 秒) | 編集は成功するが待ち時間が長い | + +測定ハーネス自体の不具合(macOS の大文字小文字を区別しないファイルシステムで +`Server` を自身へコピーして失敗)は、この PR で修正済みです。製品の不具合とは分けて扱います。 ## 再現 @@ -96,7 +156,8 @@ PR / push は `Test` workflow から呼び出します。既存の必須 `LSP Tests (required)` は全 OS の測定完了を待ち、測定失敗時には明示的に失敗します。 依存 job の skip が成功扱いになる経路も `if: always()` と結果チェックで防ぎます。 デーモン停止・初回ダウンロードは PR / push で各シナリオ 1 試行、 -週次・手動の既定は各 5 試行を別枠で記録します。Windows の実測では +週次・手動の既定は各 5 試行を別枠で記録します。このレポートの数値は、 +コールド条件も各 3 試行とした PR の測定 run 1 回分です。Windows の実測では コールド起動が約 46 秒 / 試行のため、PR の全条件測定は約 35 分かかります。 週次・手動の多試行を完了できるよう測定 job の上限は 240 分です。 `--cold-repetitions` / `--download-repetitions` で増やせます。 @@ -113,6 +174,89 @@ Issue #499 のコメント喪失修正は checkout 条件で回帰を拒否し 再測定を絞る場合は `--scenarios create_plain` のように指定できます。絞った実行は 完全なマトリクスの代わりにならず、レポートの欠けたセル数に反映します。 +## 付録: シナリオ × 開始条件 × OS + +各セルは「期待バイト列と一致した試行 / 試行数」です。 + +| シナリオ | ツール | 開始条件 | Windows | macOS | Linux | 失敗の種類(3 OS 合計) | +| --- | --- | --- | ---: | ---: | ---: | --- | +| `create_class_monobehaviour` | `create_class` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_monobehaviour` | `create_class` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_monobehaviour` | `create_class` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_monobehaviour` | `create_class` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_scriptableobject` | `create_class` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_scriptableobject` | `create_class` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_scriptableobject` | `create_class` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_scriptableobject` | `create_class` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_plain` | `create_class` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_plain` | `create_class` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_plain` | `create_class` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_class_plain` | `create_class` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_plain` | `create_csharp_file` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_plain` | `create_csharp_file` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_plain` | `create_csharp_file` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_plain` | `create_csharp_file` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_monobehaviour` | `create_csharp_file` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_monobehaviour` | `create_csharp_file` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_monobehaviour` | `create_csharp_file` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_monobehaviour` | `create_csharp_file` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_scriptableobject` | `create_csharp_file` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_scriptableobject` | `create_csharp_file` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_scriptableobject` | `create_csharp_file` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `create_scriptableobject` | `create_csharp_file` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `replace_body` | `replace_symbol_body` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `replace_body` | `replace_symbol_body` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `replace_body` | `replace_symbol_body` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `replace_body` | `replace_symbol_body` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `write_file` | `write_csharp_file` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `write_file` | `write_csharp_file` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `write_file` | `write_csharp_file` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `write_file` | `write_csharp_file` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `insert_before` | `insert_before_symbol` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `insert_before` | `insert_before_symbol` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `insert_before` | `insert_before_symbol` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `insert_before` | `insert_before_symbol` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `insert_after` | `insert_after_symbol` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `insert_after` | `insert_after_symbol` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `insert_after` | `insert_after_symbol` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `insert_after` | `insert_after_symbol` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `remove_member` | `remove_symbol` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `remove_member` | `remove_symbol` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `remove_member` | `remove_symbol` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `remove_member` | `remove_symbol` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `namespace_partial_generic_attributes` | `replace_symbol_body` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `namespace_partial_generic_attributes` | `replace_symbol_body` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `namespace_partial_generic_attributes` | `replace_symbol_body` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `namespace_partial_generic_attributes` | `replace_symbol_body` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `replace_preserve_comment` | `replace_symbol_body` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `replace_preserve_comment` | `replace_symbol_body` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9, text_changed 9 | +| `replace_preserve_comment` | `replace_symbol_body` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `replace_preserve_comment` | `replace_symbol_body` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9, text_changed 9 | +| `rename_multifile` | `rename_symbol` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `rename_multifile` | `rename_symbol` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `rename_multifile` | `rename_symbol` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `rename_multifile` | `rename_symbol` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `unicode_no_bom_crlf` | `write_csharp_file` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `unicode_no_bom_crlf` | `write_csharp_file` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `unicode_no_bom_crlf` | `write_csharp_file` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `unicode_no_bom_crlf` | `write_csharp_file` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `unicode_bom_crlf` | `write_csharp_file` | `warm_indexed` | 3/3 | 3/3 | 3/3 | なし | +| `unicode_bom_crlf` | `write_csharp_file` | `daemon_stopped` | 3/3 | 3/3 | 3/3 | なし | +| `unicode_bom_crlf` | `write_csharp_file` | `unindexed` | 3/3 | 3/3 | 3/3 | なし | +| `unicode_bom_crlf` | `write_csharp_file` | `first_download` | 3/3 | 3/3 | 3/3 | なし | +| `large_3500_lines` | `write_csharp_file` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `large_3500_lines` | `write_csharp_file` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `large_3500_lines` | `write_csharp_file` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `large_3500_lines` | `write_csharp_file` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `repair_syntax_error` | `apply_csharp_edits` | `warm_indexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `repair_syntax_error` | `apply_csharp_edits` | `daemon_stopped` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `repair_syntax_error` | `apply_csharp_edits` | `unindexed` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `repair_syntax_error` | `apply_csharp_edits` | `first_download` | 0/3 | 0/3 | 0/3 | bom_added 9 | +| `validate_without_write` | `validate_text_edits` | `warm_indexed` | 3/3 | 3/3 | 3/3 | なし | +| `validate_without_write` | `validate_text_edits` | `daemon_stopped` | 3/3 | 3/3 | 3/3 | なし | +| `validate_without_write` | `validate_text_edits` | `unindexed` | 3/3 | 3/3 | 3/3 | なし | +| `validate_without_write` | `validate_text_edits` | `first_download` | 3/3 | 3/3 | 3/3 | なし | + Launch mode: autonomous User Verification Result: n/a (autonomous) From b8beff977e69570c038d6f3480379b744df30cfc Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 21:07:29 +0900 Subject: [PATCH 46/73] test(lsp): reject checkout BOM additions in the write reliability gate Drop bom_added from every checkout baseline entry now that LSP writes keep the original BOM. The published 0.18.1 defect stays as a version-pinned exception for the cold conditions that measure the released LSP. Refs #498 Co-Authored-By: Claude Opus 5.5 --- docs/lsp-write-reliability.md | 2 + tests/fixtures/lsp-write-baseline.json | 130 +++++++++++++++++++++---- 2 files changed, 115 insertions(+), 17 deletions(-) diff --git a/docs/lsp-write-reliability.md b/docs/lsp-write-reliability.md index 8ac233df..bcd26529 100644 --- a/docs/lsp-write-reliability.md +++ b/docs/lsp-write-reliability.md @@ -112,6 +112,8 @@ Issue #499 のコメント喪失修正は checkout 条件で回帰を拒否し コールド条件では、実測した公開版 `0.18.1` の既知のテキスト SHA256 だけを 許容します。VERSION 不明・checkout・後続の公開版にはこの例外を適用しません。 無関係のファイルへの BOM 追加も regression として拒否します。 +Issue #498 の BOM 修正後は checkout 条件の `bom_added` も regression として拒否します。 +公開版 `0.18.1` の `bom_added` は、各シナリオの `published` 例外でのみ許容します。 再測定を絞る場合は `--scenarios create_plain` のように指定できます。絞った実行は 完全なマトリクスの代わりにならず、レポートの欠けたセル数に反映します。 diff --git a/tests/fixtures/lsp-write-baseline.json b/tests/fixtures/lsp-write-baseline.json index 228d4a6c..0aca568d 100644 --- a/tests/fixtures/lsp-write-baseline.json +++ b/tests/fixtures/lsp-write-baseline.json @@ -1,18 +1,90 @@ { - "create_class_monobehaviour": ["bom_added"], - "create_class_scriptableobject": ["bom_added"], - "create_class_plain": ["bom_added"], - "create_plain": ["bom_added"], - "create_monobehaviour": ["bom_added"], - "create_scriptableobject": ["bom_added"], - "replace_body": ["bom_added"], - "write_file": ["bom_added"], - "insert_before": ["bom_added"], - "insert_after": ["bom_added"], - "remove_member": ["bom_added"], - "namespace_partial_generic_attributes": ["bom_added"], + "create_class_monobehaviour": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "create_class_scriptableobject": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "create_class_plain": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "create_plain": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "create_monobehaviour": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "create_scriptableobject": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "replace_body": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "write_file": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "insert_before": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "insert_after": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "remove_member": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "namespace_partial_generic_attributes": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, "replace_preserve_comment": { - "failures": ["bom_added"], + "failures": [], "published": { "versions": ["0.18.1"], "failures": ["bom_added", "text_changed"], @@ -21,8 +93,32 @@ } } }, - "rename_multifile": ["bom_added"], - "unicode_no_bom_crlf": ["bom_added"], - "large_3500_lines": ["bom_added"], - "repair_syntax_error": ["bom_added"] + "rename_multifile": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "unicode_no_bom_crlf": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "large_3500_lines": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + }, + "repair_syntax_error": { + "failures": [], + "published": { + "versions": ["0.18.1"], + "failures": ["bom_added"] + } + } } From 6edbdb6a667debdac3a45461e0679690cf9113c5 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 21:17:46 +0900 Subject: [PATCH 47/73] fix(test): wait for lspd shutdown before deleting a reliability trial `lspd stop` only requests shutdown, and auto-started trials have no child process to wait for, so `cleanup_trial` could race the daemon's exit writes under tools/ and abort with ENOTEMPTY (macOS errno 66). The trial now waits for the daemon to remove its PID file, and cleanup retries ENOTEMPTY within the same bounded window as Windows DLL locks. Fixes #509 Co-Authored-By: Claude Opus 5.5 --- scripts/lsp-write-reliability.py | 12 ++++++-- tests/scripts/test_lsp_write_reliability.py | 34 +++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/scripts/lsp-write-reliability.py b/scripts/lsp-write-reliability.py index 85893f54..e0e43e86 100644 --- a/scripts/lsp-write-reliability.py +++ b/scripts/lsp-write-reliability.py @@ -8,6 +8,7 @@ from collections import Counter from datetime import datetime, timezone import difflib +import errno import hashlib import json import math @@ -217,9 +218,10 @@ def cleanup_trial(directory, root): try: shutil.rmtree(directory) return - except PermissionError: - # Windows can keep clrjit.dll locked briefly after lspd exits. - if time.monotonic() >= deadline: + except OSError as error: + # Windows can keep clrjit.dll locked briefly after lspd exits, and a + # stopping lspd can still add files while rmtree walks the tree. + if not (isinstance(error, PermissionError) or error.errno == errno.ENOTEMPTY) or time.monotonic() >= deadline: raise time.sleep(0.1) @@ -306,6 +308,10 @@ def close(self): subprocess.run(self.command(["lspd", "stop"]), env=self.env, capture_output=True, timeout=15) except subprocess.TimeoutExpired: pass + # `lspd stop` only requests shutdown; the daemon removes its PID file on exit. + deadline = time.monotonic() + 10 + while pid_file.exists() and time.monotonic() < deadline: + time.sleep(0.1) if self.process is not None: try: self.process.wait(timeout=10) diff --git a/tests/scripts/test_lsp_write_reliability.py b/tests/scripts/test_lsp_write_reliability.py index fdc45eb4..a2e41f8d 100644 --- a/tests/scripts/test_lsp_write_reliability.py +++ b/tests/scripts/test_lsp_write_reliability.py @@ -1,5 +1,6 @@ """Protect the reliability measurement from false PASS and hidden regressions.""" import importlib.util +import tempfile from pathlib import Path import unittest from unittest import mock @@ -154,6 +155,39 @@ def test_trial_cleanup_retries_windows_dll_locks_and_rejects_escape(self): reliability.cleanup_trial(ROOT, ROOT / ".cache") remove.assert_not_called() + def test_trial_cleanup_retries_when_lspd_writes_during_removal(self): + busy = OSError(reliability.errno.ENOTEMPTY, "Directory not empty", "tools") + with mock.patch.object(reliability.shutil, "rmtree", side_effect=[busy, busy, None]) as remove: + with mock.patch.object(reliability.time, "sleep"): + reliability.cleanup_trial(ROOT / ".cache/trial", ROOT / ".cache") + self.assertEqual(remove.call_count, 3) + broken = OSError(reliability.errno.EIO, "I/O error") + with mock.patch.object(reliability.shutil, "rmtree", side_effect=broken) as remove: + with self.assertRaises(OSError): + reliability.cleanup_trial(ROOT / ".cache/trial", ROOT / ".cache") + self.assertEqual(remove.call_count, 1) + + def test_close_waits_for_the_auto_started_lspd_to_remove_its_pid_file(self): + with tempfile.TemporaryDirectory() as directory: + trial = reliability.Trial.__new__(reliability.Trial) + trial.tools, trial.process, trial.log, trial.env = Path(directory), None, None, {} + trial.cli, trial.project = Path("unity-cli"), Path(directory) + pid_file = trial.tools / "run" / "lspd" / "lspd.pid" + pid_file.parent.mkdir(parents=True) + pid_file.write_text("4242") + polls = [] + + def sleep(_): + polls.append(1) + if len(polls) == 3: + pid_file.unlink() # The daemon finishes its shutdown writes. + + with mock.patch.object(reliability.subprocess, "run") as run, mock.patch.object(reliability.time, "sleep", side_effect=sleep): + trial.close() + self.assertIn("stop", run.call_args.args[0]) + self.assertEqual(len(polls), 3) + self.assertFalse(pid_file.exists()) + if __name__ == "__main__": unittest.main() From 0236e7566c94d6e39e812ddd7bacaef06da471f0 Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 22:36:00 +0900 Subject: [PATCH 48/73] fix(lsp): resolve canonical file URIs across Windows and Unix --- .github/workflows/test.yml | 15 +++++ ...b2cea761ec44d14099efd65ba15f50e4ead0.jsonl | 1 + ...3a9f5244d88575597a049f0c682111478415.jsonl | 1 + ...6277384ca9d18f70c54372b8107558f11696.jsonl | 1 + ...cf72e8f7ef5afa1abf76c504de71f16d2741.jsonl | 1 + ...6a5f393ed3b321c6779953fe15a7466921f8.jsonl | 1 + Cargo.lock | 1 + Cargo.toml | 1 + lsp/PathUtilitiesTests.cs | 39 ++++++++++++ lsp/RequestRouterTests.cs | 15 ++++- lsp/Server.Core/LspPathUtilities.cs | 37 ++++++++++- lsp/Server.Core/LspRequestRouter.cs | 11 +--- src/lsp/client.rs | 62 ++++++++++++++++--- 13 files changed, 165 insertions(+), 21 deletions(-) create mode 100644 .gwt/work/events/4c/4ce33f50346a3954a42153f2d493b2cea761ec44d14099efd65ba15f50e4ead0.jsonl create mode 100644 .gwt/work/events/a1/a1adfecc1aebb92b2a0e9800b7d73a9f5244d88575597a049f0c682111478415.jsonl create mode 100644 .gwt/work/events/c7/c7d35bd1295c92ec473b7da5492d6277384ca9d18f70c54372b8107558f11696.jsonl create mode 100644 .gwt/work/events/ec/ec83444727761f4cc622d5b16bf1cf72e8f7ef5afa1abf76c504de71f16d2741.jsonl create mode 100644 .gwt/work/events/f0/f0e1940255e9fb0fd98a452397926a5f393ed3b321c6779953fe15a7466921f8.jsonl diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d90ab2ec..b423ba96 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -230,6 +230,21 @@ jobs: - name: Test hot reload validation and execution observations run: dotnet test tests/hot-reload/HotReload.Tests.csproj + windows-lsp-test: + name: Windows LSP Tests + runs-on: windows-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v7 + + - name: Setup .NET SDK 10 + uses: actions/setup-dotnet@v6 + with: + dotnet-version: '10.0.x' + + - name: Run dotnet test + run: dotnet test lsp/Server.Tests.csproj + rust-coverage: name: Rust Coverage >= 90% (required) runs-on: ubuntu-latest diff --git a/.gwt/work/events/4c/4ce33f50346a3954a42153f2d493b2cea761ec44d14099efd65ba15f50e4ead0.jsonl b/.gwt/work/events/4c/4ce33f50346a3954a42153f2d493b2cea761ec44d14099efd65ba15f50e4ead0.jsonl new file mode 100644 index 00000000..e50ee245 --- /dev/null +++ b/.gwt/work/events/4c/4ce33f50346a3954a42153f2d493b2cea761ec44d14099efd65ba15f50e4ead0.jsonl @@ -0,0 +1 @@ +{"id":"372bc20d-c4b2-43ac-9d14-eab74dfd1226","work_item_id":"work-work-issue-511-ac1c61e3","kind":"update","title":"Issue #511 の受入条件を満たす","intent":"既存実装と受入条件の監査","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #511","next_action":null,"agent_session_id":"d0aa10d9-7f81-4304-905c-47fc4ce7b80c","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-511","worktree_path":"E:\\unity-cli\\work\\issue-511","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T13:01:10.833188100Z"} diff --git a/.gwt/work/events/a1/a1adfecc1aebb92b2a0e9800b7d73a9f5244d88575597a049f0c682111478415.jsonl b/.gwt/work/events/a1/a1adfecc1aebb92b2a0e9800b7d73a9f5244d88575597a049f0c682111478415.jsonl new file mode 100644 index 00000000..32e75162 --- /dev/null +++ b/.gwt/work/events/a1/a1adfecc1aebb92b2a0e9800b7d73a9f5244d88575597a049f0c682111478415.jsonl @@ -0,0 +1 @@ +{"id":"4037547a-a33f-465b-ac18-142147abf076","work_item_id":"work-work-issue-511-ac1c61e3","kind":"done","title":"Windows LSP の file URI 解決","intent":"検証済み変更の配送と CI 自動マージ","summary":null,"progress_summary":"#511 全 AC の変更前監査で未達を確認。C#/Rust の正規 file URI 双方向変換、特殊文字/UNC 往復、Assets 検索と URI 再利用、独立 Windows CI を実装。canonical verify 10/10 PASS、Rust627件、Windows/Linux C#各111件、coverage99.66%、実Windows CLI/LSP3操作 PASS。","status_category":"done","owner":"Issue #511","next_action":"commit/push → fresh verify → Ready PR → CI/自動マージ確認 → AC同期とIssue close","agent_session_id":"d0aa10d9-7f81-4304-905c-47fc4ce7b80c","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-511","worktree_path":"E:\\unity-cli\\work\\issue-511","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T13:35:57.324265100Z"} diff --git a/.gwt/work/events/c7/c7d35bd1295c92ec473b7da5492d6277384ca9d18f70c54372b8107558f11696.jsonl b/.gwt/work/events/c7/c7d35bd1295c92ec473b7da5492d6277384ca9d18f70c54372b8107558f11696.jsonl new file mode 100644 index 00000000..4003f4b5 --- /dev/null +++ b/.gwt/work/events/c7/c7d35bd1295c92ec473b7da5492d6277384ca9d18f70c54372b8107558f11696.jsonl @@ -0,0 +1 @@ +{"id":"8b2f177c-b10e-49ac-8a63-3f8a30ff4f0a","work_item_id":"work-work-issue-511-ac1c61e3","kind":"start","title":"fix(lsp): resolve Windows file URIs so symbol search finds Assets files on Windows","intent":"Check Board for latest updates","summary":"Codex is running","progress_summary":null,"status_category":"active","owner":"Issue #511","next_action":"Check Board for latest updates","agent_session_id":"d0aa10d9-7f81-4304-905c-47fc4ce7b80c","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-511","worktree_path":"E:\\unity-cli\\work\\issue-511","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T12:59:55.693971100Z"} diff --git a/.gwt/work/events/ec/ec83444727761f4cc622d5b16bf1cf72e8f7ef5afa1abf76c504de71f16d2741.jsonl b/.gwt/work/events/ec/ec83444727761f4cc622d5b16bf1cf72e8f7ef5afa1abf76c504de71f16d2741.jsonl new file mode 100644 index 00000000..48b7c0e3 --- /dev/null +++ b/.gwt/work/events/ec/ec83444727761f4cc622d5b16bf1cf72e8f7ef5afa1abf76c504de71f16d2741.jsonl @@ -0,0 +1 @@ +{"id":"40b4ea96-0c98-4512-a610-813fe95da3d5","work_item_id":"work-work-issue-511-ac1c61e3","kind":"update","title":null,"intent":"Rust / C# 間の正規 URI 相互運用","summary":null,"progress_summary":"C# Windows/Linux 108/108、coverage 99.66%、workflow 検査 PASS。実クライアント境界に同じ未エンコード/未デコードを発見し RED を確認。","status_category":null,"owner":"Issue #511","next_action":null,"agent_session_id":"d0aa10d9-7f81-4304-905c-47fc4ce7b80c","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-511","worktree_path":"E:\\unity-cli\\work\\issue-511","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T13:14:17.156690900Z"} diff --git a/.gwt/work/events/f0/f0e1940255e9fb0fd98a452397926a5f393ed3b321c6779953fe15a7466921f8.jsonl b/.gwt/work/events/f0/f0e1940255e9fb0fd98a452397926a5f393ed3b321c6779953fe15a7466921f8.jsonl new file mode 100644 index 00000000..5dfccce7 --- /dev/null +++ b/.gwt/work/events/f0/f0e1940255e9fb0fd98a452397926a5f393ed3b321c6779953fe15a7466921f8.jsonl @@ -0,0 +1 @@ +{"id":"fc57b9d5-1a72-4b71-af87-2c9399fb8f95","work_item_id":"work-work-issue-511-ac1c61e3","kind":"update","title":"Windows LSP の file URI 解決","intent":"Windows / Linux の往復と全件検証","summary":null,"progress_summary":"全 AC の変更前監査と RED を確認。共通 URI 変換、エンコード付き検索、Windows CI を実装。","status_category":null,"owner":"Issue #511","next_action":null,"agent_session_id":"d0aa10d9-7f81-4304-905c-47fc4ce7b80c","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-511","worktree_path":"E:\\unity-cli\\work\\issue-511","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T13:06:44.886302Z"} diff --git a/Cargo.lock b/Cargo.lock index 2bf3af70..5e995432 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2690,6 +2690,7 @@ dependencies = [ "tracing", "tracing-subscriber", "ureq", + "url", "walkdir", "zip", ] diff --git a/Cargo.toml b/Cargo.toml index 1fc73bf7..a1d01cce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ regex = "1.12" walkdir = "2.5" sha2 = "0.11" ureq = { version = "3.3", features = ["json"] } +url = "2.5" serde_yml = "0.0.13" similar = "3" tempfile = "3.27" diff --git a/lsp/PathUtilitiesTests.cs b/lsp/PathUtilitiesTests.cs index 23fcb635..826500ab 100644 --- a/lsp/PathUtilitiesTests.cs +++ b/lsp/PathUtilitiesTests.cs @@ -50,4 +50,43 @@ public void Path2Uri_UsesFilePrefix() { Assert.Equal("file:///repo/Assets/Scripts/Player.cs", LspPathUtilities.Path2Uri("/repo/Assets/Scripts/Player.cs")); } + + [Theory] + [InlineData(@"C:\repo\Assets\Player.cs", "file:///C:/repo/Assets/Player.cs")] + [InlineData("C:/repo/Assets/Player.cs", "file:///C:/repo/Assets/Player.cs")] + [InlineData(@"\\server\share\Assets\Player.cs", "file://server/share/Assets/Player.cs")] + [InlineData(@"C:\my project\Assets\日本語 #%.cs", "file:///C:/my%20project/Assets/%E6%97%A5%E6%9C%AC%E8%AA%9E%20%23%25.cs")] + [InlineData("/my project/Assets/日本語 #%.cs", "file:///my%20project/Assets/%E6%97%A5%E6%9C%AC%E8%AA%9E%20%23%25.cs")] + [InlineData(@"\\server\my share\Assets\A #%.cs", "file://server/my%20share/Assets/A%20%23%25.cs")] + public void Path2Uri_ProducesCanonicalEscapedFileUris(string path, string expected) + { + Assert.Equal(expected, LspPathUtilities.Path2Uri(path)); + } + + [Theory] + [InlineData(@"C:\repo\Assets\Player.cs", "file:///C:/repo/Assets/Player.cs")] + [InlineData(@"d:\my project\Assets\日本語 #%.cs", "file:///d:/my%20project/Assets/%E6%97%A5%E6%9C%AC%E8%AA%9E%20%23%25.cs")] + [InlineData("/repo/Assets/Player.cs", "file:///repo/Assets/Player.cs")] + [InlineData("/my project/Assets/日本語 #%.cs", "file:///my%20project/Assets/%E6%97%A5%E6%9C%AC%E8%AA%9E%20%23%25.cs")] + [InlineData(@"\\server\share\Assets\Player.cs", "file://server/share/Assets/Player.cs")] + [InlineData(@"\\server\my share\Assets\A #%.cs", "file://server/my%20share/Assets/A%20%23%25.cs")] + [InlineData("/repo/Assets/A %20.cs", "file:///repo/Assets/A%20%2520.cs")] + [InlineData(@"C:\repo\Assets\A %20.cs", "file:///C:/repo/Assets/A%20%2520.cs")] + [InlineData(@"C:\repo\Assets\日本語 # %20.cs", "file:///C:/repo/Assets/%E6%97%A5%E6%9C%AC%E8%AA%9E%20%23%20%2520.cs")] + [InlineData("/repo/Assets/日本語 # %20.cs", "file:///repo/Assets/%E6%97%A5%E6%9C%AC%E8%AA%9E%20%23%20%2520.cs")] + [InlineData(@"\\server\share\Assets\日本語 # %20.cs", "file://server/share/Assets/%E6%97%A5%E6%9C%AC%E8%AA%9E%20%23%20%2520.cs")] + [InlineData("/repo/Assets/A?.cs", "file:///repo/Assets/A%3F.cs")] + public void FileUris_RoundTripPathsAndUris(string path, string uri) + { + Assert.Equal(path, LspPathUtilities.Uri2Path(uri)); + Assert.Equal(path, LspPathUtilities.Uri2Path(LspPathUtilities.Path2Uri(path))); + Assert.Equal(uri, LspPathUtilities.Path2Uri(LspPathUtilities.Uri2Path(uri))); + } + + [Fact] + public void FileUriConversions_RejectNonFileUris() + { + Assert.Throws(() => LspPathUtilities.Uri2Path("https://example.com/Asset.cs")); + Assert.Throws(() => LspPathUtilities.Path2Uri("https://example.com/Asset.cs")); + } } diff --git a/lsp/RequestRouterTests.cs b/lsp/RequestRouterTests.cs index 39ff6adc..0d65a909 100644 --- a/lsp/RequestRouterTests.cs +++ b/lsp/RequestRouterTests.cs @@ -10,7 +10,7 @@ public sealed class RequestRouterTests [InlineData("unitycli/referencesByName", "name")] public async Task SymbolQueries_RespectAssetsScopeBeforeScanningPackages(string method, string key) { - var root = Path.Combine(Path.GetTempPath(), "lsp-scope-" + Path.GetRandomFileName()); + var root = Path.Combine(Path.GetTempPath(), "lsp scope 日本語 #%-" + Path.GetRandomFileName()); Directory.CreateDirectory(Path.Combine(root, "Assets")); Directory.CreateDirectory(Path.Combine(root, "Packages")); File.WriteAllText(Path.Combine(root, "Assets", "Asset.cs"), "class ScopeProbe {}"); @@ -31,6 +31,19 @@ public async Task SymbolQueries_RespectAssetsScopeBeforeScanningPackages(string var json = JsonSerializer.Serialize(response.Payload); Assert.Contains("Asset.cs", json); Assert.DoesNotContain("Package.cs", json); + if (method == "workspace/symbol") + { + using var payload = JsonDocument.Parse(json); + var symbol = Assert.Single(payload.RootElement.GetProperty("result").EnumerateArray()); + var uri = symbol.GetProperty("location").GetProperty("uri").GetString(); + Assert.Equal(new System.Uri(Path.Combine(root, "Assets", "Asset.cs")).AbsoluteUri, uri); + using var documentRequest = JsonDocument.Parse(JsonSerializer.Serialize(new { + id = 3, method = "textDocument/documentSymbol", + @params = new { textDocument = new { uri } } + })); + var documentResponse = await router.HandleAsync(documentRequest.RootElement); + Assert.Contains("ScopeProbe", JsonSerializer.Serialize(documentResponse.Payload)); + } } finally { Directory.Delete(root, recursive: true); } } diff --git a/lsp/Server.Core/LspPathUtilities.cs b/lsp/Server.Core/LspPathUtilities.cs index 13484265..e77a0ce4 100644 --- a/lsp/Server.Core/LspPathUtilities.cs +++ b/lsp/Server.Core/LspPathUtilities.cs @@ -7,8 +7,41 @@ public static class LspPathUtilities public static string NormalizeRelative(string relative) => (relative ?? string.Empty).Replace('\\', '/'); - public static string Path2Uri(string path) => - "file://" + path.Replace('\\', '/'); + public static string Path2Uri(string path) + { + var normalized = path.Replace('\\', '/'); + // Escape raw path segments before parsing so literal % sequences survive. + if (normalized.Length >= 3 && char.IsAsciiLetter(normalized[0]) + && normalized[1] == ':' && normalized[2] == '/') + { + return FileUri("file:///" + normalized[..2] + EscapePath(normalized[2..])).AbsoluteUri; + } + + if (!normalized.StartsWith("/", StringComparison.Ordinal)) + { + throw new ArgumentException("Expected an absolute file path.", nameof(path)); + } + + var prefix = normalized.StartsWith("//", StringComparison.Ordinal) ? "file:" : "file://"; + return FileUri(prefix + EscapePath(normalized)).AbsoluteUri; + } + + private static string EscapePath(string path) => + string.Join('/', path.Split('/').Select(Uri.EscapeDataString)); + + public static string Uri2Path(string uri) => + FileUri(uri).LocalPath; + + private static Uri FileUri(string value) + { + var uri = new Uri(value, UriKind.Absolute); + if (!uri.IsFile) + { + throw new ArgumentException("Expected an absolute file path or file URI.", nameof(value)); + } + + return uri; + } public static string ToRel(string fullPath, string root) { diff --git a/lsp/Server.Core/LspRequestRouter.cs b/lsp/Server.Core/LspRequestRouter.cs index 03017845..b1854752 100644 --- a/lsp/Server.Core/LspRequestRouter.cs +++ b/lsp/Server.Core/LspRequestRouter.cs @@ -264,15 +264,8 @@ private static LspRouterResult Response(JsonElement id, object? result) => _ => null }; - private static string Uri2Path(string uri) - { - if (uri.StartsWith("file://", StringComparison.Ordinal)) - { - uri = uri.Substring("file://".Length); - } - - return uri.Replace('/', Path.DirectorySeparatorChar); - } + private static string Uri2Path(string uri) => + LspPathUtilities.Uri2Path(uri); private static string Path2Uri(string path) => LspPathUtilities.Path2Uri(path); diff --git a/src/lsp/client.rs b/src/lsp/client.rs index 6df6a91e..b1d9aeb5 100644 --- a/src/lsp/client.rs +++ b/src/lsp/client.rs @@ -374,7 +374,7 @@ fn handle_get_symbols( return Err(anyhow!("File not found: {rel}")); } - let uri = file_uri(&abs); + let uri = file_uri(&abs)?; let response = session.request( "textDocument/documentSymbol", json!({ @@ -1231,8 +1231,10 @@ fn normalize_rel_path(raw: &str) -> Option { Some(parts.join("/")) } -fn file_uri(path: &Path) -> String { - format!("file://{}", path.to_string_lossy().replace('\\', "/")) +fn file_uri(path: &Path) -> Result { + url::Url::from_file_path(path) + .map(|uri| uri.to_string()) + .map_err(|()| anyhow!("LSP file paths must be absolute")) } fn uri_to_rel_path(project_root: &Path, uri: &str) -> Option { @@ -1240,8 +1242,7 @@ fn uri_to_rel_path(project_root: &Path, uri: &str) -> Option { return None; } - let raw = uri.trim_start_matches("file://").replace('\\', "/"); - let path = PathBuf::from(raw); + let path = url::Url::parse(uri).ok()?.to_file_path().ok()?; let rel = path .strip_prefix(project_root) .ok() @@ -1369,7 +1370,7 @@ impl LspSession { "method": "initialize", "params": { "processId": std::process::id(), - "rootUri": file_uri(project_root), + "rootUri": file_uri(project_root)?, "capabilities": {} } }))?; @@ -1806,7 +1807,7 @@ while True: let rel = "Assets/Scripts/Player.cs"; let abs = root.path().join(rel); - let uri = file_uri(&abs); + let uri = file_uri(&abs).expect("file URI should convert"); assert_eq!(uri_to_rel_path(root.path(), &uri).as_deref(), Some(rel)); assert_eq!( ref_path(root.path(), &json!({ "path": uri })).as_deref(), @@ -1824,6 +1825,43 @@ while True: assert!(uri_to_rel_path(root.path(), "https://example.com/file.cs").is_none()); } + #[test] + fn canonical_file_uris_preserve_encoded_paths_and_assets_scope() { + let root = tempfile::Builder::new() + .prefix("lsp URI 日本語 #%-") + .tempdir() + .expect("tempdir should succeed"); + let rel = "Assets/Scripts/日本語 # %20.cs"; + let abs = root.path().join(rel); + let uri = url::Url::from_file_path(&abs) + .expect("absolute file path should convert") + .to_string(); + + assert_eq!(uri_to_rel_path(root.path(), &uri).as_deref(), Some(rel)); + assert_eq!(file_uri(&abs).expect("file URI should convert"), uri); + assert!(path_matches_scope( + &uri_to_rel_path(root.path(), &uri).expect("file URI should resolve"), + "assets" + )); + } + + #[cfg(windows)] + #[test] + fn canonical_windows_drive_and_unc_uris_resolve_assets_paths() { + for (root, uri) in [ + (r"C:\repo", "file:///C:/repo/Assets/Player.cs"), + ( + r"\\server\share\repo", + "file://server/share/repo/Assets/Player.cs", + ), + ] { + assert_eq!( + uri_to_rel_path(std::path::Path::new(root), uri).as_deref(), + Some("Assets/Player.cs") + ); + } + } + #[test] fn to_project_relative_or_raw_returns_relative_for_absolute_under_root() { let root = tempdir().expect("tempdir should succeed"); @@ -2001,7 +2039,10 @@ while True: .to_str() .expect("tools root path should be valid UTF-8"), ); - let _uri = EnvVarGuard::set("FAKE_LSP_PLAYER_URI", &file_uri(&player_path)); + let _uri = EnvVarGuard::set( + "FAKE_LSP_PLAYER_URI", + &file_uri(&player_path).expect("file URI should convert"), + ); let _out = EnvVarGuard::set( "FAKE_LSP_OUTPUT_PATH", project_dir @@ -2081,7 +2122,10 @@ while True: .to_str() .expect("tools root path should be valid UTF-8"), ); - let _uri = EnvVarGuard::set("FAKE_LSP_PLAYER_URI", &file_uri(&player_path)); + let _uri = EnvVarGuard::set( + "FAKE_LSP_PLAYER_URI", + &file_uri(&player_path).expect("file URI should convert"), + ); let _out = EnvVarGuard::set( "FAKE_LSP_OUTPUT_PATH", project_dir From 514c56338a53d638e0efecfbcb2b3a5c04994457 Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 22:42:05 +0900 Subject: [PATCH 49/73] chore(work): record pull request for issue 511 --- ...65d8ab67ed443ed887af899da13af957950a01b8fa70a7ec102f24a.jsonl | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gwt/work/events/5a/5a65e9f1c65d8ab67ed443ed887af899da13af957950a01b8fa70a7ec102f24a.jsonl diff --git a/.gwt/work/events/5a/5a65e9f1c65d8ab67ed443ed887af899da13af957950a01b8fa70a7ec102f24a.jsonl b/.gwt/work/events/5a/5a65e9f1c65d8ab67ed443ed887af899da13af957950a01b8fa70a7ec102f24a.jsonl new file mode 100644 index 00000000..12f2cbac --- /dev/null +++ b/.gwt/work/events/5a/5a65e9f1c65d8ab67ed443ed887af899da13af957950a01b8fa70a7ec102f24a.jsonl @@ -0,0 +1 @@ +{"id":"42e4468c-2e15-49eb-8708-373b0bd7ac3e","work_item_id":"work-work-issue-511-ac1c61e3","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"done","owner":null,"next_action":null,"agent_session_id":"d0aa10d9-7f81-4304-905c-47fc4ce7b80c","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-511","worktree_path":"E:\\unity-cli\\work\\issue-511","pr_number":512,"pr_url":"https://github.com/akiojin/unity-cli/pull/512","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T13:41:06.595205700Z"} From 63f0e7d86dca1a88cbba5d8456c75fdb3a882493 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 22:52:46 +0900 Subject: [PATCH 50/73] fix(lsp): keep UTF-32 BE BOMs and CR-only newlines when saving C# files The format detector missed the UTF-32 BE BOM (00 00 FE FF), so such files were rewritten as UTF-8 without a BOM, and it ignored lone CR line breaks, so CR-only files lost their newline convention. Extend the byte-exact edit tests to every recognised BOM and LF / CRLF / CR. Refs #498 Co-Authored-By: Claude Opus 5.5 --- lsp/Server.Core/LspSourceFile.cs | 17 +++++++---- lsp/SourceFileFormatTests.cs | 48 +++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 5520f563..849caff8 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -30,6 +30,8 @@ public string ApplyNewlines(string text) { if (NewLine is null) return text; var lf = text.Replace("\r\n", "\n"); + // A CR-only file folds stray CRs too; LF and CRLF files leave a lone CR as content. + if (NewLine == "\r") return lf.Replace("\n", "\r"); return NewLine == "\n" ? lf : lf.Replace("\n", NewLine); } @@ -38,21 +40,24 @@ private static Encoding DetectEncoding(byte[] b) if (b.Length >= 3 && b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF) return new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); if (b.Length >= 4 && b[0] == 0xFF && b[1] == 0xFE && b[2] == 0 && b[3] == 0) return new UTF32Encoding(bigEndian: false, byteOrderMark: true); if (b.Length >= 2 && b[0] == 0xFF && b[1] == 0xFE) return new UnicodeEncoding(bigEndian: false, byteOrderMark: true); + if (b.Length >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0xFE && b[3] == 0xFF) return new UTF32Encoding(bigEndian: true, byteOrderMark: true); if (b.Length >= 2 && b[0] == 0xFE && b[1] == 0xFF) return new UnicodeEncoding(bigEndian: true, byteOrderMark: true); return Utf8NoBom; } private static string? DetectNewLine(string text) { - int crlf = 0, lf = 0; + int crlf = 0, lf = 0, cr = 0; for (var i = 0; i < text.Length; i++) { - if (text[i] != '\n') continue; - if (i > 0 && text[i - 1] == '\r') crlf++; - else lf++; + if (text[i] == '\n') lf++; + else if (text[i] != '\r') continue; + else if (i + 1 < text.Length && text[i + 1] == '\n') { crlf++; i++; } + else cr++; } - if (crlf > 0 && lf == 0) return "\r\n"; - if (lf > 0 && crlf == 0) return "\n"; + if (crlf > 0 && lf == 0 && cr == 0) return "\r\n"; + if (lf > 0 && crlf == 0 && cr == 0) return "\n"; + if (cr > 0 && crlf == 0 && lf == 0) return "\r"; return null; } } diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 91cc028a..55fa05f2 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -11,26 +11,29 @@ public sealed class SourceFileFormatTests { private const string Original = "public class Sample\n{\n public int Run() { return 1; }\n}\n"; - public static TheoryData ExistingFileEdits() + // Every BOM the reader recognises, plus UTF-8 without one. + private static readonly string[] Encodings = { "utf-8", "utf-8-bom", "utf-16le", "utf-16be", "utf-32le", "utf-32be" }; + + public static TheoryData ExistingFileEdits() { - var data = new TheoryData(); + var data = new TheoryData(); foreach (var operation in new[] { "write", "apply", "replace_body", "insert_before", "insert_after", "remove", "rename" }) - foreach (var bom in new[] { false, true }) - foreach (var newline in new[] { "\n", "\r\n" }) + foreach (var encoding in Encodings) + foreach (var newline in new[] { "\n", "\r\n", "\r" }) { - data.Add(operation, bom, newline); + data.Add(operation, encoding, newline); } return data; } [Theory] [MemberData(nameof(ExistingFileEdits))] - public async Task ExistingFileEdits_KeepTheOriginalBomAndNewlines(string operation, bool bom, string newline) + public async Task ExistingFileEdits_KeepTheOriginalBomAndNewlines(string operation, string encoding, string newline) { var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); Directory.CreateDirectory(Path.Combine(root, "Assets")); var scriptPath = Path.Combine(root, "Assets", "Sample.cs"); - await File.WriteAllBytesAsync(scriptPath, Encode(Original, bom, newline)); + await File.WriteAllBytesAsync(scriptPath, Encode(Original, encoding, newline)); try { var service = new LspEditService(root, new LspFileLockProvider()); @@ -55,7 +58,7 @@ public async Task ExistingFileEdits_KeepTheOriginalBomAndNewlines(string operati using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); Assert.True(response.RootElement.GetProperty("applied").GetBoolean(), response.RootElement.ToString()); - Assert.Equal(Encode(expected, bom, newline), await File.ReadAllBytesAsync(scriptPath)); + Assert.Equal(Encode(expected, encoding, newline), await File.ReadAllBytesAsync(scriptPath)); } finally { @@ -70,8 +73,8 @@ public async Task RenameAcrossFiles_KeepsEachFileFormat() Directory.CreateDirectory(Path.Combine(root, "Assets")); const string declaration = "namespace Demo\n{\n public partial class Sample {}\n}\n"; const string use = "namespace Demo\n{\n public class Consumer { public Sample Value; }\n}\n"; - await File.WriteAllBytesAsync(Path.Combine(root, "Assets", "Sample.cs"), Encode(declaration, true, "\r\n")); - await File.WriteAllBytesAsync(Path.Combine(root, "Assets", "Use.cs"), Encode(use, false, "\n")); + await File.WriteAllBytesAsync(Path.Combine(root, "Assets", "Sample.cs"), Encode(declaration, "utf-8-bom", "\r\n")); + await File.WriteAllBytesAsync(Path.Combine(root, "Assets", "Use.cs"), Encode(use, "utf-8", "\n")); try { var service = new LspEditService(root, new LspFileLockProvider()); @@ -80,9 +83,9 @@ public async Task RenameAcrossFiles_KeepsEachFileFormat() using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); Assert.True(response.RootElement.GetProperty("applied").GetBoolean(), response.RootElement.ToString()); - Assert.Equal(Encode(declaration.Replace("Sample", "Renamed"), true, "\r\n"), + Assert.Equal(Encode(declaration.Replace("Sample", "Renamed"), "utf-8-bom", "\r\n"), await File.ReadAllBytesAsync(Path.Combine(root, "Assets", "Sample.cs"))); - Assert.Equal(Encode(use.Replace("Sample", "Renamed"), false, "\n"), + Assert.Equal(Encode(use.Replace("Sample", "Renamed"), "utf-8", "\n"), await File.ReadAllBytesAsync(Path.Combine(root, "Assets", "Use.cs"))); } finally @@ -120,7 +123,7 @@ public async Task WriteCSharpFile_TreatsANewlineOnlyDifferenceAsNoChange() var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); Directory.CreateDirectory(Path.Combine(root, "Assets")); var scriptPath = Path.Combine(root, "Assets", "Sample.cs"); - await File.WriteAllBytesAsync(scriptPath, Encode(Original, true, "\r\n")); + await File.WriteAllBytesAsync(scriptPath, Encode(Original, "utf-8-bom", "\r\n")); try { var service = new LspEditService(root, new LspFileLockProvider()); @@ -129,7 +132,7 @@ public async Task WriteCSharpFile_TreatsANewlineOnlyDifferenceAsNoChange() using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); Assert.Equal("no_change", response.RootElement.GetProperty("reason").GetString()); - Assert.Equal(Encode(Original, true, "\r\n"), await File.ReadAllBytesAsync(scriptPath)); + Assert.Equal(Encode(Original, "utf-8-bom", "\r\n"), await File.ReadAllBytesAsync(scriptPath)); } finally { @@ -142,6 +145,8 @@ public async Task WriteCSharpFile_TreatsANewlineOnlyDifferenceAsNoChange() [InlineData("single line", "x\r\ny\n", "x\r\ny\n")] [InlineData("a\r\nb\r\n", "x\ny\r\nz\rw", "x\r\ny\r\nz\rw")] [InlineData("a\nb\n", "x\r\ny\n", "x\ny\n")] + [InlineData("a\rb\r", "x\ny\r\nz\rw", "x\ry\rz\rw")] + [InlineData("a\rb\nc\r", "x\ny\n", "x\ny\n")] public void ApplyNewlines_OnlyRewritesWhenTheOriginalUsesOneConvention(string original, string text, string expected) { var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes(original)); @@ -149,9 +154,18 @@ public void ApplyNewlines_OnlyRewritesWhenTheOriginalUsesOneConvention(string or Assert.Equal(expected, format.ApplyNewlines(text)); } - private static byte[] Encode(string lfText, bool bom, string newline) + private static byte[] Encode(string lfText, string encoding, string newline) { - var body = Encoding.UTF8.GetBytes(lfText.Replace("\n", newline)); - return bom ? Encoding.UTF8.GetPreamble().Concat(body).ToArray() : body; + Encoding target = encoding switch + { + "utf-8" => new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), + "utf-8-bom" => new UTF8Encoding(encoderShouldEmitUTF8Identifier: true), + "utf-16le" => new UnicodeEncoding(bigEndian: false, byteOrderMark: true), + "utf-16be" => new UnicodeEncoding(bigEndian: true, byteOrderMark: true), + "utf-32le" => new UTF32Encoding(bigEndian: false, byteOrderMark: true), + "utf-32be" => new UTF32Encoding(bigEndian: true, byteOrderMark: true), + _ => throw new ArgumentOutOfRangeException(nameof(encoding), encoding, null), + }; + return target.GetPreamble().Concat(target.GetBytes(lfText.Replace("\n", newline))).ToArray(); } } From 97e760a2b84501e35fb370308c148738500fdaa2 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 23:06:11 +0900 Subject: [PATCH 51/73] chore(work): record work events for #498 Co-Authored-By: Claude Opus 5.5 --- ...32dc1447867bfa2d72a9da813868c6e5e7fc9291fbbc760e9dd24bd.jsonl | 1 + ...278faa950cf84eba19aa3697b6fe974cc3d063e567d035940bd197f.jsonl | 1 + ...e5b55af68841d8bf4737cb00806f6c33292c757fa1d37f5b92aaf91.jsonl | 1 + ...ceeacb1ab14f22b5b21777b62d1dedac999bb68c0f74b168176e0d8.jsonl | 1 + ...0b7f6985d9297f51aa92c388a79025f34063639c0607dffafd19fc6.jsonl | 1 + ...1f6767bd775b77e39984e58182bfbec209257e7181b4bc5888c3230.jsonl | 1 + ...76717162859737bc36a4b305017cbf6c4002112f651fcc2959754d1.jsonl | 1 + ...ea0622ffdbd14c0b666c9bd77b80207a30c56b03281050561808547.jsonl | 1 + ...a33f9af77112a6a65f739f7ed25afc9fee373d21f6bfb4f401ee735.jsonl | 1 + ...f200f95e5d73531596dc75b4a0cdb07727819bbb636dcd50911dd4b.jsonl | 1 + ...464e9214fe1e65994a7a8ef2101ff34d97e461542aadb981fe1ab4e.jsonl | 1 + ...47a5515cb101314be0ec192b7fc1b63f92e82466f433bdfe9305837.jsonl | 1 + 12 files changed, 12 insertions(+) create mode 100644 .gwt/work/events/1a/1adf5461732dc1447867bfa2d72a9da813868c6e5e7fc9291fbbc760e9dd24bd.jsonl create mode 100644 .gwt/work/events/1d/1dcc0e96f278faa950cf84eba19aa3697b6fe974cc3d063e567d035940bd197f.jsonl create mode 100644 .gwt/work/events/30/30d165d1ee5b55af68841d8bf4737cb00806f6c33292c757fa1d37f5b92aaf91.jsonl create mode 100644 .gwt/work/events/7c/7c14f5a78ceeacb1ab14f22b5b21777b62d1dedac999bb68c0f74b168176e0d8.jsonl create mode 100644 .gwt/work/events/7f/7fe1378430b7f6985d9297f51aa92c388a79025f34063639c0607dffafd19fc6.jsonl create mode 100644 .gwt/work/events/82/82e8442c61f6767bd775b77e39984e58182bfbec209257e7181b4bc5888c3230.jsonl create mode 100644 .gwt/work/events/ad/ad4ba11da76717162859737bc36a4b305017cbf6c4002112f651fcc2959754d1.jsonl create mode 100644 .gwt/work/events/c3/c375b7253ea0622ffdbd14c0b666c9bd77b80207a30c56b03281050561808547.jsonl create mode 100644 .gwt/work/events/e9/e9e18901ca33f9af77112a6a65f739f7ed25afc9fee373d21f6bfb4f401ee735.jsonl create mode 100644 .gwt/work/events/f1/f14878cd3f200f95e5d73531596dc75b4a0cdb07727819bbb636dcd50911dd4b.jsonl create mode 100644 .gwt/work/events/f8/f820fbe3d464e9214fe1e65994a7a8ef2101ff34d97e461542aadb981fe1ab4e.jsonl create mode 100644 .gwt/work/events/f8/f86f2649a47a5515cb101314be0ec192b7fc1b63f92e82466f433bdfe9305837.jsonl diff --git a/.gwt/work/events/1a/1adf5461732dc1447867bfa2d72a9da813868c6e5e7fc9291fbbc760e9dd24bd.jsonl b/.gwt/work/events/1a/1adf5461732dc1447867bfa2d72a9da813868c6e5e7fc9291fbbc760e9dd24bd.jsonl new file mode 100644 index 00000000..3d3af2f0 --- /dev/null +++ b/.gwt/work/events/1a/1adf5461732dc1447867bfa2d72a9da813868c6e5e7fc9291fbbc760e9dd24bd.jsonl @@ -0,0 +1 @@ +{"id":"bac7b601-c210-4aa7-833c-4381836db4d3","work_item_id":"work-work-issue-498-892fdd8e","kind":"start","title":"fix(lsp): keep the original BOM and newlines when C# LSP write tools save a file","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #498","next_action":"Check Board for latest updates","agent_session_id":"59a2fa97-8e6a-4559-996b-52a6865f473b","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T09:40:12.350761Z"} diff --git a/.gwt/work/events/1d/1dcc0e96f278faa950cf84eba19aa3697b6fe974cc3d063e567d035940bd197f.jsonl b/.gwt/work/events/1d/1dcc0e96f278faa950cf84eba19aa3697b6fe974cc3d063e567d035940bd197f.jsonl new file mode 100644 index 00000000..1d89fb75 --- /dev/null +++ b/.gwt/work/events/1d/1dcc0e96f278faa950cf84eba19aa3697b6fe974cc3d063e567d035940bd197f.jsonl @@ -0,0 +1 @@ +{"id":"cddd4c76-3dfc-419e-a102-e14015afbeeb","work_item_id":"work-work-issue-498-892fdd8e","kind":"update","title":null,"intent":"PR #507 の auto-merge と verify.run 完了待ち","summary":"run 38397430741 の再実行で Rust Format & Lint が success。PR #507 は auto-merge 待ち、verify.run は lease 待ち","progress_summary":null,"status_category":null,"owner":"Issue #498","next_action":null,"agent_session_id":"59a2fa97-8e6a-4559-996b-52a6865f473b","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":507,"pr_url":"https://github.com/akiojin/unity-cli/pull/507","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T12:30:55.796785Z"} diff --git a/.gwt/work/events/30/30d165d1ee5b55af68841d8bf4737cb00806f6c33292c757fa1d37f5b92aaf91.jsonl b/.gwt/work/events/30/30d165d1ee5b55af68841d8bf4737cb00806f6c33292c757fa1d37f5b92aaf91.jsonl new file mode 100644 index 00000000..985d6d7f --- /dev/null +++ b/.gwt/work/events/30/30d165d1ee5b55af68841d8bf4737cb00806f6c33292c757fa1d37f5b92aaf91.jsonl @@ -0,0 +1 @@ +{"id":"d51c72ea-58d6-4eaf-a2b0-44cfb22b3158","work_item_id":"work-work-issue-498-892fdd8e","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"active","owner":null,"next_action":null,"agent_session_id":"28641b50-7397-40b7-98fc-192f96e72d4a","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":513,"pr_url":"https://github.com/akiojin/unity-cli/pull/513","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T14:04:50.925733Z"} diff --git a/.gwt/work/events/7c/7c14f5a78ceeacb1ab14f22b5b21777b62d1dedac999bb68c0f74b168176e0d8.jsonl b/.gwt/work/events/7c/7c14f5a78ceeacb1ab14f22b5b21777b62d1dedac999bb68c0f74b168176e0d8.jsonl new file mode 100644 index 00000000..7ca015b8 --- /dev/null +++ b/.gwt/work/events/7c/7c14f5a78ceeacb1ab14f22b5b21777b62d1dedac999bb68c0f74b168176e0d8.jsonl @@ -0,0 +1 @@ +{"id":"5f6f6b8d-2451-463c-b149-a49898690982","work_item_id":"work-work-issue-498-892fdd8e","kind":"update","title":null,"intent":"#497 ハーネスで BOM なし baseline のローカル検証中","summary":null,"progress_summary":"LspSourceFile ヘルパで既存ファイルの BOM/エンコーディング/改行規約を保持、新規は BOM なし UTF-8。LSP テスト 92 件 PASS。docs/tools.md に規約追記。","status_category":null,"owner":"Issue #498","next_action":null,"agent_session_id":"59a2fa97-8e6a-4559-996b-52a6865f473b","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T10:03:15.040663Z"} diff --git a/.gwt/work/events/7f/7fe1378430b7f6985d9297f51aa92c388a79025f34063639c0607dffafd19fc6.jsonl b/.gwt/work/events/7f/7fe1378430b7f6985d9297f51aa92c388a79025f34063639c0607dffafd19fc6.jsonl new file mode 100644 index 00000000..34c4f2cc --- /dev/null +++ b/.gwt/work/events/7f/7fe1378430b7f6985d9297f51aa92c388a79025f34063639c0607dffafd19fc6.jsonl @@ -0,0 +1 @@ +{"id":"72c033d0-b9f8-4366-87a7-ee049fb0c941","work_item_id":"work-work-issue-498-892fdd8e","kind":"update","title":null,"intent":"PR #507 の auto-merge 待機","summary":"PR #507 は CI green、PM が Ready 化済み。auto-merge 待ち","progress_summary":null,"status_category":null,"owner":"Issue #498","next_action":null,"agent_session_id":"59a2fa97-8e6a-4559-996b-52a6865f473b","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":507,"pr_url":"https://github.com/akiojin/unity-cli/pull/507","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T12:26:08.290578Z"} diff --git a/.gwt/work/events/82/82e8442c61f6767bd775b77e39984e58182bfbec209257e7181b4bc5888c3230.jsonl b/.gwt/work/events/82/82e8442c61f6767bd775b77e39984e58182bfbec209257e7181b4bc5888c3230.jsonl new file mode 100644 index 00000000..02665fa0 --- /dev/null +++ b/.gwt/work/events/82/82e8442c61f6767bd775b77e39984e58182bfbec209257e7181b4bc5888c3230.jsonl @@ -0,0 +1 @@ +{"id":"3fa5c1b6-d3ba-47e5-b2f8-6b2dd8ccfc9a","work_item_id":"work-work-issue-498-892fdd8e","kind":"update","title":null,"intent":"PR #507 CI 確認","summary":"PR #507 の CI(LSP Write Reliability 3 OS)待ち","progress_summary":"LspSourceFile ヘルパで既存ファイルの BOM/エンコーディング/改行規約を保持し、新規ファイルは BOM なし UTF-8(AC-1/AC-2)。LSP テスト 92 件 PASS。develop(#497 含む)に追従し、baseline の checkout failures から bom_added を全削除(published 0.18.1 の例外は残す)。ローカルハーネス warm_indexed 19/19 PASS。PR #507 を Draft で作成・更新し push 済み。","status_category":null,"owner":"Issue #498","next_action":null,"agent_session_id":"59a2fa97-8e6a-4559-996b-52a6865f473b","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":507,"pr_url":"https://github.com/akiojin/unity-cli/pull/507","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T12:07:50.340283Z"} diff --git a/.gwt/work/events/ad/ad4ba11da76717162859737bc36a4b305017cbf6c4002112f651fcc2959754d1.jsonl b/.gwt/work/events/ad/ad4ba11da76717162859737bc36a4b305017cbf6c4002112f651fcc2959754d1.jsonl new file mode 100644 index 00000000..1619d5b5 --- /dev/null +++ b/.gwt/work/events/ad/ad4ba11da76717162859737bc36a4b305017cbf6c4002112f651fcc2959754d1.jsonl @@ -0,0 +1 @@ +{"id":"7545127f-79bd-457e-910d-d616caa0ac1e","work_item_id":"work-work-issue-498-892fdd8e","kind":"done","title":null,"intent":"PR #513 の CI 待ち(PM が Ready にする)","summary":null,"progress_summary":"AC-1 の残件(UTF-32 BE BOM と CR 単独改行)を実装し、Draft PR #513 を作成。dotnet test 192 件 pass、fmt と clippy も pass。Issue にコメント済み。","status_category":"done","owner":"Issue #498","next_action":null,"agent_session_id":"28641b50-7397-40b7-98fc-192f96e72d4a","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":513,"pr_url":"https://github.com/akiojin/unity-cli/pull/513","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T14:05:57.542827Z"} diff --git a/.gwt/work/events/c3/c375b7253ea0622ffdbd14c0b666c9bd77b80207a30c56b03281050561808547.jsonl b/.gwt/work/events/c3/c375b7253ea0622ffdbd14c0b666c9bd77b80207a30c56b03281050561808547.jsonl new file mode 100644 index 00000000..10a0b89e --- /dev/null +++ b/.gwt/work/events/c3/c375b7253ea0622ffdbd14c0b666c9bd77b80207a30c56b03281050561808547.jsonl @@ -0,0 +1 @@ +{"id":"a3fac5c7-e020-4dc7-8818-b85ea11e087d","work_item_id":"work-work-issue-498-892fdd8e","kind":"resume","title":"fix(lsp): keep the original BOM and newlines when C# LSP write tools save a file","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #498","next_action":"Check Board for latest updates","agent_session_id":"28641b50-7397-40b7-98fc-192f96e72d4a","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T13:38:52.132622Z"} diff --git a/.gwt/work/events/e9/e9e18901ca33f9af77112a6a65f739f7ed25afc9fee373d21f6bfb4f401ee735.jsonl b/.gwt/work/events/e9/e9e18901ca33f9af77112a6a65f739f7ed25afc9fee373d21f6bfb4f401ee735.jsonl new file mode 100644 index 00000000..e8e6390d --- /dev/null +++ b/.gwt/work/events/e9/e9e18901ca33f9af77112a6a65f739f7ed25afc9fee373d21f6bfb4f401ee735.jsonl @@ -0,0 +1 @@ +{"id":"e5c04312-d6a0-439f-8c11-3a1fef7fbfa9","work_item_id":"work-work-issue-498-892fdd8e","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"active","owner":null,"next_action":null,"agent_session_id":"59a2fa97-8e6a-4559-996b-52a6865f473b","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":507,"pr_url":"https://github.com/akiojin/unity-cli/pull/507","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T12:05:09.340813Z"} diff --git a/.gwt/work/events/f1/f14878cd3f200f95e5d73531596dc75b4a0cdb07727819bbb636dcd50911dd4b.jsonl b/.gwt/work/events/f1/f14878cd3f200f95e5d73531596dc75b4a0cdb07727819bbb636dcd50911dd4b.jsonl new file mode 100644 index 00000000..9d71ba3a --- /dev/null +++ b/.gwt/work/events/f1/f14878cd3f200f95e5d73531596dc75b4a0cdb07727819bbb636dcd50911dd4b.jsonl @@ -0,0 +1 @@ +{"id":"665fab9d-8bc2-4b2c-b1d2-b8a0be55a4ae","work_item_id":"work-work-issue-498-892fdd8e","kind":"resume","title":"fix(lsp): keep the original BOM and newlines when C# LSP write tools save a file","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #498","next_action":"Check Board for latest updates","agent_session_id":"e1d54ec9-5124-4889-9240-91f209dd091b","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T13:04:35.586129Z"} diff --git a/.gwt/work/events/f8/f820fbe3d464e9214fe1e65994a7a8ef2101ff34d97e461542aadb981fe1ab4e.jsonl b/.gwt/work/events/f8/f820fbe3d464e9214fe1e65994a7a8ef2101ff34d97e461542aadb981fe1ab4e.jsonl new file mode 100644 index 00000000..e39fa0a9 --- /dev/null +++ b/.gwt/work/events/f8/f820fbe3d464e9214fe1e65994a7a8ef2101ff34d97e461542aadb981fe1ab4e.jsonl @@ -0,0 +1 @@ +{"id":"d46b3b1b-f8e0-4083-9865-97f14d1a347c","work_item_id":"work-work-issue-498-892fdd8e","kind":"resume","title":"fix(lsp): keep the original BOM and newlines when C# LSP write tools save a file","intent":"Check Board for latest updates","summary":"2 active agents","progress_summary":null,"status_category":"active","owner":"Issue #498","next_action":"Check Board for latest updates","agent_session_id":"09f6982f-e4aa-44e9-84f3-338e44faa7ff","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-13T12:05:35.433882Z"} diff --git a/.gwt/work/events/f8/f86f2649a47a5515cb101314be0ec192b7fc1b63f92e82466f433bdfe9305837.jsonl b/.gwt/work/events/f8/f86f2649a47a5515cb101314be0ec192b7fc1b63f92e82466f433bdfe9305837.jsonl new file mode 100644 index 00000000..b2a84903 --- /dev/null +++ b/.gwt/work/events/f8/f86f2649a47a5515cb101314be0ec192b7fc1b63f92e82466f433bdfe9305837.jsonl @@ -0,0 +1 @@ +{"id":"c40ccc57-c6f8-4afa-bb79-a07deec714ee","work_item_id":"work-work-issue-498-892fdd8e","kind":"update","title":"C# LSP 書き込み時の BOM/改行保持","intent":"PR #513 の CI 待ち","summary":null,"progress_summary":"#498 の AC-1 で残っていた UTF-32 BE BOM と CR 単独改行の保持を修正。42 件の RED を確認後、dotnet test は 192 件すべて pass。fmt と clippy も pass。Draft PR #513 を develop 向けに作成。","status_category":null,"owner":"Issue #498","next_action":null,"agent_session_id":"28641b50-7397-40b7-98fc-192f96e72d4a","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":513,"pr_url":"https://github.com/akiojin/unity-cli/pull/513","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-13T14:04:57.936134Z"} From 68a3672e4618f6345bc172e8a9d25c6af784a0af Mon Sep 17 00:00:00 2001 From: akiojin Date: Tue, 13 Oct 2026 23:08:21 +0900 Subject: [PATCH 52/73] fix(lsp): negotiate file URI encoding with older servers --- lsp/RequestRouterTests.cs | 1 + lsp/Server.Core/LspRequestRouter.cs | 2 +- src/lsp/client.rs | 92 +++++++++++++++++++++-------- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/lsp/RequestRouterTests.cs b/lsp/RequestRouterTests.cs index 0d65a909..2067176b 100644 --- a/lsp/RequestRouterTests.cs +++ b/lsp/RequestRouterTests.cs @@ -61,6 +61,7 @@ public async Task HandleAsync_Ping_ReturnsJsonRpcResponsePayload() Assert.False(result.ShouldExit); Assert.Contains("\"id\":7", json); Assert.Contains("\"ok\":true", json); + Assert.Contains("\"fileUriEncoding\":true", json); } [Fact] diff --git a/lsp/Server.Core/LspRequestRouter.cs b/lsp/Server.Core/LspRequestRouter.cs index b1854752..7ac87279 100644 --- a/lsp/Server.Core/LspRequestRouter.cs +++ b/lsp/Server.Core/LspRequestRouter.cs @@ -124,7 +124,7 @@ public async Task HandleAsync(JsonElement root) if (method == "unitycli/ping") { - return Response(id, new { ok = true }); + return Response(id, new { ok = true, fileUriEncoding = true }); } if (method == "unitycli/referencesByName") diff --git a/src/lsp/client.rs b/src/lsp/client.rs index b1d9aeb5..9b34ced1 100644 --- a/src/lsp/client.rs +++ b/src/lsp/client.rs @@ -374,7 +374,7 @@ fn handle_get_symbols( return Err(anyhow!("File not found: {rel}")); } - let uri = file_uri(&abs)?; + let uri = file_uri(&abs, session.file_uri_encoding)?; let response = session.request( "textDocument/documentSymbol", json!({ @@ -455,7 +455,7 @@ fn handle_find_symbol( Some(value) => value, None => continue, }; - let rel_path = match uri_to_rel_path(project_root, uri) { + let rel_path = match uri_to_rel_path(project_root, uri, session.file_uri_encoding) { Some(value) => value, None => continue, }; @@ -542,8 +542,8 @@ fn handle_find_refs( let mut refs = response.as_array().cloned().unwrap_or_default(); refs.sort_by(|a, b| { - let a_path = ref_path(project_root, a).unwrap_or_default(); - let b_path = ref_path(project_root, b).unwrap_or_default(); + let a_path = ref_path(project_root, a, session.file_uri_encoding).unwrap_or_default(); + let b_path = ref_path(project_root, b, session.file_uri_encoding).unwrap_or_default(); let a_line = a.get("line").and_then(Value::as_u64).unwrap_or(0); let b_line = b.get("line").and_then(Value::as_u64).unwrap_or(0); let a_col = a.get("column").and_then(Value::as_u64).unwrap_or(0); @@ -561,7 +561,7 @@ fn handle_find_refs( let mut last_path: Option = None; for item in refs { - let Some(path) = ref_path(project_root, &item) else { + let Some(path) = ref_path(project_root, &item, session.file_uri_encoding) else { continue; }; @@ -1231,18 +1231,29 @@ fn normalize_rel_path(raw: &str) -> Option { Some(parts.join("/")) } -fn file_uri(path: &Path) -> Result { +fn file_uri(path: &Path, encoded: bool) -> Result { + if !encoded { + return Ok(format!( + "file://{}", + path.to_string_lossy().replace('\\', "/") + )); + } + url::Url::from_file_path(path) .map(|uri| uri.to_string()) .map_err(|()| anyhow!("LSP file paths must be absolute")) } -fn uri_to_rel_path(project_root: &Path, uri: &str) -> Option { +fn uri_to_rel_path(project_root: &Path, uri: &str, encoded: bool) -> Option { if !uri.starts_with("file://") { return None; } - let path = url::Url::parse(uri).ok()?.to_file_path().ok()?; + let path = if encoded { + url::Url::parse(uri).ok()?.to_file_path().ok()? + } else { + PathBuf::from(uri.trim_start_matches("file://").replace('\\', "/")) + }; let rel = path .strip_prefix(project_root) .ok() @@ -1252,10 +1263,10 @@ fn uri_to_rel_path(project_root: &Path, uri: &str) -> Option { normalize_rel_path(&rel) } -fn ref_path(project_root: &Path, item: &Value) -> Option { +fn ref_path(project_root: &Path, item: &Value, encoded: bool) -> Option { let path = item.get("path").and_then(Value::as_str)?; if path.starts_with("file://") { - return uri_to_rel_path(project_root, path); + return uri_to_rel_path(project_root, path, encoded); } normalize_rel_path(path) } @@ -1313,6 +1324,7 @@ struct LspSession { rx: Receiver, next_id: u64, timeout: Duration, + file_uri_encoding: bool, } impl LspSession { @@ -1356,8 +1368,13 @@ impl LspSession { rx, next_id: 1, timeout: lsp_timeout(), + file_uri_encoding: false, }; + // Older published servers treat file URIs as unescaped path strings. + let ping = session.request("unitycli/ping", json!({}))?; + session.file_uri_encoding = + ping.get("fileUriEncoding").and_then(Value::as_bool) == Some(true); session.initialize(project_root)?; Ok(session) } @@ -1370,7 +1387,7 @@ impl LspSession { "method": "initialize", "params": { "processId": std::process::id(), - "rootUri": file_uri(project_root)?, + "rootUri": file_uri(project_root, self.file_uri_encoding)?, "capabilities": {} } }))?; @@ -1669,7 +1686,9 @@ while True: method = message.get("method") message_id = message.get("id") - if method == "initialize": + if method == "unitycli/ping": + send_message({"jsonrpc": "2.0", "id": message_id, "result": {"ok": True, "fileUriEncoding": True}}) + elif method == "initialize": send_message({"jsonrpc": "2.0", "id": message_id, "result": {"capabilities": {"documentSymbolProvider": True}}}) elif method == "initialized": continue @@ -1807,14 +1826,17 @@ while True: let rel = "Assets/Scripts/Player.cs"; let abs = root.path().join(rel); - let uri = file_uri(&abs).expect("file URI should convert"); - assert_eq!(uri_to_rel_path(root.path(), &uri).as_deref(), Some(rel)); + let uri = file_uri(&abs, true).expect("file URI should convert"); + assert_eq!( + uri_to_rel_path(root.path(), &uri, true).as_deref(), + Some(rel) + ); assert_eq!( - ref_path(root.path(), &json!({ "path": uri })).as_deref(), + ref_path(root.path(), &json!({ "path": uri }), true).as_deref(), Some(rel) ); assert_eq!( - ref_path(root.path(), &json!({ "path": rel })).as_deref(), + ref_path(root.path(), &json!({ "path": rel }), true).as_deref(), Some(rel) ); } @@ -1822,7 +1844,7 @@ while True: #[test] fn uri_to_rel_path_rejects_non_file_uris() { let root = tempdir().expect("tempdir should succeed"); - assert!(uri_to_rel_path(root.path(), "https://example.com/file.cs").is_none()); + assert!(uri_to_rel_path(root.path(), "https://example.com/file.cs", true).is_none()); } #[test] @@ -1837,10 +1859,13 @@ while True: .expect("absolute file path should convert") .to_string(); - assert_eq!(uri_to_rel_path(root.path(), &uri).as_deref(), Some(rel)); - assert_eq!(file_uri(&abs).expect("file URI should convert"), uri); + assert_eq!( + uri_to_rel_path(root.path(), &uri, true).as_deref(), + Some(rel) + ); + assert_eq!(file_uri(&abs, true).expect("file URI should convert"), uri); assert!(path_matches_scope( - &uri_to_rel_path(root.path(), &uri).expect("file URI should resolve"), + &uri_to_rel_path(root.path(), &uri, true).expect("file URI should resolve"), "assets" )); } @@ -1856,12 +1881,33 @@ while True: ), ] { assert_eq!( - uri_to_rel_path(std::path::Path::new(root), uri).as_deref(), + uri_to_rel_path(std::path::Path::new(root), uri, true).as_deref(), Some("Assets/Player.cs") ); } } + #[test] + fn legacy_file_uris_preserve_raw_paths_for_older_servers() { + let root = tempfile::Builder::new() + .prefix("legacy URI 日本語 #%-") + .tempdir() + .expect("tempdir should succeed"); + let rel = "Assets/日本語 # %20.cs"; + let path = root.path().join(rel); + let uri = file_uri(&path, false).expect("legacy file URI should convert"); + + assert!(uri.ends_with(rel)); + assert_eq!( + uri_to_rel_path(root.path(), &uri, false).as_deref(), + Some(rel) + ); + assert_eq!( + ref_path(root.path(), &json!({ "path": uri }), false).as_deref(), + Some(rel) + ); + } + #[test] fn to_project_relative_or_raw_returns_relative_for_absolute_under_root() { let root = tempdir().expect("tempdir should succeed"); @@ -2041,7 +2087,7 @@ while True: ); let _uri = EnvVarGuard::set( "FAKE_LSP_PLAYER_URI", - &file_uri(&player_path).expect("file URI should convert"), + &file_uri(&player_path, true).expect("file URI should convert"), ); let _out = EnvVarGuard::set( "FAKE_LSP_OUTPUT_PATH", @@ -2124,7 +2170,7 @@ while True: ); let _uri = EnvVarGuard::set( "FAKE_LSP_PLAYER_URI", - &file_uri(&player_path).expect("file URI should convert"), + &file_uri(&player_path, true).expect("file URI should convert"), ); let _out = EnvVarGuard::set( "FAKE_LSP_OUTPUT_PATH", From bcf7f3ac201ba8bfb59b24e96d02faca624152b5 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 23:13:28 +0900 Subject: [PATCH 53/73] chore(work): record work events for #498 Co-Authored-By: Claude Opus 5.5 --- ...db2966e8db6bb98fbfe022696fd8cbd096903acb885d88316a61e7b.jsonl | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gwt/work/events/fe/fe3e27ca8db2966e8db6bb98fbfe022696fd8cbd096903acb885d88316a61e7b.jsonl diff --git a/.gwt/work/events/fe/fe3e27ca8db2966e8db6bb98fbfe022696fd8cbd096903acb885d88316a61e7b.jsonl b/.gwt/work/events/fe/fe3e27ca8db2966e8db6bb98fbfe022696fd8cbd096903acb885d88316a61e7b.jsonl new file mode 100644 index 00000000..e2e58c59 --- /dev/null +++ b/.gwt/work/events/fe/fe3e27ca8db2966e8db6bb98fbfe022696fd8cbd096903acb885d88316a61e7b.jsonl @@ -0,0 +1 @@ +{"id":"4263ce85-9cce-4caa-9b2d-efacaf1916c2","work_item_id":"work-successor-3057df15a3a56389941d9d6badd9f07a06f89ea077e09b2b3f2f0e79a596ef6d","kind":"start","title":"fix(lsp): keep the original BOM and newlines when C# LSP write tools save a file","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #498","next_action":"Check Board for latest updates","agent_session_id":"f8a5d838-ed43-4759-8676-8ac572fdfb4c","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-498","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-498","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":"work-work-issue-498-892fdd8e","updated_at":"2026-10-13T14:09:24.085409Z"} From 02783f0a9b0c87f70dd7dc90d36987fede585fe2 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Tue, 13 Oct 2026 23:28:59 +0900 Subject: [PATCH 54/73] fix(install): retry transient download errors and wait for the test release server The Windows Installer Checksum Test failed with "failed to download SHA256SUMS or manifest" because install-ps1-test.ps1 slept a fixed 2 s before using its local python release server; the failed runs show no request reaching the server. The test now takes a free port from the OS and waits until the server answers. install.ps1 and install.sh now retry transient failures (no response, 408, 429, 5xx) with backoff, keep 404 as the manifest fallback, and abort with the real cause instead of reporting a network failure as a missing SHA256SUMS. The checksum gate is unchanged. Closes #514 Co-Authored-By: Claude Opus 5.5 --- scripts/install.ps1 | 57 +++++++++-- scripts/install.sh | 23 ++++- tests/install_script.rs | 123 ++++++++++++++++++++++++ tests/scripts/install-ps1-test.ps1 | 26 ++++- tests/scripts/install-ps1-text-test.ps1 | 69 ++++++++++++- 5 files changed, 278 insertions(+), 20 deletions(-) diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 22658f3d..7de07394 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -5,7 +5,8 @@ # auto-update maintains (%USERPROFILE%\.unity\tools\unity-cli\), and that # directory is added to the user PATH. The download is verified against the # release SHA256SUMS (or the release manifest for older releases); any -# mismatch aborts the install before the existing binary is touched. +# mismatch aborts the install before the existing binary is touched. Transient +# network errors (no response, 408, 429, 5xx) are retried with backoff. # # Environment: # UNITY_CLI_VERSION install a specific tag instead of the latest @@ -30,18 +31,50 @@ function Get-Rid { } } +function Get-HttpStatus($ErrorRecord) { + $response = $ErrorRecord.Exception.Response + if ($response -and $response.StatusCode) { return [int]$response.StatusCode } + return $null +} + +# No HTTP response (DNS, refused, reset, timeout), 408, 429 and 5xx are worth +# another attempt; any other status is a definitive answer. +function Test-TransientError($ErrorRecord) { + $status = Get-HttpStatus $ErrorRecord + return ($null -eq $status -or $status -eq 408 -or $status -eq 429 -or $status -ge 500) +} + +function Invoke-WithRetry([scriptblock]$Action) { + $attempts = 4 + for ($attempt = 1; ; $attempt++) { + try { + return & $Action + } catch { + if ($attempt -ge $attempts -or -not (Test-TransientError $_)) { throw } + $delay = [math]::Pow(2, $attempt - 1) + Write-Host "Download failed ($($_.Exception.Message)); retrying in ${delay}s..." + Start-Sleep -Seconds $delay + } + } +} + function Get-Text([string]$Url) { - $content = (Invoke-WebRequest -Uri $Url -UseBasicParsing -Headers @{ 'User-Agent' = 'unity-cli-installer' }).Content - # Decode before returning: PowerShell enumerates byte[] function results - # into Object[], which would bypass the caller's byte[] type check. - if ($content -is [byte[]]) { return [System.Text.Encoding]::UTF8.GetString($content) } - return $content + Invoke-WithRetry { + $content = (Invoke-WebRequest -Uri $Url -UseBasicParsing -Headers @{ 'User-Agent' = 'unity-cli-installer' }).Content + # Decode before returning: PowerShell enumerates byte[] function results + # into Object[], which would bypass the caller's byte[] type check. + if ($content -is [byte[]]) { return [System.Text.Encoding]::UTF8.GetString($content) } + return $content + } } +# Returns $null only when the server definitively answers that the file is not +# there, so the caller can fall back; a network failure aborts with its cause. function Get-OptionalText([string]$Url) { try { Get-Text $Url } catch { + if (Test-TransientError $_) { Fail "failed to download ${Url}: $($_.Exception.Message)" } $null } } @@ -55,8 +88,10 @@ if ($env:UNITY_CLI_VERSION) { if (-not $tag.StartsWith('v')) { $tag = "v$tag" } } else { Write-Host 'Fetching latest release...' - $release = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" ` - -Headers @{ 'User-Agent' = 'unity-cli-installer' } + $release = Invoke-WithRetry { + Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" ` + -Headers @{ 'User-Agent' = 'unity-cli-installer' } + } $tag = $release.tag_name } if (-not $tag) { Fail 'failed to determine release tag' } @@ -99,8 +134,10 @@ $tmp = Join-Path $destDir 'unity-cli.download' Write-Host "Downloading $assetName..." try { - Invoke-WebRequest -Uri $assetUrl -OutFile $tmp -UseBasicParsing ` - -Headers @{ 'User-Agent' = 'unity-cli-installer' } + Invoke-WithRetry { + Invoke-WebRequest -Uri $assetUrl -OutFile $tmp -UseBasicParsing ` + -Headers @{ 'User-Agent' = 'unity-cli-installer' } + } } catch { Remove-Item -Force -ErrorAction SilentlyContinue $tmp Fail "download failed: $($_.Exception.Message)" diff --git a/scripts/install.sh b/scripts/install.sh index b7ea6d39..add6e82c 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -4,6 +4,8 @@ # # The download is verified against the release SHA256SUMS (or the release # manifest for older releases) and the install aborts on any mismatch. +# Transient network errors (no response, 408, 429, 5xx) are retried with +# backoff by curl; a missing file (404) is not. # # Environment: # UNITY_CLI_VERSION install a specific tag instead of the latest @@ -18,6 +20,11 @@ LINK_DIR="${HOME}/.local/bin" die() { echo "error: $*" >&2; exit 1; } +# curl with backoff retries for transient failures only. +fetch() { + curl -fsSL --retry 3 --retry-connrefused "$@" +} + need() { command -v "$1" >/dev/null 2>&1 || die "required command not found: $1" } @@ -72,7 +79,7 @@ if [ -n "${UNITY_CLI_VERSION:-}" ]; then case "$TAG" in v*) ;; *) TAG="v${TAG}" ;; esac else echo "Fetching latest release..." - TAG=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \ + TAG=$(fetch "https://api.github.com/repos/${REPO}/releases/latest" \ | grep '"tag_name"' | head -1 | sed 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') fi @@ -85,14 +92,22 @@ ASSET_NAME="unity-cli-${RID}" # 2. Resolve the expected SHA-256 and asset URL. # Prefer SHA256SUMS; fall back to the manifest for releases without it. -SUMS=$(curl -fsSL "${BASE_URL}/${TAG}/SHA256SUMS" 2>/dev/null) || SUMS="" +# Only a definitive "not there" (HTTP error 22, unreadable file:// 37) +# selects the fallback; a network failure aborts with its cause. +SUMS_RC=0 +SUMS=$(fetch "${BASE_URL}/${TAG}/SHA256SUMS") || SUMS_RC=$? +case "$SUMS_RC" in + 0) ;; + 22|37) SUMS="" ;; + *) die "failed to download SHA256SUMS (curl exit ${SUMS_RC})" ;; +esac if [ -n "$SUMS" ]; then EXPECTED_SHA=$(printf '%s\n' "$SUMS" \ | awk -v name="$ASSET_NAME" '{ f = $2; sub(/^\*/, "", f); if (f == name) { print tolower($1); exit } }') [ -z "$EXPECTED_SHA" ] && die "SHA256SUMS has no entry for ${ASSET_NAME}" ASSET_URL="${BASE_URL}/${TAG}/${ASSET_NAME}" else - MANIFEST=$(curl -fsSL "${BASE_URL}/${TAG}/unity-cli-manifest.json") \ + MANIFEST=$(fetch "${BASE_URL}/${TAG}/unity-cli-manifest.json") \ || die "failed to download SHA256SUMS or manifest" ASSET_URL=$(echo "$MANIFEST" | grep -A2 "\"${RID}\"" | grep '"url"' | head -1 \ | sed 's/.*"url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') @@ -108,7 +123,7 @@ mkdir -p "$DEST_DIR" TMP="${DEST_DIR}/unity-cli.download" echo "Downloading ${ASSET_NAME}..." -curl -fsSL -o "$TMP" "$ASSET_URL" || { rm -f "$TMP"; die "download failed"; } +fetch -o "$TMP" "$ASSET_URL" || { rm -f "$TMP"; die "download failed"; } # 4. Verify SHA-256 before touching the installed binary ACTUAL_SHA=$(sha256_check "$TMP") diff --git a/tests/install_script.rs b/tests/install_script.rs index 21b10bcf..371cbebd 100644 --- a/tests/install_script.rs +++ b/tests/install_script.rs @@ -164,3 +164,126 @@ fn install_sh_falls_back_to_manifest_checksum_without_sha256sums() { assert!(stderr.contains("checksum mismatch"), "stderr: {stderr}"); assert!(installed_binaries(&home).is_empty()); } + +/// Serves the release under `release_dir` over HTTP on 127.0.0.1, answering +/// the first `failures` requests for `flaky_path` with 503 (#514). Returns the +/// base URL and the per-path request counter. +fn serve_release_with_transient_failures( + release_dir: PathBuf, + flaky_path: &'static str, + failures: usize, +) -> (String, std::sync::Arc>>) { + use std::io::{BufRead, BufReader, Write}; + use std::net::TcpListener; + use std::sync::{Arc, Mutex}; + + let listener = TcpListener::bind("127.0.0.1:0").expect("bind"); + let base_url = format!("http://{}", listener.local_addr().expect("addr")); + let requests = Arc::new(Mutex::new(Vec::new())); + let seen = Arc::clone(&requests); + std::thread::spawn(move || { + for stream in listener.incoming() { + let Ok(mut stream) = stream else { break }; + let mut request_line = String::new(); + let mut reader = BufReader::new(stream.try_clone().expect("clone")); + if reader.read_line(&mut request_line).is_err() { + continue; + } + loop { + let mut header = String::new(); + match reader.read_line(&mut header) { + Ok(0) | Err(_) => break, + Ok(_) if header == "\r\n" || header == "\n" => break, + Ok(_) => {} + } + } + let path = request_line + .split_whitespace() + .nth(1) + .unwrap_or("/") + .to_string(); + let attempt = { + let mut seen = seen.lock().expect("lock"); + seen.push(path.clone()); + seen.iter().filter(|p| **p == path).count() + }; + let (status, body) = if path == flaky_path && attempt <= failures { + ("503 Service Unavailable", b"busy".to_vec()) + } else { + match fs::read(release_dir.join(path.trim_start_matches('/'))) { + Ok(bytes) => ("200 OK", bytes), + Err(_) => ("404 Not Found", b"missing".to_vec()), + } + }; + let header = format!( + "HTTP/1.1 {status}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n", + body.len() + ); + let _ = stream.write_all(header.as_bytes()); + let _ = stream.write_all(&body); + } + }); + (base_url, requests) +} + +#[test] +fn install_sh_retries_transient_sha256sums_errors_and_keeps_checksum_gate() { + let root = TempDir::new().expect("tempdir"); + let (_, tag_dir) = write_release(root.path(), b"genuine binary"); + write_sha256sums(&tag_dir, b"genuine binary"); + let sums_path = "/v9.9.9/SHA256SUMS"; + let (base_url, requests) = + serve_release_with_transient_failures(root.path().join("release"), sums_path, 1); + + let home = root.path().join("home"); + let output = run_install(&home, &base_url); + + assert!( + output.status.success(), + "install should survive one 503: {}", + String::from_utf8_lossy(&output.stderr) + ); + let sums_requests = requests + .lock() + .expect("lock") + .iter() + .filter(|p| *p == sums_path) + .count(); + assert_eq!(sums_requests, 2, "SHA256SUMS should be retried once"); + assert_eq!(installed_binaries(&home).len(), 1); + + // The retry must not weaken the gate: a tampered binary still aborts. + for rid in UNIX_RIDS { + fs::write(tag_dir.join(format!("unity-cli-{rid}")), b"tampered binary").expect("asset"); + } + let (base_url, _) = + serve_release_with_transient_failures(root.path().join("release"), sums_path, 1); + let tampered_home = root.path().join("tampered-home"); + let output = run_install(&tampered_home, &base_url); + assert!(!output.status.success(), "tampered install must fail"); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!(stderr.contains("checksum mismatch"), "stderr: {stderr}"); + assert!(installed_binaries(&tampered_home).is_empty()); +} + +#[test] +fn install_sh_reports_unreachable_release_instead_of_missing_checksums() { + let root = TempDir::new().expect("tempdir"); + // Bind then drop a listener so the port refuses connections. + let port = std::net::TcpListener::bind("127.0.0.1:0") + .expect("bind") + .local_addr() + .expect("addr") + .port(); + let home = root.path().join("home"); + + let output = run_install(&home, &format!("http://127.0.0.1:{port}")); + + assert!(!output.status.success()); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + stderr.contains("failed to download SHA256SUMS") && !stderr.contains("or manifest"), + "a network failure must not be reported as a missing SHA256SUMS: {stderr}" + ); + assert!(installed_binaries(&home).is_empty()); +} diff --git a/tests/scripts/install-ps1-test.ps1 b/tests/scripts/install-ps1-test.ps1 index 80393296..9dda12cb 100644 --- a/tests/scripts/install-ps1-test.ps1 +++ b/tests/scripts/install-ps1-test.ps1 @@ -23,10 +23,30 @@ $tampered = [System.Text.Encoding]::ASCII.GetBytes('tampered binary') Set-Content -Path (Join-Path $releaseDir 'SHA256SUMS') -Encoding ascii ` -Value "$(Get-Sha256Hex $genuine) unity-cli-win-x64" -$port = Get-Random -Minimum 20000 -Maximum 40000 +# Let the OS pick a free port instead of guessing one. +$probe = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) +$probe.Start() +$port = $probe.LocalEndpoint.Port +$probe.Stop() $server = Start-Process -PassThru -NoNewWindow python ` -ArgumentList @('-m', 'http.server', "$port", '--bind', '127.0.0.1', '--directory', (Join-Path $work 'release')) -Start-Sleep -Seconds 2 + +# Wait until the server answers instead of sleeping a fixed time: on a busy +# Windows runner python can take longer than 2 s to bind, and the installer +# then reports the refused connection as a download failure (#514). +function Wait-ReleaseServer { + $deadline = [DateTime]::UtcNow.AddSeconds(60) + while ([DateTime]::UtcNow -lt $deadline) { + if ($server.HasExited) { throw "FAIL: local release server exited with code $($server.ExitCode)" } + try { + Invoke-WebRequest -Uri "http://127.0.0.1:$port/$tag/SHA256SUMS" -UseBasicParsing | Out-Null + return + } catch { + Start-Sleep -Milliseconds 200 + } + } + throw 'FAIL: local release server did not start within 60 s' +} function Invoke-Installer([string]$ToolsRoot) { $env:UNITY_CLI_VERSION = $tag @@ -42,6 +62,8 @@ function Invoke-Installer([string]$ToolsRoot) { } try { + Wait-ReleaseServer + # Tampered binary: install must abort and leave nothing behind. [System.IO.File]::WriteAllBytes((Join-Path $releaseDir 'unity-cli-win-x64'), $tampered) $tamperedRoot = Join-Path $work 'tools-tampered' diff --git a/tests/scripts/install-ps1-text-test.ps1 b/tests/scripts/install-ps1-text-test.ps1 index 07a3959c..45df7dd8 100644 --- a/tests/scripts/install-ps1-text-test.ps1 +++ b/tests/scripts/install-ps1-text-test.ps1 @@ -1,28 +1,89 @@ -# Check the installer's HTTP text boundary on any PowerShell platform. +# Check the installer's HTTP text and retry boundary on any PowerShell platform. $ErrorActionPreference = 'Stop' $installer = Join-Path $PSScriptRoot '../../scripts/install.ps1' $ast = [System.Management.Automation.Language.Parser]::ParseFile($installer, [ref]$null, [ref]$null) -foreach ($name in @('Get-Text', 'Get-OptionalText')) { +foreach ($name in @('Fail', 'Get-HttpStatus', 'Test-TransientError', 'Invoke-WithRetry', 'Get-Text', 'Get-OptionalText')) { $definition = $ast.Find({ param($node) $node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $node.Name -eq $name }, $false) + if (-not $definition) { throw "install.ps1 must define $name" } . ([scriptblock]::Create($definition.Extent.Text)) } +# Keep the retry backoff out of the test run. +function Start-Sleep { param($Seconds, $Milliseconds) $script:sleeps++ } + # Invoke-WebRequest returns byte[] for application/octet-stream (SHA256SUMS). +# $script:failures holds the exceptions to throw before the response succeeds. function Invoke-WebRequest { - param($Uri, [switch]$UseBasicParsing, $Headers) + param($Uri, [switch]$UseBasicParsing, $Headers, $OutFile) + $script:calls++ + if ($script:failures.Count -gt 0) { + $next = $script:failures[0] + $script:failures = @($script:failures | Select-Object -Skip 1) + throw $next + } [pscustomobject]@{ Content = $script:responseContent } } +function Reset-Http([object[]]$Failures) { + $script:calls = 0 + $script:sleeps = 0 + $script:failures = @($Failures) +} + +# Same shape as WebException (PS 5.1) and HttpResponseException (PS 7): the +# HTTP status is on Exception.Response.StatusCode. +class FakeHttpException : System.Exception { + [object]$Response + FakeHttpException([string]$Message, [int]$Status) : base($Message) { + $this.Response = [pscustomobject]@{ StatusCode = $Status } + } +} + +function New-HttpError([int]$Status) { + [FakeHttpException]::new("Response status code does not indicate success: $Status", $Status) +} + +function New-NetworkError { + [System.Net.Http.HttpRequestException]::new('No connection could be made because the target machine actively refused it.') +} + +$url = 'https://example.invalid/SHA256SUMS' $expected = ('a' * 64) + " unity-cli-win-x64`r`n" + ('b' * 64) + " unity-cli-win-x64.exe`r`n" foreach ($binary in @($true, $false)) { + Reset-Http @() $script:responseContent = if ($binary) { [System.Text.Encoding]::UTF8.GetBytes($expected) } else { $expected } # Preserve the byte[] type in the mocked HTTP response. if ($binary) { $script:responseContent = [byte[]]$script:responseContent } - $actual = Get-OptionalText 'https://example.invalid/SHA256SUMS' + $actual = Get-OptionalText $url if ($actual -isnot [string] -or $actual -cne $expected) { throw "HTTP content must return unchanged text (binary=$binary, actual type=$($actual.GetType().FullName))" } } + +# Transient failures (no response, 5xx, 429) are retried with backoff (#514). +$script:responseContent = [byte[]][System.Text.Encoding]::UTF8.GetBytes($expected) +Reset-Http @((New-NetworkError), (New-HttpError 503), (New-HttpError 429)) +$actual = Get-Text $url +if ($actual -cne $expected) { throw "transient errors must be retried until the download succeeds (actual: $actual)" } +if ($script:calls -ne 4) { throw "expected 4 HTTP attempts, got $($script:calls)" } +if ($script:sleeps -ne 3) { throw "expected a backoff before each retry, got $($script:sleeps)" } + +# A missing optional file (404) is not retried and selects the fallback. +Reset-Http @((New-HttpError 404)) +$actual = Get-OptionalText $url +if ($null -ne $actual) { throw "404 must return null so the installer can fall back to the manifest" } +if ($script:calls -ne 1) { throw "404 must not be retried, got $($script:calls) attempts" } + +# A persistent network failure is reported with its cause, never as a missing file. +Reset-Http @(1..10 | ForEach-Object { New-NetworkError }) +$message = $null +try { Get-OptionalText $url | Out-Null } catch { $message = $_.Exception.Message } +if (-not $message) { throw 'a persistent network failure must abort, not fall back to the manifest' } +if ($message -notlike "unity-cli install failed: failed to download ${url}:*refused*") { + throw "unexpected network failure message: $message" +} +if ($script:calls -ne 4) { throw "expected 4 HTTP attempts before giving up, got $($script:calls)" } + Write-Host 'install.ps1 HTTP text tests passed' From d3359d6fd7121527f031353e3db5717d973f6b27 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 09:54:45 +0900 Subject: [PATCH 55/73] fix(lsp): normalize lone CR in edits to the file's newline style (#516) ApplyNewlines now treats a lone CR as a line terminator (as the C# spec does) for LF and CRLF files too, so write/apply/create-overwrite no longer leave mixed newlines. A lone CR inside verbatim, raw, or interpolated string text is part of the string value and is kept. Adds the 3x3 original-by-input newline byte matrix and string-literal cases. Co-Authored-By: Claude Opus 5.5 --- lsp/Server.Core/LspSourceFile.cs | 44 ++++++++++++++++++--- lsp/SourceFileFormatTests.cs | 66 +++++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 6 deletions(-) diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 849caff8..d7ac4be7 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -1,7 +1,10 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; namespace UnityCli.Lsp.Core; @@ -25,16 +28,47 @@ public static (string Text, LspSourceFileFormat Format) Decode(byte[] bytes) return (text, new LspSourceFileFormat(encoding, DetectNewLine(text))); } - /// Rewrites line breaks to the file's convention; mixed or unknown conventions are left as given. + /// + /// Rewrites line breaks (CRLF, LF, and a lone CR, which C# also treats as a line terminator) to the + /// file's convention; mixed or unknown conventions are left as given. A lone CR inside a string + /// literal is part of the string's value and is kept. + /// public string ApplyNewlines(string text) { if (NewLine is null) return text; - var lf = text.Replace("\r\n", "\n"); - // A CR-only file folds stray CRs too; LF and CRLF files leave a lone CR as content. - if (NewLine == "\r") return lf.Replace("\n", "\r"); - return NewLine == "\n" ? lf : lf.Replace("\n", NewLine); + var literalCrs = text.Contains('\r') ? FindLoneCrsInStringLiterals(text) : null; + var result = new StringBuilder(text.Length); + for (var i = 0; i < text.Length; i++) + { + var c = text[i]; + if (c == '\n') result.Append(NewLine); + else if (c != '\r') result.Append(c); + else if (i + 1 < text.Length && text[i + 1] == '\n') { result.Append(NewLine); i++; } + else result.Append(literalCrs?.Contains(i) == true ? "\r" : NewLine); + } + return result.ToString(); } + private static HashSet FindLoneCrsInStringLiterals(string text) + { + var positions = new HashSet(); + foreach (var token in CSharpSyntaxTree.ParseText(text).GetRoot().DescendantTokens()) + { + if (!IsMultiLineStringContent(token.Kind())) continue; + for (var i = token.SpanStart; i < token.Span.End; i++) + { + if (text[i] == '\r' && (i + 1 >= text.Length || text[i + 1] != '\n')) positions.Add(i); + } + } + return positions; + } + + // Only verbatim, raw, and interpolated text can span lines; a CR ends any other literal. + private static bool IsMultiLineStringContent(SyntaxKind kind) => kind is + SyntaxKind.StringLiteralToken or SyntaxKind.Utf8StringLiteralToken or + SyntaxKind.MultiLineRawStringLiteralToken or SyntaxKind.Utf8MultiLineRawStringLiteralToken or + SyntaxKind.InterpolatedStringTextToken; + private static Encoding DetectEncoding(byte[] b) { if (b.Length >= 3 && b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF) return new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 55fa05f2..f149fd00 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -143,7 +143,8 @@ public async Task WriteCSharpFile_TreatsANewlineOnlyDifferenceAsNoChange() [Theory] [InlineData("a\r\nb\nc\n", "x\ny\n", "x\ny\n")] [InlineData("single line", "x\r\ny\n", "x\r\ny\n")] - [InlineData("a\r\nb\r\n", "x\ny\r\nz\rw", "x\r\ny\r\nz\rw")] + [InlineData("a\r\nb\r\n", "x\ny\r\nz\rw", "x\r\ny\r\nz\r\nw")] + [InlineData("a\nb\n", "x\ry\r\nz\rw", "x\ny\nz\nw")] [InlineData("a\nb\n", "x\r\ny\n", "x\ny\n")] [InlineData("a\rb\r", "x\ny\r\nz\rw", "x\ry\rz\rw")] [InlineData("a\rb\nc\r", "x\ny\n", "x\ny\n")] @@ -154,6 +155,69 @@ public void ApplyNewlines_OnlyRewritesWhenTheOriginalUsesOneConvention(string or Assert.Equal(expected, format.ApplyNewlines(text)); } + public static TheoryData NewlineMatrix() + { + var data = new TheoryData(); + foreach (var original in new[] { "\n", "\r\n", "\r" }) + foreach (var input in new[] { "\n", "\r\n", "\r" }) + { + data.Add(original, input); + } + return data; + } + + [Theory] + [MemberData(nameof(NewlineMatrix))] + public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string originalNewline, string inputNewline) + { + const string written = "public class Sample\n{\n public int Run() { return 2; }\n}\n"; + foreach (var operation in new[] { "write", "apply", "create_overwrite" }) + { + var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); + Directory.CreateDirectory(Path.Combine(root, "Assets")); + var scriptPath = Path.Combine(root, "Assets", "Sample.cs"); + await File.WriteAllBytesAsync(scriptPath, Encode(Original, "utf-8", originalNewline)); + try + { + var service = new LspEditService(root, new LspFileLockProvider()); + var input = written.Replace("\n", inputNewline); + using var files = JsonDocument.Parse(JsonSerializer.Serialize(new[] { new { relative = "Assets/Sample.cs", newText = input } })); + var result = operation switch + { + "write" => await service.WriteCSharpFileAsync("Assets/Sample.cs", input, true, true, false), + "apply" => await service.ApplyCSharpEditsAsync(files.RootElement, true, true, false), + _ => await service.CreateCSharpFileAsync("Assets/Sample.cs", input, true, true, true, false), + }; + + using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); + Assert.True(response.RootElement.GetProperty("applied").GetBoolean(), operation + ": " + response.RootElement); + Assert.Equal(Encode(written, "utf-8", originalNewline), await File.ReadAllBytesAsync(scriptPath)); + } + finally + { + Directory.Delete(root, recursive: true); + } + } + } + + // A lone CR inside a string literal is part of the string's value, so it is never rewritten; + // lone CRs anywhere else (code, comments) are line terminators and follow the file's convention. + [Theory] + [InlineData("\n", "var a = @\"x\ry\";\rvar b = 1;\n", "var a = @\"x\ry\";\nvar b = 1;\n")] + [InlineData("\r\n", "var a = @\"x\ry\";\rvar b = 1;\n", "var a = @\"x\ry\";\r\nvar b = 1;\r\n")] + [InlineData("\n", "var a = $@\"x\r{b}\ry\";\r", "var a = $@\"x\r{b}\ry\";\n")] + [InlineData("\r\n", "var a = \"\"\"\n x\ry\n \"\"\";\r", "var a = \"\"\"\r\n x\ry\r\n \"\"\";\r\n")] + [InlineData("\n", "var a = $\"\"\"\n x\r{b}\n \"\"\";\r", "var a = $\"\"\"\n x\r{b}\n \"\"\";\n")] + [InlineData("\n", "var a = \"\"\"\n x\ry\n \"\"\"u8;\r", "var a = \"\"\"\n x\ry\n \"\"\"u8;\n")] + [InlineData("\n", "// comment\rvar a = 1; /* x\ry */\r", "// comment\nvar a = 1; /* x\ny */\n")] + [InlineData("\n", "var a = \"x\ry\";\r", "var a = \"x\ny\";\n")] + public void ApplyNewlines_KeepsLoneCrInsideStringLiterals(string originalNewline, string text, string expected) + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a" + originalNewline + "b" + originalNewline)); + + Assert.Equal(expected, format.ApplyNewlines(text)); + } + private static byte[] Encode(string lfText, string encoding, string newline) { Encoding target = encoding switch From 8f15477b41919b88135df576564ef61c90a62b00 Mon Sep 17 00:00:00 2001 From: akiojin Date: Wed, 14 Oct 2026 10:22:22 +0900 Subject: [PATCH 56/73] fix(lsp): preserve string CRs in all preprocessor branches --- ...4eb3fff8b95db8dd0467dc69e71c7264cbc6.jsonl | 1 + ...ba79316189b993fd3b8822cfbfe3b7af7f81.jsonl | 1 + ...80f5799c68e043cb6145d400e5e32345bd9b.jsonl | 1 + ...a352bd7cc308c3378de4eaa820358085e6d0.jsonl | 1 + ...39f74033569483f7dc6407390800eb844fe7.jsonl | 1 + ...d02fbada6d1024058a2c21e0c7244cd2c0b9.jsonl | 1 + lsp/Server.Core/LspSourceFile.cs | 26 ++++++- lsp/SourceFileFormatTests.cs | 77 +++++++++++++++++++ 8 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 .gwt/work/events/28/28fa8c792aee41fe0b4e79084fb54eb3fff8b95db8dd0467dc69e71c7264cbc6.jsonl create mode 100644 .gwt/work/events/80/8021ea88ebe8fc33004155e7772aba79316189b993fd3b8822cfbfe3b7af7f81.jsonl create mode 100644 .gwt/work/events/94/946595126fec4af72bd325bb618180f5799c68e043cb6145d400e5e32345bd9b.jsonl create mode 100644 .gwt/work/events/bb/bb77301504a6ced56569c8335a63a352bd7cc308c3378de4eaa820358085e6d0.jsonl create mode 100644 .gwt/work/events/d5/d5632de57ae50f64b59d7c3fa6db39f74033569483f7dc6407390800eb844fe7.jsonl create mode 100644 .gwt/work/events/da/da12e9f6b2845608bfb8503d7662d02fbada6d1024058a2c21e0c7244cd2c0b9.jsonl diff --git a/.gwt/work/events/28/28fa8c792aee41fe0b4e79084fb54eb3fff8b95db8dd0467dc69e71c7264cbc6.jsonl b/.gwt/work/events/28/28fa8c792aee41fe0b4e79084fb54eb3fff8b95db8dd0467dc69e71c7264cbc6.jsonl new file mode 100644 index 00000000..05dfed4b --- /dev/null +++ b/.gwt/work/events/28/28fa8c792aee41fe0b4e79084fb54eb3fff8b95db8dd0467dc69e71c7264cbc6.jsonl @@ -0,0 +1 @@ +{"id":"533267ed-456b-4e4e-ae96-8e10df85df0d","work_item_id":"work-work-issue-516-59f2c1be","kind":"start","title":"fix(lsp): normalize lone CR in edits to the file's newline style for LF and CRLF files","intent":"Check Board for latest updates","summary":"Codex is running","progress_summary":null,"status_category":"active","owner":"Issue #516","next_action":"Check Board for latest updates","agent_session_id":"9df139e6-24fb-452f-98d6-3388b16297b3","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T00:57:21.834855200Z"} diff --git a/.gwt/work/events/80/8021ea88ebe8fc33004155e7772aba79316189b993fd3b8822cfbfe3b7af7f81.jsonl b/.gwt/work/events/80/8021ea88ebe8fc33004155e7772aba79316189b993fd3b8822cfbfe3b7af7f81.jsonl new file mode 100644 index 00000000..f3a77ba3 --- /dev/null +++ b/.gwt/work/events/80/8021ea88ebe8fc33004155e7772aba79316189b993fd3b8822cfbfe3b7af7f81.jsonl @@ -0,0 +1 @@ +{"id":"aff272b6-abeb-4b22-97d5-ac6857d5bdb1","work_item_id":"work-work-issue-516-59f2c1be","kind":"resume","title":"fix(lsp): normalize lone CR in edits to the file's newline style for LF and CRLF files","intent":"Codex started work on Issue #516 fix(lsp): normalize lone CR in edits to the file's newline style for LF and CRLF files (work/issue-516)","summary":"3 active agents","progress_summary":null,"status_category":"active","owner":"Issue #516","next_action":"Check Board for latest updates","agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:/unity-cli/work/issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T01:13:28.924834700Z"} diff --git a/.gwt/work/events/94/946595126fec4af72bd325bb618180f5799c68e043cb6145d400e5e32345bd9b.jsonl b/.gwt/work/events/94/946595126fec4af72bd325bb618180f5799c68e043cb6145d400e5e32345bd9b.jsonl new file mode 100644 index 00000000..e7016b39 --- /dev/null +++ b/.gwt/work/events/94/946595126fec4af72bd325bb618180f5799c68e043cb6145d400e5e32345bd9b.jsonl @@ -0,0 +1 @@ +{"id":"39223122-1863-4d4a-a755-962ebe880c2a","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":".NET の変更範囲に合う正式検証と PR 作成","summary":null,"progress_summary":"条件コンパイル全分岐の文字列 CR 保護を実装し、LSP 全339テストが成功。指示行の空白ケースを追加して正式検証へ進む。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T01:21:37.696264300Z"} diff --git a/.gwt/work/events/bb/bb77301504a6ced56569c8335a63a352bd7cc308c3378de4eaa820358085e6d0.jsonl b/.gwt/work/events/bb/bb77301504a6ced56569c8335a63a352bd7cc308c3378de4eaa820358085e6d0.jsonl new file mode 100644 index 00000000..b3ae1a55 --- /dev/null +++ b/.gwt/work/events/bb/bb77301504a6ced56569c8335a63a352bd7cc308c3378de4eaa820358085e6d0.jsonl @@ -0,0 +1 @@ +{"id":"7870472f-ab27-4cb7-9b24-0bc936374999","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":"無効な条件コンパイル分岐の CR 保持を再現・修正","summary":null,"progress_summary":"origin/develop に初回修正が収録済み。残 AC-1 は無効分岐内の文字列 CR 保護。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T01:16:42.946264500Z"} diff --git a/.gwt/work/events/d5/d5632de57ae50f64b59d7c3fa6db39f74033569483f7dc6407390800eb844fe7.jsonl b/.gwt/work/events/d5/d5632de57ae50f64b59d7c3fa6db39f74033569483f7dc6407390800eb844fe7.jsonl new file mode 100644 index 00000000..60a9926a --- /dev/null +++ b/.gwt/work/events/d5/d5632de57ae50f64b59d7c3fa6db39f74033569483f7dc6407390800eb844fe7.jsonl @@ -0,0 +1 @@ +{"id":"613ce139-0256-4818-a25e-f86b4d4a59ae","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":"Issue #516 の改行正規化修正を届ける","intent":"実行手順と未配信差分の確認","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T01:14:18.065917600Z"} diff --git a/.gwt/work/events/da/da12e9f6b2845608bfb8503d7662d02fbada6d1024058a2c21e0c7244cd2c0b9.jsonl b/.gwt/work/events/da/da12e9f6b2845608bfb8503d7662d02fbada6d1024058a2c21e0c7244cd2c0b9.jsonl new file mode 100644 index 00000000..2d03941b --- /dev/null +++ b/.gwt/work/events/da/da12e9f6b2845608bfb8503d7662d02fbada6d1024058a2c21e0c7244cd2c0b9.jsonl @@ -0,0 +1 @@ +{"id":"ba97b431-504b-459a-9e9b-bd5bef1805fb","work_item_id":"work-work-issue-516-59f2c1be","kind":"resume","title":"fix(lsp): normalize lone CR in edits to the file's newline style for LF and CRLF files","intent":"Codex started work on Issue #516 fix(lsp): normalize lone CR in edits to the file's newline style for LF and CRLF files (work/issue-516)","summary":"2 active agents","progress_summary":null,"status_category":"active","owner":"Issue #516","next_action":"Check Board for latest updates","agent_session_id":"df5ad3b4-6dc1-488f-a0a9-a3cd91749075","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:/unity-cli/work/issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T01:07:33.740196800Z"} diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index d7ac4be7..7d0fcf14 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -52,7 +52,10 @@ public string ApplyNewlines(string text) private static HashSet FindLoneCrsInStringLiterals(string text) { var positions = new HashSet(); - foreach (var token in CSharpSyntaxTree.ParseText(text).GetRoot().DescendantTokens()) + // Inspect every preprocessor branch, independent of the current project's symbols. + // Keep positions identical to the original text, including directive-looking string lines. + var syntaxText = CommentOutDirectivePrefixes(text); + foreach (var token in CSharpSyntaxTree.ParseText(syntaxText).GetRoot().DescendantTokens(descendIntoTrivia: true)) { if (!IsMultiLineStringContent(token.Kind())) continue; for (var i = token.SpanStart; i < token.Span.End; i++) @@ -63,6 +66,27 @@ private static HashSet FindLoneCrsInStringLiterals(string text) return positions; } + private static string CommentOutDirectivePrefixes(string text) + { + var chars = text.ToCharArray(); + var lineStart = true; + for (var i = 0; i < chars.Length; i++) + { + var c = chars[i]; + if (c is '\r' or '\n' or '\u0085' or '\u2028' or '\u2029') { lineStart = true; continue; } + if (lineStart && char.IsWhiteSpace(c)) continue; + if (lineStart && c == '#' && i + 1 < chars.Length && + (char.IsLetter(chars[i + 1]) || chars[i + 1] is ' ' or '\t')) + { + // Replace only the prefix: a quote after '#' inside a literal must stay intact. + chars[i] = '/'; + chars[i + 1] = '/'; + } + lineStart = false; + } + return new string(chars); + } + // Only verbatim, raw, and interpolated text can span lines; a CR ends any other literal. private static bool IsMultiLineStringContent(SyntaxKind kind) => kind is SyntaxKind.StringLiteralToken or SyntaxKind.Utf8StringLiteralToken or diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index f149fd00..e4a0ad3f 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -211,6 +211,7 @@ public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string origi [InlineData("\n", "var a = \"\"\"\n x\ry\n \"\"\"u8;\r", "var a = \"\"\"\n x\ry\n \"\"\"u8;\n")] [InlineData("\n", "// comment\rvar a = 1; /* x\ry */\r", "// comment\nvar a = 1; /* x\ny */\n")] [InlineData("\n", "var a = \"x\ry\";\r", "var a = \"x\ny\";\n")] + [InlineData("\n", "var a = @\"x\r#\";\r", "var a = @\"x\r#\";\n")] public void ApplyNewlines_KeepsLoneCrInsideStringLiterals(string originalNewline, string text, string expected) { var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a" + originalNewline + "b" + originalNewline)); @@ -218,6 +219,82 @@ public void ApplyNewlines_KeepsLoneCrInsideStringLiterals(string originalNewline Assert.Equal(expected, format.ApplyNewlines(text)); } + public static TheoryData InactiveBranchStrings() + { + var data = new TheoryData(); + foreach (var newline in new[] { "\n", "\r\n", "\r" }) + foreach (var literal in new[] + { + "@\"x\ry\"", + "\"\"\"\n x\ry\n \"\"\"", + "\"\"\"\n x\ry\n \"\"\"u8", + "$@\"x\r{1}\ry\"", + "$\"\"\"\n x\r{1}\ry\n \"\"\"", + "@\"x\r#if OTHER\r#endif\ry\"", + }) + foreach (var branch in new[] + { + "#if UNITY_EDITOR\n{0}\n#endif\n", + "\t# if UNITY_EDITOR\n{0}\n\t# endif\n", + "#if false\n{0}\n#endif\n", + "#if true\nint enabled = 1;\n#elif UNITY_STANDALONE\n{0}\n#endif\n", + "#if true\nint enabled = 1;\n#else\n{0}\n#endif\n", + "#if UNITY_EDITOR\n#if UNITY_STANDALONE\n{0}\n#endif\n#endif\n", + "#define UNITY_EDITOR\n#if !UNITY_EDITOR\n{0}\n#endif\n", + }) + { + data.Add(newline, literal, branch); + } + return data; + } + + [Theory] + [MemberData(nameof(InactiveBranchStrings))] + public async Task EditInputNewlines_KeepStringCrsInInactiveBranches(string newline, string literal, string branch) + { + // Construct expected bytes separately: source line breaks follow the original convention, + // while the lone CRs in the literal remain part of its value. + var declaration = "var text = " + literal + ";"; + var input = branch.Replace("{0}", declaration); + var expected = branch.Replace("\n", newline).Replace("{0}", declaration.Replace("\n", newline)); + foreach (var operation in new[] { "write", "apply", "create_overwrite" }) + { + var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); + Directory.CreateDirectory(Path.Combine(root, "Assets")); + var scriptPath = Path.Combine(root, "Assets", "Sample.cs"); + await File.WriteAllBytesAsync(scriptPath, Encode(Original, "utf-8-bom", newline)); + try + { + var service = new LspEditService(root, new LspFileLockProvider()); + using var files = JsonDocument.Parse(JsonSerializer.Serialize(new[] { new { relative = "Assets/Sample.cs", newText = input } })); + var result = operation switch + { + "write" => await service.WriteCSharpFileAsync("Assets/Sample.cs", input, true, true, false), + "apply" => await service.ApplyCSharpEditsAsync(files.RootElement, true, true, false), + _ => await service.CreateCSharpFileAsync("Assets/Sample.cs", input, true, true, true, false), + }; + + using var response = JsonDocument.Parse(JsonSerializer.Serialize(result)); + Assert.True(response.RootElement.GetProperty("applied").GetBoolean(), operation + ": " + response.RootElement); + var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); + Assert.Equal(encoding.GetPreamble().Concat(encoding.GetBytes(expected)).ToArray(), await File.ReadAllBytesAsync(scriptPath)); + } + finally + { + Directory.Delete(root, recursive: true); + } + } + } + + [Fact] + public void ApplyNewlines_NormalizesCrsInInactiveCommentsAndDirectiveMessages() + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + const string input = "#if UNITY_EDITOR\r// @\"x\ry\"\r/* @\"x\ry\" */\r#error @\"x\ry\"\r#endif\r"; + + Assert.Equal(input.Replace("\r", "\n"), format.ApplyNewlines(input)); + } + private static byte[] Encode(string lfText, string encoding, string newline) { Encoding target = encoding switch From 63d10ee48eab58bbee55500bd3748ff546295e2a Mon Sep 17 00:00:00 2001 From: akiojin Date: Wed, 14 Oct 2026 10:29:36 +0900 Subject: [PATCH 57/73] fix(lsp): recognize all whitespace before directive names --- ...e5e450d19c82aeaae85c0be992f09a28b3bd54af7a265861c3.jsonl | 1 + ...630b51977eae7e76fe5b17a00aa8ef2826da72fc1e7e6e16eb.jsonl | 1 + lsp/Server.Core/LspSourceFile.cs | 6 ++++-- lsp/SourceFileFormatTests.cs | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .gwt/work/events/33/3318750b0538f8e5e450d19c82aeaae85c0be992f09a28b3bd54af7a265861c3.jsonl create mode 100644 .gwt/work/events/e5/e5ba87b8461511630b51977eae7e76fe5b17a00aa8ef2826da72fc1e7e6e16eb.jsonl diff --git a/.gwt/work/events/33/3318750b0538f8e5e450d19c82aeaae85c0be992f09a28b3bd54af7a265861c3.jsonl b/.gwt/work/events/33/3318750b0538f8e5e450d19c82aeaae85c0be992f09a28b3bd54af7a265861c3.jsonl new file mode 100644 index 00000000..c16f70d8 --- /dev/null +++ b/.gwt/work/events/33/3318750b0538f8e5e450d19c82aeaae85c0be992f09a28b3bd54af7a265861c3.jsonl @@ -0,0 +1 @@ +{"id":"fdba7846-8c4e-4d11-a671-fd122fcd0380","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":"指示名の前の Unicode 空白も含めた AC-1 の最終検証","summary":null,"progress_summary":"Ready PR #518 を develop と同期済み。レビュー中にプリプロセッサ指示内の追加空白2ケースをREDで再現し、文字列CR保持を補強。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":518,"pr_url":"https://github.com/akiojin/unity-cli/pull/518","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T01:29:24.426439700Z"} diff --git a/.gwt/work/events/e5/e5ba87b8461511630b51977eae7e76fe5b17a00aa8ef2826da72fc1e7e6e16eb.jsonl b/.gwt/work/events/e5/e5ba87b8461511630b51977eae7e76fe5b17a00aa8ef2826da72fc1e7e6e16eb.jsonl new file mode 100644 index 00000000..2a26f838 --- /dev/null +++ b/.gwt/work/events/e5/e5ba87b8461511630b51977eae7e76fe5b17a00aa8ef2826da72fc1e7e6e16eb.jsonl @@ -0,0 +1 @@ +{"id":"7dbc9a61-b6b7-4993-ac0a-59e337b8449d","work_item_id":"work-work-issue-516-59f2c1be","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"active","owner":null,"next_action":null,"agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":518,"pr_url":"https://github.com/akiojin/unity-cli/pull/518","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T01:24:52.918816600Z"} diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 7d0fcf14..1377e6e4 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -73,10 +73,10 @@ private static string CommentOutDirectivePrefixes(string text) for (var i = 0; i < chars.Length; i++) { var c = chars[i]; - if (c is '\r' or '\n' or '\u0085' or '\u2028' or '\u2029') { lineStart = true; continue; } + if (IsLineBreak(c)) { lineStart = true; continue; } if (lineStart && char.IsWhiteSpace(c)) continue; if (lineStart && c == '#' && i + 1 < chars.Length && - (char.IsLetter(chars[i + 1]) || chars[i + 1] is ' ' or '\t')) + (char.IsLetter(chars[i + 1]) || (char.IsWhiteSpace(chars[i + 1]) && !IsLineBreak(chars[i + 1])))) { // Replace only the prefix: a quote after '#' inside a literal must stay intact. chars[i] = '/'; @@ -87,6 +87,8 @@ private static string CommentOutDirectivePrefixes(string text) return new string(chars); } + private static bool IsLineBreak(char c) => c is '\r' or '\n' or '\u0085' or '\u2028' or '\u2029'; + // Only verbatim, raw, and interpolated text can span lines; a CR ends any other literal. private static bool IsMultiLineStringContent(SyntaxKind kind) => kind is SyntaxKind.StringLiteralToken or SyntaxKind.Utf8StringLiteralToken or diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index e4a0ad3f..9596b719 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -212,6 +212,8 @@ public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string origi [InlineData("\n", "// comment\rvar a = 1; /* x\ry */\r", "// comment\nvar a = 1; /* x\ny */\n")] [InlineData("\n", "var a = \"x\ry\";\r", "var a = \"x\ny\";\n")] [InlineData("\n", "var a = @\"x\r#\";\r", "var a = @\"x\r#\";\n")] + [InlineData("\n", "#\fif UNITY_EDITOR\nvar a = @\"x\ry\";\r#endif\n", "#\fif UNITY_EDITOR\nvar a = @\"x\ry\";\n#endif\n")] + [InlineData("\n", "#\u00a0if UNITY_EDITOR\nvar a = @\"x\ry\";\r#endif\n", "#\u00a0if UNITY_EDITOR\nvar a = @\"x\ry\";\n#endif\n")] public void ApplyNewlines_KeepsLoneCrInsideStringLiterals(string originalNewline, string text, string expected) { var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a" + originalNewline + "b" + originalNewline)); From e8a6189be8f292282e24b216f0a06a09a660cf58 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 10:45:16 +0900 Subject: [PATCH 58/73] chore(work): record Work events for #516 verification Co-Authored-By: Claude Opus 5.5 --- ...67f2bb56feea74f2745a763da628128b9b209f25de5e04def3609d4.jsonl | 1 + ...86ffd579cd4f0b7ab48d5ff55c1bcf33ef1a62641fff9214bf69dae.jsonl | 1 + ...595178b02462ac3e615640b8b798b38b5ce45f19a43e6a3ff1631f1.jsonl | 1 + ...d9890b38f154f4201bcc76343fd387167eb1dfc6b35da38c8c88e66.jsonl | 1 + ...3fa672eed535443166fd5dfd5e5b07bd95611ee614f760823af2cb0.jsonl | 1 + ...f002714e266210435aeb76900d77e23e5611ee84ee50e8fef642639.jsonl | 1 + ...d64ef32dddfd526ea6a0e174992f8ac171907a5ab55aedcfe836a73.jsonl | 1 + ...37cdbfe8ea439dbd4d88fb6590a3c7ad37297584d6cb01335c81218.jsonl | 1 + ...82a1e0c01d54f9ec52168270b59a40c0244106531add4bb6760242d.jsonl | 1 + ...ef74597116a67bb02a7d085199df22202724e9325546b959d6a0a24.jsonl | 1 + 10 files changed, 10 insertions(+) create mode 100644 .gwt/work/events/0e/0ef73dc5867f2bb56feea74f2745a763da628128b9b209f25de5e04def3609d4.jsonl create mode 100644 .gwt/work/events/6f/6f5ed846e86ffd579cd4f0b7ab48d5ff55c1bcf33ef1a62641fff9214bf69dae.jsonl create mode 100644 .gwt/work/events/79/792461313595178b02462ac3e615640b8b798b38b5ce45f19a43e6a3ff1631f1.jsonl create mode 100644 .gwt/work/events/98/985343f37d9890b38f154f4201bcc76343fd387167eb1dfc6b35da38c8c88e66.jsonl create mode 100644 .gwt/work/events/9d/9d86038043fa672eed535443166fd5dfd5e5b07bd95611ee614f760823af2cb0.jsonl create mode 100644 .gwt/work/events/a7/a7ac6a6e9f002714e266210435aeb76900d77e23e5611ee84ee50e8fef642639.jsonl create mode 100644 .gwt/work/events/af/afade077dd64ef32dddfd526ea6a0e174992f8ac171907a5ab55aedcfe836a73.jsonl create mode 100644 .gwt/work/events/b5/b5d75d20837cdbfe8ea439dbd4d88fb6590a3c7ad37297584d6cb01335c81218.jsonl create mode 100644 .gwt/work/events/c2/c272cda4b82a1e0c01d54f9ec52168270b59a40c0244106531add4bb6760242d.jsonl create mode 100644 .gwt/work/events/ee/eeb5d58edef74597116a67bb02a7d085199df22202724e9325546b959d6a0a24.jsonl diff --git a/.gwt/work/events/0e/0ef73dc5867f2bb56feea74f2745a763da628128b9b209f25de5e04def3609d4.jsonl b/.gwt/work/events/0e/0ef73dc5867f2bb56feea74f2745a763da628128b9b209f25de5e04def3609d4.jsonl new file mode 100644 index 00000000..3fe949d8 --- /dev/null +++ b/.gwt/work/events/0e/0ef73dc5867f2bb56feea74f2745a763da628128b9b209f25de5e04def3609d4.jsonl @@ -0,0 +1 @@ +{"id":"d79e484a-3e42-40d5-bb27-228e5a5aa330","work_item_id":"work-work-issue-516-59f2c1be","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"active","owner":null,"next_action":null,"agent_session_id":"2422daaa-fb2e-42af-a9de-476f61a2dc84","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":517,"pr_url":"https://github.com/akiojin/unity-cli/pull/517","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T00:55:14.793037Z"} diff --git a/.gwt/work/events/6f/6f5ed846e86ffd579cd4f0b7ab48d5ff55c1bcf33ef1a62641fff9214bf69dae.jsonl b/.gwt/work/events/6f/6f5ed846e86ffd579cd4f0b7ab48d5ff55c1bcf33ef1a62641fff9214bf69dae.jsonl new file mode 100644 index 00000000..21c67b99 --- /dev/null +++ b/.gwt/work/events/6f/6f5ed846e86ffd579cd4f0b7ab48d5ff55c1bcf33ef1a62641fff9214bf69dae.jsonl @@ -0,0 +1 @@ +{"id":"c5600ee3-4c19-45a8-b97d-c48a355bbf2e","work_item_id":"work-work-issue-516-59f2c1be","kind":"start","title":"Issue #516","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #516","next_action":"Check Board for latest updates","agent_session_id":"2422daaa-fb2e-42af-a9de-476f61a2dc84","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T00:38:53.802182Z"} diff --git a/.gwt/work/events/79/792461313595178b02462ac3e615640b8b798b38b5ce45f19a43e6a3ff1631f1.jsonl b/.gwt/work/events/79/792461313595178b02462ac3e615640b8b798b38b5ce45f19a43e6a3ff1631f1.jsonl new file mode 100644 index 00000000..7118f4a2 --- /dev/null +++ b/.gwt/work/events/79/792461313595178b02462ac3e615640b8b798b38b5ce45f19a43e6a3ff1631f1.jsonl @@ -0,0 +1 @@ +{"id":"e8b05b9a-1a0f-463f-9ed7-1cfc93469731","work_item_id":"work-successor-7c2dfc5d2b5cce43936b35438f6127d998d532280cf12c1dd034899b09313645","kind":"start","title":"fix(lsp): normalize lone CR in edits to the file's newline style for LF and CRLF files","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #516","next_action":"Check Board for latest updates","agent_session_id":"efd1f1c5-7a52-4d29-9970-e43f2e9a9519","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":"work-work-issue-516-59f2c1be","updated_at":"2026-10-14T01:44:06.698532Z"} diff --git a/.gwt/work/events/98/985343f37d9890b38f154f4201bcc76343fd387167eb1dfc6b35da38c8c88e66.jsonl b/.gwt/work/events/98/985343f37d9890b38f154f4201bcc76343fd387167eb1dfc6b35da38c8c88e66.jsonl new file mode 100644 index 00000000..304f3eac --- /dev/null +++ b/.gwt/work/events/98/985343f37d9890b38f154f4201bcc76343fd387167eb1dfc6b35da38c8c88e66.jsonl @@ -0,0 +1 @@ +{"id":"71dc8444-f077-41c3-9527-443c381b504a","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":"verify.run(TMPDIR=/tmp)と PR CI の完了待ち","summary":"verify.run を再実行中です(3 回目)。PR CI は残り 3 件です。","progress_summary":"ApplyNewlines で単独 CR を行終端子として正規化しました(文字列リテラル内の CR は保持)。3×3 改行行列テストとリテラルテストを追加し、LSP テストは 229 件合格です。Draft PR #517 を作成しました。macOS の書き込み信頼性ゲートは checkout LSP の条件で 100% です。verify.run の cargo test 失敗は、verify の長い TMPDIR が Unix socket パス制限を超えるという環境要因と特定しました。TMPDIR=/tmp を付けて再実行しています。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"2422daaa-fb2e-42af-a9de-476f61a2dc84","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":517,"pr_url":"https://github.com/akiojin/unity-cli/pull/517","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T01:03:23.908908Z"} diff --git a/.gwt/work/events/9d/9d86038043fa672eed535443166fd5dfd5e5b07bd95611ee614f760823af2cb0.jsonl b/.gwt/work/events/9d/9d86038043fa672eed535443166fd5dfd5e5b07bd95611ee614f760823af2cb0.jsonl new file mode 100644 index 00000000..0577de0a --- /dev/null +++ b/.gwt/work/events/9d/9d86038043fa672eed535443166fd5dfd5e5b07bd95611ee614f760823af2cb0.jsonl @@ -0,0 +1 @@ +{"id":"da62bab5-67c1-48bf-abd5-cfc9d10d2a4a","work_item_id":"work-work-issue-516-59f2c1be","kind":"resume","title":"fix(lsp): normalize lone CR in edits to the file's newline style for LF and CRLF files","intent":"verify.run を実行中です。PR CI も待っています。","summary":"2 active agents","progress_summary":null,"status_category":"active","owner":"Issue #516","next_action":"Check Board for latest updates","agent_session_id":"09be6709-cd11-44d6-9b30-8fdea359c0ef","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T00:58:43.869889Z"} diff --git a/.gwt/work/events/a7/a7ac6a6e9f002714e266210435aeb76900d77e23e5611ee84ee50e8fef642639.jsonl b/.gwt/work/events/a7/a7ac6a6e9f002714e266210435aeb76900d77e23e5611ee84ee50e8fef642639.jsonl new file mode 100644 index 00000000..cb8802ab --- /dev/null +++ b/.gwt/work/events/a7/a7ac6a6e9f002714e266210435aeb76900d77e23e5611ee84ee50e8fef642639.jsonl @@ -0,0 +1 @@ +{"id":"16925dea-044b-451d-81e2-b5d2f12f3b3d","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":"verify.run(再実行)と PR CI の完了待ち","summary":"プロジェクト品質ゲート(--test-threads=1)で verify.run を再実行中です。","progress_summary":"ApplyNewlines で単独 CR を行終端子として正規化しました(文字列リテラル内の CR は保持)。3×3 改行行列テストとリテラルテストを追加し、LSP テストは 229 件合格です。Draft PR #517 を作成しました。ローカル macOS の書き込み信頼性ゲートは、checkout LSP の条件で 100% でした。derived matrix の verify.run は、並列実行の cargo test で daemon 系テストが失敗しました。単一スレッドでは全件合格です(変更していない Rust コードの環境要因)。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"2422daaa-fb2e-42af-a9de-476f61a2dc84","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":517,"pr_url":"https://github.com/akiojin/unity-cli/pull/517","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T01:00:43.049416Z"} diff --git a/.gwt/work/events/af/afade077dd64ef32dddfd526ea6a0e174992f8ac171907a5ab55aedcfe836a73.jsonl b/.gwt/work/events/af/afade077dd64ef32dddfd526ea6a0e174992f8ac171907a5ab55aedcfe836a73.jsonl new file mode 100644 index 00000000..b20038a5 --- /dev/null +++ b/.gwt/work/events/af/afade077dd64ef32dddfd526ea6a0e174992f8ac171907a5ab55aedcfe836a73.jsonl @@ -0,0 +1 @@ +{"id":"a159f90c-fea6-4070-a8ac-5dab1e86852c","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":"PR #517 の CI 待ち","summary":null,"progress_summary":"ApplyNewlines で単独 CR を行終端として正規化(文字列リテラル内は保持)。9 通り行列テストとリテラルテストを追加、LSP テスト 229 件合格。Draft PR #517 作成。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"2422daaa-fb2e-42af-a9de-476f61a2dc84","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":517,"pr_url":"https://github.com/akiojin/unity-cli/pull/517","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T00:55:19.883034Z"} diff --git a/.gwt/work/events/b5/b5d75d20837cdbfe8ea439dbd4d88fb6590a3c7ad37297584d6cb01335c81218.jsonl b/.gwt/work/events/b5/b5d75d20837cdbfe8ea439dbd4d88fb6590a3c7ad37297584d6cb01335c81218.jsonl new file mode 100644 index 00000000..a711ddb9 --- /dev/null +++ b/.gwt/work/events/b5/b5d75d20837cdbfe8ea439dbd4d88fb6590a3c7ad37297584d6cb01335c81218.jsonl @@ -0,0 +1 @@ +{"id":"f729ada6-8b65-49ef-b62b-46b95036194e","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":"verify.run と PR CI の完了待ち","summary":"verify.run を実行中です。PR CI も待っています。","progress_summary":"ApplyNewlines で単独 CR を行終端子として正規化しました(文字列リテラル内の CR は保持)。3×3 改行行列テストとリテラルテストを追加し、LSP テストは 229 件合格です。Draft PR #517 を作成しました。ローカル macOS の書き込み信頼性ゲートは、checkout LSP を使う 2 条件(warm_indexed / unindexed)が全シナリオ 100%、baseline 判定は exit 0 です。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"2422daaa-fb2e-42af-a9de-476f61a2dc84","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":517,"pr_url":"https://github.com/akiojin/unity-cli/pull/517","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T00:57:27.920652Z"} diff --git a/.gwt/work/events/c2/c272cda4b82a1e0c01d54f9ec52168270b59a40c0244106531add4bb6760242d.jsonl b/.gwt/work/events/c2/c272cda4b82a1e0c01d54f9ec52168270b59a40c0244106531add4bb6760242d.jsonl new file mode 100644 index 00000000..ba312030 --- /dev/null +++ b/.gwt/work/events/c2/c272cda4b82a1e0c01d54f9ec52168270b59a40c0244106531add4bb6760242d.jsonl @@ -0,0 +1 @@ +{"id":"3790a9c8-40b7-448d-87a6-54d2a455aad9","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":"Issue #516 の実装と develop への配信","intent":"受け入れ基準の評価","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"2422daaa-fb2e-42af-a9de-476f61a2dc84","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T00:39:08.831132Z"} diff --git a/.gwt/work/events/ee/eeb5d58edef74597116a67bb02a7d085199df22202724e9325546b959d6a0a24.jsonl b/.gwt/work/events/ee/eeb5d58edef74597116a67bb02a7d085199df22202724e9325546b959d6a0a24.jsonl new file mode 100644 index 00000000..5905b169 --- /dev/null +++ b/.gwt/work/events/ee/eeb5d58edef74597116a67bb02a7d085199df22202724e9325546b959d6a0a24.jsonl @@ -0,0 +1 @@ +{"id":"382dbfc9-2d5a-45d0-849c-04ea8004e8e0","work_item_id":"work-successor-7c2dfc5d2b5cce43936b35438f6127d998d532280cf12c1dd034899b09313645","kind":"done","title":null,"intent":"受け入れ基準を origin/develop で確認済み","summary":null,"progress_summary":"work/issue-516 は origin/develop (69ad5ab) と同一で、未配送のコミットはない。修正 d3359d6 (PR #517) は develop にマージ済みで、CI は全 green (LSP Write Reliability 3 OS を含む)。ローカルの dotnet test は 229 件すべて pass。3x3 改行マトリクスのテスト (NewlineMatrix) と文字列リテラル内 CR のテスト (ApplyNewlines_KeepsLoneCrInsideStringLiterals) があることを確認。AC-1〜3 はすべて満たしている。新しい PR は不要。Issue は手動で close せず、release PR で自動 close させる。","status_category":"done","owner":"Issue #516","next_action":null,"agent_session_id":"efd1f1c5-7a52-4d29-9970-e43f2e9a9519","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T01:45:03.057639Z"} From 22de2819b57f8bbc902ff66277f1324bddf92c74 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 11:07:39 +0900 Subject: [PATCH 59/73] fix(lsp): parse each preprocessor branch in isolation for string CRs An unterminated comment or string in one branch no longer changes how another branch is lexed: each inactive branch is re-parsed alone in a same-length copy with the group's directives and sibling branches blanked. Co-Authored-By: Claude Opus 5.5 --- ...4ce29d4868294f9548f10c9f2ec4dad54949.jsonl | 1 + lsp/Server.Core/LspSourceFile.cs | 63 ++++++++++++------- lsp/SourceFileFormatTests.cs | 5 ++ 3 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 .gwt/work/events/d1/d11d070eaa16ffde4327dd6732584ce29d4868294f9548f10c9f2ec4dad54949.jsonl diff --git a/.gwt/work/events/d1/d11d070eaa16ffde4327dd6732584ce29d4868294f9548f10c9f2ec4dad54949.jsonl b/.gwt/work/events/d1/d11d070eaa16ffde4327dd6732584ce29d4868294f9548f10c9f2ec4dad54949.jsonl new file mode 100644 index 00000000..b6cb858c --- /dev/null +++ b/.gwt/work/events/d1/d11d070eaa16ffde4327dd6732584ce29d4868294f9548f10c9f2ec4dad54949.jsonl @@ -0,0 +1 @@ +{"id":"9a40c654-fc4c-4e24-aa65-83557e570316","work_item_id":"work-successor-7c2dfc5d2b5cce43936b35438f6127d998d532280cf12c1dd034899b09313645","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"done","owner":null,"next_action":null,"agent_session_id":"efd1f1c5-7a52-4d29-9970-e43f2e9a9519","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-516","pr_number":518,"pr_url":"https://github.com/akiojin/unity-cli/pull/518","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T01:49:14.247281Z"} diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 1377e6e4..dabe9218 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; namespace UnityCli.Lsp.Core; @@ -52,39 +55,55 @@ public string ApplyNewlines(string text) private static HashSet FindLoneCrsInStringLiterals(string text) { var positions = new HashSet(); - // Inspect every preprocessor branch, independent of the current project's symbols. - // Keep positions identical to the original text, including directive-looking string lines. - var syntaxText = CommentOutDirectivePrefixes(text); - foreach (var token in CSharpSyntaxTree.ParseText(syntaxText).GetRoot().DescendantTokens(descendIntoTrivia: true)) + CollectLoneCrsInStringLiterals(text, text, new TextSpan(0, text.Length), positions); + return positions; + } + + // Inspect every preprocessor branch, independent of the current project's symbols. Each inactive + // branch is re-parsed alone in a same-length copy, so another branch's lexical state (an + // unterminated comment or string) cannot change how it is read, and nested directives are + // resolved as they would be with that branch active. + private static void CollectLoneCrsInStringLiterals(string text, string syntaxText, TextSpan scope, HashSet positions) + { + var root = CSharpSyntaxTree.ParseText(syntaxText).GetRoot(); + foreach (var token in root.DescendantTokens()) { if (!IsMultiLineStringContent(token.Kind())) continue; - for (var i = token.SpanStart; i < token.Span.End; i++) + var span = token.Span.Intersection(scope); + if (span is null) continue; + for (var i = span.Value.Start; i < span.Value.End; i++) { if (text[i] == '\r' && (i + 1 >= text.Length || text[i + 1] != '\n')) positions.Add(i); } } - return positions; - } - private static string CommentOutDirectivePrefixes(string text) - { - var chars = text.ToCharArray(); - var lineStart = true; - for (var i = 0; i < chars.Length; i++) + foreach (var directive in root.DescendantNodes(descendIntoTrivia: true).OfType()) { - var c = chars[i]; - if (IsLineBreak(c)) { lineStart = true; continue; } - if (lineStart && char.IsWhiteSpace(c)) continue; - if (lineStart && c == '#' && i + 1 < chars.Length && - (char.IsLetter(chars[i + 1]) || (char.IsWhiteSpace(chars[i + 1]) && !IsLineBreak(chars[i + 1])))) + if (!directive.IsActive || !scope.Contains(directive.Span)) continue; + var group = directive.GetRelatedDirectives(); + for (var b = 0; b + 1 < group.Count; b++) { - // Replace only the prefix: a quote after '#' inside a literal must stay intact. - chars[i] = '/'; - chars[i + 1] = '/'; + if (group[b] is BranchingDirectiveTriviaSyntax { BranchTaken: true }) continue; + var branch = TextSpan.FromBounds(group[b].FullSpan.End, group[b + 1].FullSpan.Start); + var chars = syntaxText.ToCharArray(); + for (var g = 0; g + 1 < group.Count; g++) + { + Blank(chars, group[g].Span); + if (g != b) Blank(chars, TextSpan.FromBounds(group[g].FullSpan.End, group[g + 1].FullSpan.Start)); + } + Blank(chars, group[^1].Span); + CollectLoneCrsInStringLiterals(text, new string(chars), branch, positions); } - lineStart = false; } - return new string(chars); + } + + // Replace with spaces but keep line breaks, so every position still maps to the original text. + private static void Blank(char[] chars, TextSpan span) + { + for (var i = span.Start; i < span.End; i++) + { + if (!IsLineBreak(chars[i])) chars[i] = ' '; + } } private static bool IsLineBreak(char c) => c is '\r' or '\n' or '\u0085' or '\u2028' or '\u2029'; diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 9596b719..6e49da57 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -214,6 +214,11 @@ public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string origi [InlineData("\n", "var a = @\"x\r#\";\r", "var a = @\"x\r#\";\n")] [InlineData("\n", "#\fif UNITY_EDITOR\nvar a = @\"x\ry\";\r#endif\n", "#\fif UNITY_EDITOR\nvar a = @\"x\ry\";\n#endif\n")] [InlineData("\n", "#\u00a0if UNITY_EDITOR\nvar a = @\"x\ry\";\r#endif\n", "#\u00a0if UNITY_EDITOR\nvar a = @\"x\ry\";\n#endif\n")] + // An unterminated comment or string in one branch must not change how another branch is lexed. + [InlineData("\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n")] + [InlineData("\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n")] + [InlineData("\n", "#if UNITY_EDITOR\nvar b = @\"\n#else\nvar a = 1;\n#endif\nvar c = @\"x\ry\";\r", "#if UNITY_EDITOR\nvar b = @\"\n#else\nvar a = 1;\n#endif\nvar c = @\"x\ry\";\n")] + [InlineData("\r\n", "#if UNITY_EDITOR\nvar b = \"\"\"\n#endif\nvar a = 1;\rvar c = @\"x\ry\";\n", "#if UNITY_EDITOR\r\nvar b = \"\"\"\r\n#endif\r\nvar a = 1;\r\nvar c = @\"x\ry\";\r\n")] public void ApplyNewlines_KeepsLoneCrInsideStringLiterals(string originalNewline, string text, string expected) { var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a" + originalNewline + "b" + originalNewline)); From 02dbdea017b30c50a861d2ce2a86f22679593c19 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 11:15:49 +0900 Subject: [PATCH 60/73] fix(lsp): activate each skipped branch to find its real extent A directive-looking line inside a string of an inactive branch is string content once that branch is active. Re-parse each skipped branch from its directive, rewritten to an always-true #if, in a doubling window so the parser decides where the branch ends; follow the sibling it reveals. Co-Authored-By: Claude Opus 5.5 --- lsp/Server.Core/LspSourceFile.cs | 95 +++++++++++++++++++------------- lsp/SourceFileFormatTests.cs | 17 ++++++ 2 files changed, 75 insertions(+), 37 deletions(-) diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index dabe9218..c0405436 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -52,62 +52,83 @@ public string ApplyNewlines(string text) return result.ToString(); } + private const string ActiveSymbol = "_"; + private const string ActiveDirective = "#if " + ActiveSymbol; + private static readonly CSharpParseOptions ActiveBranchOptions = CSharpParseOptions.Default.WithPreprocessorSymbols(ActiveSymbol); + private static HashSet FindLoneCrsInStringLiterals(string text) { - var positions = new HashSet(); - CollectLoneCrsInStringLiterals(text, text, new TextSpan(0, text.Length), positions); - return positions; + var scan = new LiteralCrScan(text, new HashSet(), new HashSet()); + scan.Collect(0, CSharpSyntaxTree.ParseText(text).GetRoot(), new TextSpan(0, text.Length)); + return scan.Positions; } - // Inspect every preprocessor branch, independent of the current project's symbols. Each inactive - // branch is re-parsed alone in a same-length copy, so another branch's lexical state (an - // unterminated comment or string) cannot change how it is read, and nested directives are - // resolved as they would be with that branch active. - private static void CollectLoneCrsInStringLiterals(string text, string syntaxText, TextSpan scope, HashSet positions) + // Inspects every preprocessor branch, independent of the current project's symbols. Each branch a + // parse skipped is parsed again on its own with that branch active, so the parser decides where the + // branch really ends (a directive-looking line inside its strings is string content) and no other + // branch's lexical state (an unterminated comment or string) reaches it. Positions are offsets into + // Text; Activated holds the branch directives already parsed that way, so each is parsed once. + private readonly record struct LiteralCrScan(string Text, HashSet Positions, HashSet Activated) { - var root = CSharpSyntaxTree.ParseText(syntaxText).GetRoot(); - foreach (var token in root.DescendantTokens()) + public void Collect(int offset, SyntaxNode root, TextSpan scope) { - if (!IsMultiLineStringContent(token.Kind())) continue; - var span = token.Span.Intersection(scope); - if (span is null) continue; - for (var i = span.Value.Start; i < span.Value.End; i++) + foreach (var token in root.DescendantTokens()) { - if (text[i] == '\r' && (i + 1 >= text.Length || text[i + 1] != '\n')) positions.Add(i); + if (!IsMultiLineStringContent(token.Kind())) continue; + var span = token.Span.Intersection(scope); + if (span is null) continue; + for (var i = offset + span.Value.Start; i < offset + span.Value.End; i++) + { + if (Text[i] == '\r' && (i + 1 >= Text.Length || Text[i + 1] != '\n')) Positions.Add(i); + } } - } - foreach (var directive in root.DescendantNodes(descendIntoTrivia: true).OfType()) - { - if (!directive.IsActive || !scope.Contains(directive.Span)) continue; - var group = directive.GetRelatedDirectives(); - for (var b = 0; b + 1 < group.Count; b++) + foreach (var directive in root.DescendantNodes(descendIntoTrivia: true).OfType()) { - if (group[b] is BranchingDirectiveTriviaSyntax { BranchTaken: true }) continue; - var branch = TextSpan.FromBounds(group[b].FullSpan.End, group[b + 1].FullSpan.Start); - var chars = syntaxText.ToCharArray(); - for (var g = 0; g + 1 < group.Count; g++) + if (!directive.IsActive || !scope.Contains(directive.Span)) continue; + var group = directive.GetRelatedDirectives(); + for (var b = 0; b < group.Count; b++) { - Blank(chars, group[g].Span); - if (g != b) Blank(chars, TextSpan.FromBounds(group[g].FullSpan.End, group[g + 1].FullSpan.Start)); + var end = b + 1 < group.Count ? group[b + 1].FullSpan.Start : scope.End; + if (group[b] is BranchingDirectiveTriviaSyntax { BranchTaken: false }) Activate(offset, group[b], offset + end); } - Blank(chars, group[^1].Span); - CollectLoneCrsInStringLiterals(text, new string(chars), branch, positions); } } - } - // Replace with spaces but keep line breaks, so every position still maps to the original text. - private static void Blank(char[] chars, TextSpan span) - { - for (var i = span.Start; i < span.End; i++) + // Parses the text from a skipped branch's directive onward, with that directive rewritten in place + // to an always-true "#if" (every #if/#elif/#else directive is at least as long). The window doubles + // until the branch's next directive is fully inside it, so the cost follows the branch size. That + // next #elif/#else is followed too: a directive inside a string can hide it from the outer parse. + // A branch that never closes once active is not valid C# that way; it keeps the outer extent. + private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd) { - if (!IsLineBreak(chars[i])) chars[i] = ' '; + // A malformed directive (a bare "#if") is too short to rewrite; it is not valid C# anyway. + var start = offset + directive.Span.Start; + if (directive.Span.Length < ActiveDirective.Length || !Activated.Add(start)) return; + for (var length = 256; ; length *= 2) + { + var end = (int)Math.Min(Text.Length, (long)start + length); + var window = ActiveDirective + new string(' ', directive.Span.Length - ActiveDirective.Length) + Text[(start + directive.Span.Length)..end]; + var root = CSharpSyntaxTree.ParseText(window, ActiveBranchOptions).GetRoot(); + var opening = root.DescendantNodes(descendIntoTrivia: true).OfType().First(); + var group = opening.GetRelatedDirectives(); + var complete = end == Text.Length; + if (group.Count > 1 && (complete || group[1].FullSpan.End < window.Length)) + { + Collect(start, root, TextSpan.FromBounds(opening.FullSpan.End, group[1].FullSpan.Start)); + var next = group.Count > 2 ? group[2].FullSpan.Start : window.Length; + if (group[1] is BranchingDirectiveTriviaSyntax) Activate(start, group[1], start + next); + return; + } + if (complete) + { + Collect(start, root, TextSpan.FromBounds(opening.FullSpan.End, Math.Max(opening.FullSpan.End, outerEnd - start))); + return; + } + } } } - private static bool IsLineBreak(char c) => c is '\r' or '\n' or '\u0085' or '\u2028' or '\u2029'; - // Only verbatim, raw, and interpolated text can span lines; a CR ends any other literal. private static bool IsMultiLineStringContent(SyntaxKind kind) => kind is SyntaxKind.StringLiteralToken or SyntaxKind.Utf8StringLiteralToken or diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 6e49da57..d408b9dd 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -214,6 +214,12 @@ public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string origi [InlineData("\n", "var a = @\"x\r#\";\r", "var a = @\"x\r#\";\n")] [InlineData("\n", "#\fif UNITY_EDITOR\nvar a = @\"x\ry\";\r#endif\n", "#\fif UNITY_EDITOR\nvar a = @\"x\ry\";\n#endif\n")] [InlineData("\n", "#\u00a0if UNITY_EDITOR\nvar a = @\"x\ry\";\r#endif\n", "#\u00a0if UNITY_EDITOR\nvar a = @\"x\ry\";\n#endif\n")] + // A directive-looking line inside a string of an inactive branch is string content once that branch is active. + [InlineData("\n", "#if A\nvar a = @\"x\r#elif false\r\";\n#endif\n", "#if A\nvar a = @\"x\r#elif false\r\";\n#endif\n")] + [InlineData("\n", "#if A\nvar a = @\"x\r#else\ry\";\n#endif\n", "#if A\nvar a = @\"x\r#else\ry\";\n#endif\n")] + [InlineData("\n", "#if A\nvar a = @\"x\r#endif\ry\";\n#endif\n", "#if A\nvar a = @\"x\r#endif\ry\";\n#endif\n")] + [InlineData("\r\n", "#if false\nvar a = \"\"\"\n x\r #if B\r \"\"\";\n#else\nvar a = $@\"x\r#else\r{1}\";\n#endif\n", "#if false\r\nvar a = \"\"\"\r\n x\r #if B\r \"\"\";\r\n#else\r\nvar a = $@\"x\r#else\r{1}\";\r\n#endif\r\n")] + [InlineData("\n", "#if A\n#if B\nvar a = @\"x\r#elif C\r#endif\ry\";\n#endif\n#endif\n", "#if A\n#if B\nvar a = @\"x\r#elif C\r#endif\ry\";\n#endif\n#endif\n")] // An unterminated comment or string in one branch must not change how another branch is lexed. [InlineData("\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n")] [InlineData("\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n")] @@ -226,6 +232,17 @@ public void ApplyNewlines_KeepsLoneCrInsideStringLiterals(string originalNewline Assert.Equal(expected, format.ApplyNewlines(text)); } + [Fact] + public void ApplyNewlines_HandlesMalformedDirectivesAndManyBranches() + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + Assert.Equal("#if\nvar a = 1;\n#endif\n", format.ApplyNewlines("#if\rvar a = 1;\r#endif\r")); + + var block = "#if A\nvar a = @\"x\r#else\ry\";\n#else\nvar b = 1;\r#endif\n"; + var input = string.Concat(Enumerable.Repeat(block, 400)); + Assert.Equal(string.Concat(Enumerable.Repeat(block.Replace(";\r#endif", ";\n#endif"), 400)), format.ApplyNewlines(input)); + } + public static TheoryData InactiveBranchStrings() { var data = new TheoryData(); From f5118157621d36116e14aaed0b2b1c793a1bce60 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 11:27:21 +0900 Subject: [PATCH 61/73] perf(lsp): skip string-literal parsing when input has no lone CR Co-Authored-By: Claude Opus 5.5 --- lsp/Server.Core/LspSourceFile.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index c0405436..927c57b2 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -39,7 +39,7 @@ public static (string Text, LspSourceFileFormat Format) Decode(byte[] bytes) public string ApplyNewlines(string text) { if (NewLine is null) return text; - var literalCrs = text.Contains('\r') ? FindLoneCrsInStringLiterals(text) : null; + var literalCrs = HasLoneCr(text) ? FindLoneCrsInStringLiterals(text) : null; var result = new StringBuilder(text.Length); for (var i = 0; i < text.Length; i++) { @@ -52,6 +52,16 @@ public string ApplyNewlines(string text) return result.ToString(); } + // Plain CRLF input has no lone CR to classify, so it skips parsing. + private static bool HasLoneCr(string text) + { + for (var i = text.IndexOf('\r'); i >= 0; i = text.IndexOf('\r', i + 1)) + { + if (i + 1 >= text.Length || text[i + 1] != '\n') return true; + } + return false; + } + private const string ActiveSymbol = "_"; private const string ActiveDirective = "#if " + ActiveSymbol; private static readonly CSharpParseOptions ActiveBranchOptions = CSharpParseOptions.Default.WithPreprocessorSymbols(ActiveSymbol); From d435a0be7799e6d493480def5da77260391df5e7 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 11:46:03 +0900 Subject: [PATCH 62/73] fix(lsp): handle long branch directives and fake directive paths The activation window now always holds the whole directive, so an #elif/#else longer than the first window no longer throws. When an activated branch ends past the directive the outer parse stopped at, strings the outer parse started in between are dropped: that stretch is string content once the branch is active. Co-Authored-By: Claude Opus 5.5 --- lsp/Server.Core/LspSourceFile.cs | 53 +++++++++++++++++++++++--------- lsp/SourceFileFormatTests.cs | 19 ++++++++++++ 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 927c57b2..7806fd3b 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -68,30 +68,47 @@ private static bool HasLoneCr(string text) private static HashSet FindLoneCrsInStringLiterals(string text) { - var scan = new LiteralCrScan(text, new HashSet(), new HashSet()); + var scan = new LiteralCrScan(text, new List(), new HashSet()); scan.Collect(0, CSharpSyntaxTree.ParseText(text).GetRoot(), new TextSpan(0, text.Length)); - return scan.Positions; + var positions = new HashSet(); + foreach (var run in scan.Runs) + { + if (run.Dropped) continue; + for (var i = run.Start; i < run.End; i++) + { + if (text[i] == '\r' && (i + 1 >= text.Length || text[i + 1] != '\n')) positions.Add(i); + } + } + return positions; + } + + // Offsets into the original text of string content that one parse found; TokenStart is where the + // token begins, so a parse that misread the region holding that start can drop the whole token. + private sealed class StringRun(int tokenStart, int start, int end) + { + public int TokenStart { get; } = tokenStart; + public int Start { get; } = start; + public int End { get; } = end; + public bool Dropped { get; set; } } // Inspects every preprocessor branch, independent of the current project's symbols. Each branch a // parse skipped is parsed again on its own with that branch active, so the parser decides where the // branch really ends (a directive-looking line inside its strings is string content) and no other - // branch's lexical state (an unterminated comment or string) reaches it. Positions are offsets into - // Text; Activated holds the branch directives already parsed that way, so each is parsed once. - private readonly record struct LiteralCrScan(string Text, HashSet Positions, HashSet Activated) + // branch's lexical state (an unterminated comment or string) reaches it. Activated holds the branch + // directives already parsed that way, so each is parsed once. + private readonly record struct LiteralCrScan(string Text, List Runs, HashSet Activated) { public void Collect(int offset, SyntaxNode root, TextSpan scope) { + var runs = new List(); foreach (var token in root.DescendantTokens()) { if (!IsMultiLineStringContent(token.Kind())) continue; var span = token.Span.Intersection(scope); - if (span is null) continue; - for (var i = offset + span.Value.Start; i < offset + span.Value.End; i++) - { - if (Text[i] == '\r' && (i + 1 >= Text.Length || Text[i + 1] != '\n')) Positions.Add(i); - } + if (span is not null) runs.Add(new StringRun(offset + token.SpanStart, offset + span.Value.Start, offset + span.Value.End)); } + Runs.AddRange(runs); foreach (var directive in root.DescendantNodes(descendIntoTrivia: true).OfType()) { @@ -100,7 +117,7 @@ public void Collect(int offset, SyntaxNode root, TextSpan scope) for (var b = 0; b < group.Count; b++) { var end = b + 1 < group.Count ? group[b + 1].FullSpan.Start : scope.End; - if (group[b] is BranchingDirectiveTriviaSyntax { BranchTaken: false }) Activate(offset, group[b], offset + end); + if (group[b] is BranchingDirectiveTriviaSyntax { BranchTaken: false }) Activate(offset, group[b], offset + end, runs); } } } @@ -109,13 +126,16 @@ public void Collect(int offset, SyntaxNode root, TextSpan scope) // to an always-true "#if" (every #if/#elif/#else directive is at least as long). The window doubles // until the branch's next directive is fully inside it, so the cost follows the branch size. That // next #elif/#else is followed too: a directive inside a string can hide it from the outer parse. + // When the branch ends past where the outer parse ended it, the outer parse read that stretch as + // code after a directive that is really string content; its strings starting there are dropped. // A branch that never closes once active is not valid C# that way; it keeps the outer extent. - private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd) + private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd, List outerRuns) { // A malformed directive (a bare "#if") is too short to rewrite; it is not valid C# anyway. var start = offset + directive.Span.Start; if (directive.Span.Length < ActiveDirective.Length || !Activated.Add(start)) return; - for (var length = 256; ; length *= 2) + // The window always holds the whole directive, however long its condition or comment is. + for (var length = directive.Span.Length + 256; ; length *= 2) { var end = (int)Math.Min(Text.Length, (long)start + length); var window = ActiveDirective + new string(' ', directive.Span.Length - ActiveDirective.Length) + Text[(start + directive.Span.Length)..end]; @@ -125,9 +145,14 @@ private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd) var complete = end == Text.Length; if (group.Count > 1 && (complete || group[1].FullSpan.End < window.Length)) { + var branchEnd = start + group[1].FullSpan.Start; + foreach (var run in outerRuns) + { + if (run.TokenStart >= outerEnd && run.TokenStart < branchEnd) run.Dropped = true; + } Collect(start, root, TextSpan.FromBounds(opening.FullSpan.End, group[1].FullSpan.Start)); var next = group.Count > 2 ? group[2].FullSpan.Start : window.Length; - if (group[1] is BranchingDirectiveTriviaSyntax) Activate(start, group[1], start + next); + if (group[1] is BranchingDirectiveTriviaSyntax) Activate(start, group[1], start + next, new List()); return; } if (complete) diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index d408b9dd..64b7234e 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -220,6 +220,12 @@ public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string origi [InlineData("\n", "#if A\nvar a = @\"x\r#endif\ry\";\n#endif\n", "#if A\nvar a = @\"x\r#endif\ry\";\n#endif\n")] [InlineData("\r\n", "#if false\nvar a = \"\"\"\n x\r #if B\r \"\"\";\n#else\nvar a = $@\"x\r#else\r{1}\";\n#endif\n", "#if false\r\nvar a = \"\"\"\r\n x\r #if B\r \"\"\";\r\n#else\r\nvar a = $@\"x\r#else\r{1}\";\r\n#endif\r\n")] [InlineData("\n", "#if A\n#if B\nvar a = @\"x\r#elif C\r#endif\ry\";\n#endif\n#endif\n", "#if A\n#if B\nvar a = @\"x\r#elif C\r#endif\ry\";\n#endif\n#endif\n")] + // A fake #endif inside a skipped branch's string: what follows is code in the configuration where the branch is skipped. + [InlineData("\n", "#if false\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if false\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] + [InlineData("\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] + [InlineData("\r\n", "#if A\nvar s = @\"\n#elif B\nx\"\"@\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\r\nvar s = @\"\r\n#elif B\r\nx\"\"@\"\";\r\nvar a = 1;\r\nvar b = 2;\r\n#endif\r\n")] + [InlineData("\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] + [InlineData("\n", "#if A\nvar s = @\"\n#endif\nvar t = \"\"+@\"\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nvar s = @\"\n#endif\nvar t = \"\"+@\"\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] // An unterminated comment or string in one branch must not change how another branch is lexed. [InlineData("\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n")] [InlineData("\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n")] @@ -243,6 +249,19 @@ public void ApplyNewlines_HandlesMalformedDirectivesAndManyBranches() Assert.Equal(string.Concat(Enumerable.Repeat(block.Replace(";\r#endif", ";\n#endif"), 400)), format.ApplyNewlines(input)); } + [Fact] + public void ApplyNewlines_ActivatesBranchesWithDirectivesLongerThanTheFirstWindow() + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + var condition = string.Join(" || ", Enumerable.Range(0, 60).Select(i => "SYMBOL_" + i)); + foreach (var directive in new[] { "#elif " + condition, "#else // " + new string('x', 300) }) + { + var input = "#if false\nvar a = 1;\r" + directive + "\nvar b = @\"x\ry\";\r#endif\n"; + Assert.True(directive.Length > 256); + Assert.Equal("#if false\nvar a = 1;\n" + directive + "\nvar b = @\"x\ry\";\n#endif\n", format.ApplyNewlines(input)); + } + } + public static TheoryData InactiveBranchStrings() { var data = new TheoryData(); From 653d81af87ce61a6fc846ca553d8c076326478bd Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 11:59:49 +0900 Subject: [PATCH 63/73] fix(lsp): keep CRs any well-formed parse reads as string content Replace the fake-path drop rule with the PM ruling: a lone CR is kept when any configuration's parse reads it inside a string, except string tokens that are unterminated literals (CS1039, CS8997, or an interpolated string missing its end), whose extent is not valid C# in that configuration. Co-Authored-By: Claude Opus 5.5 --- lsp/Server.Core/LspSourceFile.cs | 64 +++++++++++++------------------- lsp/SourceFileFormatTests.cs | 8 ++++ 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 7806fd3b..54082aca 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -68,47 +68,32 @@ private static bool HasLoneCr(string text) private static HashSet FindLoneCrsInStringLiterals(string text) { - var scan = new LiteralCrScan(text, new List(), new HashSet()); + var scan = new LiteralCrScan(text, new HashSet(), new HashSet()); scan.Collect(0, CSharpSyntaxTree.ParseText(text).GetRoot(), new TextSpan(0, text.Length)); - var positions = new HashSet(); - foreach (var run in scan.Runs) - { - if (run.Dropped) continue; - for (var i = run.Start; i < run.End; i++) - { - if (text[i] == '\r' && (i + 1 >= text.Length || text[i + 1] != '\n')) positions.Add(i); - } - } - return positions; - } - - // Offsets into the original text of string content that one parse found; TokenStart is where the - // token begins, so a parse that misread the region holding that start can drop the whole token. - private sealed class StringRun(int tokenStart, int start, int end) - { - public int TokenStart { get; } = tokenStart; - public int Start { get; } = start; - public int End { get; } = end; - public bool Dropped { get; set; } + return scan.Positions; } // Inspects every preprocessor branch, independent of the current project's symbols. Each branch a // parse skipped is parsed again on its own with that branch active, so the parser decides where the // branch really ends (a directive-looking line inside its strings is string content) and no other - // branch's lexical state (an unterminated comment or string) reaches it. Activated holds the branch - // directives already parsed that way, so each is parsed once. - private readonly record struct LiteralCrScan(string Text, List Runs, HashSet Activated) + // branch's lexical state (an unterminated comment or string) reaches it. A lone CR is kept when any + // of these parses reads it inside a well-formed string; an unterminated string token is not valid C# + // in that configuration and keeps nothing. Positions are + // offsets into Text; Activated holds the branch directives already parsed, so each is parsed once. + private readonly record struct LiteralCrScan(string Text, HashSet Positions, HashSet Activated) { public void Collect(int offset, SyntaxNode root, TextSpan scope) { - var runs = new List(); foreach (var token in root.DescendantTokens()) { - if (!IsMultiLineStringContent(token.Kind())) continue; + if (!IsMultiLineStringContent(token.Kind()) || HasError(token)) continue; var span = token.Span.Intersection(scope); - if (span is not null) runs.Add(new StringRun(offset + token.SpanStart, offset + span.Value.Start, offset + span.Value.End)); + if (span is null) continue; + for (var i = offset + span.Value.Start; i < offset + span.Value.End; i++) + { + if (Text[i] == '\r' && (i + 1 >= Text.Length || Text[i + 1] != '\n')) Positions.Add(i); + } } - Runs.AddRange(runs); foreach (var directive in root.DescendantNodes(descendIntoTrivia: true).OfType()) { @@ -117,19 +102,27 @@ public void Collect(int offset, SyntaxNode root, TextSpan scope) for (var b = 0; b < group.Count; b++) { var end = b + 1 < group.Count ? group[b + 1].FullSpan.Start : scope.End; - if (group[b] is BranchingDirectiveTriviaSyntax { BranchTaken: false }) Activate(offset, group[b], offset + end, runs); + if (group[b] is BranchingDirectiveTriviaSyntax { BranchTaken: false }) Activate(offset, group[b], offset + end); } } } + // An unterminated literal (CS1039, CS8997) runs past where the string really ends, so its extent is + // wrong; other errors, such as raw-string indentation, leave the extent intact. An interpolated + // string's text token is well-formed even when the enclosing literal is not closed. + private static bool HasError(SyntaxToken token) + { + var literal = token.IsKind(SyntaxKind.InterpolatedStringTextToken) ? token.Parent?.Parent : null; + return token.GetDiagnostics().Any(d => d.Id is "CS1039" or "CS8997") || + literal is InterpolatedStringExpressionSyntax interpolated && interpolated.StringEndToken.IsMissing; + } + // Parses the text from a skipped branch's directive onward, with that directive rewritten in place // to an always-true "#if" (every #if/#elif/#else directive is at least as long). The window doubles // until the branch's next directive is fully inside it, so the cost follows the branch size. That // next #elif/#else is followed too: a directive inside a string can hide it from the outer parse. - // When the branch ends past where the outer parse ended it, the outer parse read that stretch as - // code after a directive that is really string content; its strings starting there are dropped. // A branch that never closes once active is not valid C# that way; it keeps the outer extent. - private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd, List outerRuns) + private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd) { // A malformed directive (a bare "#if") is too short to rewrite; it is not valid C# anyway. var start = offset + directive.Span.Start; @@ -145,14 +138,9 @@ private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd, var complete = end == Text.Length; if (group.Count > 1 && (complete || group[1].FullSpan.End < window.Length)) { - var branchEnd = start + group[1].FullSpan.Start; - foreach (var run in outerRuns) - { - if (run.TokenStart >= outerEnd && run.TokenStart < branchEnd) run.Dropped = true; - } Collect(start, root, TextSpan.FromBounds(opening.FullSpan.End, group[1].FullSpan.Start)); var next = group.Count > 2 ? group[2].FullSpan.Start : window.Length; - if (group[1] is BranchingDirectiveTriviaSyntax) Activate(start, group[1], start + next, new List()); + if (group[1] is BranchingDirectiveTriviaSyntax) Activate(start, group[1], start + next); return; } if (complete) diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 64b7234e..fc58703f 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -226,6 +226,14 @@ public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string origi [InlineData("\r\n", "#if A\nvar s = @\"\n#elif B\nx\"\"@\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\r\nvar s = @\"\r\n#elif B\r\nx\"\"@\"\";\r\nvar a = 1;\r\nvar b = 2;\r\n#endif\r\n")] [InlineData("\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] [InlineData("\n", "#if A\nvar s = @\"\n#endif\nvar t = \"\"+@\"\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nvar s = @\"\n#endif\nvar t = \"\"+@\"\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] + // A CR stays when any configuration that parses without errors reads it as string content. + [InlineData("\n", "#if A\nvar s = \"\"\"\"\n#else\nvar t = @\"\n\"\"\"\";\nvar u = 1;\rvar v = 2;\n//\";\n#endif\n", "#if A\nvar s = \"\"\"\"\n#else\nvar t = @\"\n\"\"\"\";\nvar u = 1;\rvar v = 2;\n//\";\n#endif\n")] + [InlineData("\n", "#if A\nint q;\n#elif B\nvar s = @\"\n#else\nvar t = \"\"+@\"\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nint q;\n#elif B\nvar s = @\"\n#else\nvar t = \"\"+@\"\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] + [InlineData("\n", "#if A\nint q;\n#elif B\nvar s = @\"\n#endif\nvar t = \"\"+@\"\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nint q;\n#elif B\nvar s = @\"\n#endif\nvar t = \"\"+@\"\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] + // An unterminated literal is not valid C#: its extent is unknown, so it keeps no CR. + [InlineData("\n", "var a = @\"x\ry;\r", "var a = @\"x\ny;\n")] + [InlineData("\n", "var a = $@\"x\r{1}y;\r", "var a = $@\"x\n{1}y;\n")] + [InlineData("\n", "var a = \"\"\"\n x\ry;\r", "var a = \"\"\"\n x\ny;\n")] // An unterminated comment or string in one branch must not change how another branch is lexed. [InlineData("\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n")] [InlineData("\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n")] From 5bb3ace228a47ee1d03f8e9c6d5b84bb7d226366 Mon Sep 17 00:00:00 2001 From: akiojin Date: Wed, 14 Oct 2026 12:01:49 +0900 Subject: [PATCH 64/73] fix(lsp): preserve literal CRs across malformed nested branches --- ...f37b999f1bb2c6803b81f9ddd0d7d7ad5e42.jsonl | 1 + ...5ab7f52e3cbb94d4d3c7d50eeb51f5336fac.jsonl | 1 + lsp/Server.Core/LspSourceFile.cs | 246 ++++++++++++++---- lsp/SourceFileFormatTests.cs | 53 +++- 4 files changed, 249 insertions(+), 52 deletions(-) create mode 100644 .gwt/work/events/34/348bd9ca0e21d1290afe10c97ba1f37b999f1bb2c6803b81f9ddd0d7d7ad5e42.jsonl create mode 100644 .gwt/work/events/50/504ccd1c84fac1827f014249f48b5ab7f52e3cbb94d4d3c7d50eeb51f5336fac.jsonl diff --git a/.gwt/work/events/34/348bd9ca0e21d1290afe10c97ba1f37b999f1bb2c6803b81f9ddd0d7d7ad5e42.jsonl b/.gwt/work/events/34/348bd9ca0e21d1290afe10c97ba1f37b999f1bb2c6803b81f9ddd0d7d7ad5e42.jsonl new file mode 100644 index 00000000..d9458a8c --- /dev/null +++ b/.gwt/work/events/34/348bd9ca0e21d1290afe10c97ba1f37b999f1bb2c6803b81f9ddd0d7d7ad5e42.jsonl @@ -0,0 +1 @@ +{"id":"a8614755-69e2-4858-a465-340c7c87cc03","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":"統合した分岐解析修正の正式検証と再レビュー","summary":null,"progress_summary":"02dbdea/d435a0bの修正と回帰テストを取り込み、入れ子の字句干渉・長い条件式・誤った文字列保護を補完。LSP全433件が成功。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":518,"pr_url":"https://github.com/akiojin/unity-cli/pull/518","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T03:01:36.577158600Z"} diff --git a/.gwt/work/events/50/504ccd1c84fac1827f014249f48b5ab7f52e3cbb94d4d3c7d50eeb51f5336fac.jsonl b/.gwt/work/events/50/504ccd1c84fac1827f014249f48b5ab7f52e3cbb94d4d3c7d50eeb51f5336fac.jsonl new file mode 100644 index 00000000..07b60273 --- /dev/null +++ b/.gwt/work/events/50/504ccd1c84fac1827f014249f48b5ab7f52e3cbb94d4d3c7d50eeb51f5336fac.jsonl @@ -0,0 +1 @@ +{"id":"bb0fae43-086d-40f5-87a6-78bf84c24e82","work_item_id":"work-work-issue-516-59f2c1be","kind":"update","title":null,"intent":"PR #518 の分岐間字句干渉を修正・検証","summary":null,"progress_summary":"初回追加修正のCIは全成功。CodeRabbit指摘を再現し、条件分岐ごとの独立解析へ修正中。","status_category":null,"owner":"Issue #516","next_action":null,"agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":518,"pr_url":"https://github.com/akiojin/unity-cli/pull/518","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T02:19:56.855868400Z"} diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 7806fd3b..ddc9c6d8 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -52,64 +51,226 @@ public string ApplyNewlines(string text) return result.ToString(); } - // Plain CRLF input has no lone CR to classify, so it skips parsing. private static bool HasLoneCr(string text) { for (var i = text.IndexOf('\r'); i >= 0; i = text.IndexOf('\r', i + 1)) - { if (i + 1 >= text.Length || text[i + 1] != '\n') return true; - } return false; } - private const string ActiveSymbol = "_"; - private const string ActiveDirective = "#if " + ActiveSymbol; - private static readonly CSharpParseOptions ActiveBranchOptions = CSharpParseOptions.Default.WithPreprocessorSymbols(ActiveSymbol); - private static HashSet FindLoneCrsInStringLiterals(string text) { - var scan = new LiteralCrScan(text, new List(), new HashSet()); - scan.Collect(0, CSharpSyntaxTree.ParseText(text).GetRoot(), new TextSpan(0, text.Length)); var positions = new HashSet(); + var root = CSharpSyntaxTree.ParseText(text).GetRoot(); + var branches = ConditionalBranches(root).ToArray(); + var scan = new LiteralCrScan(text, positions, new(), new(), new(), branches); + scan.Collect(0, root, new TextSpan(0, text.Length)); foreach (var run in scan.Runs) + if (!run.Dropped) positions.UnionWith(run.Positions); + foreach (var branch in branches) { - if (run.Dropped) continue; - for (var i = run.Start; i < run.End; i++) + if (branch.AlreadyActive || scan.CleanActivations.Contains(branch.DirectiveStart)) continue; + // Select one branch and its ancestors, leaving sibling branches disabled. Their + // arbitrary text (including unfinished comments) must not affect this branch's lexer. + var (view, offsets) = SelectBranch(text, branch.Choices); + var viewRoot = CSharpSyntaxTree.ParseText(view).GetRoot(); + // Disabled text can contain directive-looking lines inside a string. Only accept + // a selection when its entire path is still real directives in the selected view. + var scope = SelectedScope(viewRoot, offsets, branch); + if (scope is not null) + CollectStringCrs(viewRoot, view, offsets, positions, scope, branches, HasSyntaxErrors(viewRoot, scope.Value, offsets)); + } + return positions; + } + + private static void CollectStringCrs(SyntaxNode root, string text, int[]? offsets, HashSet positions, + TextSpan? bounds = null, IReadOnlyList? branches = null, bool conservative = false, int sourceOffset = 0, + List? runs = null) + { + foreach (var token in root.DescendantTokens(descendIntoTrivia: true)) + { + if (token.Span.IsEmpty || !IsMultiLineStringContent(token.Kind())) continue; + var tokenPositions = runs is null ? null : new List(); + int? limit = null; + if (conservative && branches is not null) + { + var anchor = token.Parent?.AncestorsAndSelf().OfType().FirstOrDefault()?.SpanStart ?? token.SpanStart; + var originalStart = offsets?[anchor] ?? sourceOffset + anchor; + limit = branches.Where(b => b.BodyStart <= originalStart && originalStart < b.BodyEnd) + .OrderBy(b => b.BodyEnd - b.BodyStart).FirstOrDefault()?.BodyEnd; + } + for (var i = token.SpanStart; i < token.Span.End; i++) { - if (text[i] == '\r' && (i + 1 >= text.Length || text[i + 1] != '\n')) positions.Add(i); + if (text[i] != '\r' || (i + 1 < text.Length && text[i + 1] == '\n')) continue; + var original = offsets?[i] ?? sourceOffset + i; + if (limit is not null && original >= limit.Value) continue; + if (bounds is not null && !bounds.Value.Contains(original)) continue; + if (tokenPositions is not null) tokenPositions.Add(original); + else positions.Add(original); } + if (tokenPositions is { Count: > 0 }) runs!.Add(new(sourceOffset + token.SpanStart, tokenPositions)); } - return positions; } - // Offsets into the original text of string content that one parse found; TokenStart is where the - // token begins, so a parse that misread the region holding that start can drop the whole token. - private sealed class StringRun(int tokenStart, int start, int end) + private readonly record struct ConditionalChoice(int DirectiveStart, TextSpan Condition, bool Enabled); + private sealed record ConditionalBranch(int DirectiveStart, List Choices, int BodyStart) + { + public int BodyEnd { get; set; } + public bool AlreadyActive { get; init; } + } + + private sealed class ConditionalGroup(List parents) + { + public List Parents { get; } = parents; + public List Conditions { get; } = new(); + public List Current { get; set; } = parents; + public ConditionalBranch? Branch { get; private set; } + + public List Select(bool lastCondition) + { + var choices = new List(Parents); + for (var i = 0; i < Conditions.Count; i++) + { + choices.Add(Conditions[i] with { Enabled = lastCondition && i == Conditions.Count - 1 }); + } + return Current = choices; + } + + public ConditionalBranch StartBranch(DirectiveTriviaSyntax directive, bool lastCondition, int fileEnd) + { + if (Branch is not null) Branch.BodyEnd = directive.FullSpan.Start; + return Branch = new(directive.SpanStart, Select(lastCondition), directive.FullSpan.End) + { + BodyEnd = fileEnd, + AlreadyActive = directive.IsActive && directive is BranchingDirectiveTriviaSyntax { BranchTaken: true }, + }; + } + } + + private static IEnumerable ConditionalBranches(SyntaxNode root) + { + var groups = new Stack(); + var branches = new List(); + foreach (var trivia in root.DescendantTrivia(descendIntoTrivia: true)) + { + switch (trivia.GetStructure()) + { + case IfDirectiveTriviaSyntax directive: + var group = new ConditionalGroup(groups.TryPeek(out var parent) ? parent.Current : new()); + groups.Push(group); + group.Conditions.Add(new(directive.SpanStart, directive.Condition.Span, true)); + branches.Add(group.StartBranch(directive, true, root.FullSpan.End)); + break; + case ElifDirectiveTriviaSyntax directive when groups.TryPeek(out var elifGroup): + elifGroup.Conditions.Add(new(directive.SpanStart, directive.Condition.Span, true)); + branches.Add(elifGroup.StartBranch(directive, true, root.FullSpan.End)); + break; + case ElseDirectiveTriviaSyntax directive when groups.TryPeek(out var elseGroup): + branches.Add(elseGroup.StartBranch(directive, false, root.FullSpan.End)); + break; + case EndIfDirectiveTriviaSyntax directive when groups.Count > 0: + var ended = groups.Pop(); + if (ended.Branch is not null) ended.Branch.BodyEnd = directive.FullSpan.Start; + break; + } + } + return branches; + } + + private static (string Text, int[] Offsets) SelectBranch(string text, List choices) + { + var view = new StringBuilder(text.Length); + var offsets = new List(text.Length); + var original = 0; + foreach (var choice in choices.OrderBy(choice => choice.Condition.Start)) + { + while (original < choice.Condition.Start) { offsets.Add(original); view.Append(text[original++]); } + var replacement = choice.Enabled ? "true" : "false"; + for (var i = 0; i < replacement.Length; i++) + { + offsets.Add(i == replacement.Length - 1 ? Math.Max(choice.Condition.Start, choice.Condition.End - 1) : choice.Condition.Start); + view.Append(replacement[i]); + } + original = choice.Condition.End; + } + while (original < text.Length) { offsets.Add(original); view.Append(text[original++]); } + return (view.ToString(), offsets.ToArray()); + } + + private static TextSpan? SelectedScope(SyntaxNode root, int[] offsets, ConditionalBranch branch) + { + var choices = branch.Choices.ToDictionary(choice => choice.DirectiveStart); + var found = new HashSet(); + DirectiveTriviaSyntax? target = null; + foreach (var trivia in root.DescendantTrivia(descendIntoTrivia: true)) + { + if (trivia.GetStructure() is not DirectiveTriviaSyntax directive) continue; + var original = offsets[directive.SpanStart]; + var taken = directive switch + { + IfDirectiveTriviaSyntax condition => condition.BranchTaken, + ElifDirectiveTriviaSyntax condition => condition.BranchTaken, + ElseDirectiveTriviaSyntax condition => condition.BranchTaken, + _ => false, + }; + if (original == branch.DirectiveStart && directive.IsActive && taken) target = directive; + if (!choices.TryGetValue(original, out var choice)) continue; + if (!directive.IsActive || taken != choice.Enabled) return null; + found.Add(original); + } + if (target is null || found.Count != choices.Count) return null; + var end = branch.BodyEnd; + var related = target.GetRelatedDirectives(); + var index = 0; + while (index < related.Count && related[index].SpanStart != target.SpanStart) index++; + if (index + 1 < related.Count) + { + var actualEnd = offsets[related[index + 1].FullSpan.Start]; + // A valid selected view knows which directive-looking lines were really literal text. + // An invalid view may have swallowed a sibling with an unfinished string/comment; + // retain the original extent so that branch cannot protect unrelated code newlines. + if (actualEnd <= end || !HasSyntaxErrors(root, TextSpan.FromBounds(branch.BodyStart, actualEnd), offsets)) + end = actualEnd; + } + return TextSpan.FromBounds(branch.BodyStart, Math.Max(branch.BodyStart, end)); + } + + private static bool HasSyntaxErrors(SyntaxNode root, TextSpan scope, int[]? offsets = null, int sourceOffset = 0) + { + foreach (var diagnostic in root.GetDiagnostics()) + { + // #error does not alter lexing; CS0116 comes from parsing a class-field fragment at file scope. + if (diagnostic.Severity != DiagnosticSeverity.Error || diagnostic.Id is "CS1029" or "CS0116") continue; + var span = diagnostic.Location.SourceSpan; + var start = offsets is null ? sourceOffset + span.Start : span.Start < offsets.Length ? offsets[span.Start] : offsets[^1] + 1; + var end = offsets is null ? sourceOffset + span.End : span.Length > 0 ? offsets[span.End - 1] + 1 : start; + if (start < scope.End && end >= scope.Start) return true; + } + return false; + } + + private const string ActiveDirective = "#if _"; + private static readonly CSharpParseOptions ActiveBranchOptions = CSharpParseOptions.Default.WithPreprocessorSymbols("_"); + + private sealed class StringRun(int tokenStart, List positions) { public int TokenStart { get; } = tokenStart; - public int Start { get; } = start; - public int End { get; } = end; + public List Positions { get; } = positions; public bool Dropped { get; set; } } - // Inspects every preprocessor branch, independent of the current project's symbols. Each branch a - // parse skipped is parsed again on its own with that branch active, so the parser decides where the - // branch really ends (a directive-looking line inside its strings is string content) and no other - // branch's lexical state (an unterminated comment or string) reaches it. Activated holds the branch - // directives already parsed that way, so each is parsed once. - private readonly record struct LiteralCrScan(string Text, List Runs, HashSet Activated) + // Reparse skipped branches in isolation to discover real extents through directive-looking literal + // lines. The context-preserving selections above recover descendants hidden by a malformed sibling. + private readonly record struct LiteralCrScan(string Text, HashSet Positions, List Runs, HashSet Activated, + HashSet CleanActivations, IReadOnlyList Branches) { public void Collect(int offset, SyntaxNode root, TextSpan scope) { + var originalScope = new TextSpan(offset + scope.Start, scope.Length); var runs = new List(); - foreach (var token in root.DescendantTokens()) - { - if (!IsMultiLineStringContent(token.Kind())) continue; - var span = token.Span.Intersection(scope); - if (span is not null) runs.Add(new StringRun(offset + token.SpanStart, offset + span.Value.Start, offset + span.Value.End)); - } + CollectStringCrs(root, root.ToFullString(), null, Positions, originalScope, Branches, + HasSyntaxErrors(root, originalScope, sourceOffset: offset), offset, runs); Runs.AddRange(runs); - foreach (var directive in root.DescendantNodes(descendIntoTrivia: true).OfType()) { if (!directive.IsActive || !scope.Contains(directive.Span)) continue; @@ -122,22 +283,13 @@ public void Collect(int offset, SyntaxNode root, TextSpan scope) } } - // Parses the text from a skipped branch's directive onward, with that directive rewritten in place - // to an always-true "#if" (every #if/#elif/#else directive is at least as long). The window doubles - // until the branch's next directive is fully inside it, so the cost follows the branch size. That - // next #elif/#else is followed too: a directive inside a string can hide it from the outer parse. - // When the branch ends past where the outer parse ended it, the outer parse read that stretch as - // code after a directive that is really string content; its strings starting there are dropped. - // A branch that never closes once active is not valid C# that way; it keeps the outer extent. private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd, List outerRuns) { - // A malformed directive (a bare "#if") is too short to rewrite; it is not valid C# anyway. var start = offset + directive.Span.Start; if (directive.Span.Length < ActiveDirective.Length || !Activated.Add(start)) return; - // The window always holds the whole directive, however long its condition or comment is. - for (var length = directive.Span.Length + 256; ; length *= 2) + for (var length = directive.Span.Length + 256L; ; length *= 2) { - var end = (int)Math.Min(Text.Length, (long)start + length); + var end = (int)Math.Min(Text.Length, start + length); var window = ActiveDirective + new string(' ', directive.Span.Length - ActiveDirective.Length) + Text[(start + directive.Span.Length)..end]; var root = CSharpSyntaxTree.ParseText(window, ActiveBranchOptions).GetRoot(); var opening = root.DescendantNodes(descendIntoTrivia: true).OfType().First(); @@ -147,12 +299,12 @@ private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd, { var branchEnd = start + group[1].FullSpan.Start; foreach (var run in outerRuns) - { if (run.TokenStart >= outerEnd && run.TokenStart < branchEnd) run.Dropped = true; - } - Collect(start, root, TextSpan.FromBounds(opening.FullSpan.End, group[1].FullSpan.Start)); + var scope = TextSpan.FromBounds(opening.FullSpan.End, group[1].FullSpan.Start); + if (!HasSyntaxErrors(root, new TextSpan(start + scope.Start, scope.Length), sourceOffset: start)) CleanActivations.Add(start); + Collect(start, root, scope); var next = group.Count > 2 ? group[2].FullSpan.Start : window.Length; - if (group[1] is BranchingDirectiveTriviaSyntax) Activate(start, group[1], start + next, new List()); + if (group[1] is BranchingDirectiveTriviaSyntax) Activate(start, group[1], start + next, new()); return; } if (complete) diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 64b7234e..4f4119b0 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -220,13 +220,12 @@ public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string origi [InlineData("\n", "#if A\nvar a = @\"x\r#endif\ry\";\n#endif\n", "#if A\nvar a = @\"x\r#endif\ry\";\n#endif\n")] [InlineData("\r\n", "#if false\nvar a = \"\"\"\n x\r #if B\r \"\"\";\n#else\nvar a = $@\"x\r#else\r{1}\";\n#endif\n", "#if false\r\nvar a = \"\"\"\r\n x\r #if B\r \"\"\";\r\n#else\r\nvar a = $@\"x\r#else\r{1}\";\r\n#endif\r\n")] [InlineData("\n", "#if A\n#if B\nvar a = @\"x\r#elif C\r#endif\ry\";\n#endif\n#endif\n", "#if A\n#if B\nvar a = @\"x\r#elif C\r#endif\ry\";\n#endif\n#endif\n")] - // A fake #endif inside a skipped branch's string: what follows is code in the configuration where the branch is skipped. + // An unterminated comment or string in one branch must not change how another branch is lexed. [InlineData("\n", "#if false\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if false\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] [InlineData("\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] [InlineData("\r\n", "#if A\nvar s = @\"\n#elif B\nx\"\"@\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\r\nvar s = @\"\r\n#elif B\r\nx\"\"@\"\";\r\nvar a = 1;\r\nvar b = 2;\r\n#endif\r\n")] [InlineData("\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nvar s = @\"\n#endif\nx\"\"@\"\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] [InlineData("\n", "#if A\nvar s = @\"\n#endif\nvar t = \"\"+@\"\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if A\nvar s = @\"\n#endif\nvar t = \"\"+@\"\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] - // An unterminated comment or string in one branch must not change how another branch is lexed. [InlineData("\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n", "#if false\n/*\n#else\nvar a = @\"x\ry\";\n#endif\n")] [InlineData("\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n", "#if UNITY_EDITOR\n/*\n#elif UNITY_STANDALONE\nvar a = @\"x\ry\";\n#endif\n")] [InlineData("\n", "#if UNITY_EDITOR\nvar b = @\"\n#else\nvar a = 1;\n#endif\nvar c = @\"x\ry\";\r", "#if UNITY_EDITOR\nvar b = @\"\n#else\nvar a = 1;\n#endif\nvar c = @\"x\ry\";\n")] @@ -269,10 +268,10 @@ public static TheoryData InactiveBranchStrings() foreach (var literal in new[] { "@\"x\ry\"", - "\"\"\"\n x\ry\n \"\"\"", - "\"\"\"\n x\ry\n \"\"\"u8", + "\"\"\"\n x\r y\n \"\"\"", + "\"\"\"\n x\r y\n \"\"\"u8", "$@\"x\r{1}\ry\"", - "$\"\"\"\n x\r{1}\ry\n \"\"\"", + "$\"\"\"\n x\r {1}\r y\n \"\"\"", "@\"x\r#if OTHER\r#endif\ry\"", }) foreach (var branch in new[] @@ -284,6 +283,9 @@ public static TheoryData InactiveBranchStrings() "#if true\nint enabled = 1;\n#else\n{0}\n#endif\n", "#if UNITY_EDITOR\n#if UNITY_STANDALONE\n{0}\n#endif\n#endif\n", "#define UNITY_EDITOR\n#if !UNITY_EDITOR\n{0}\n#endif\n", + "#if false\n/*\n#else\n{0}\n#endif\n", + "#if false\n/*\n#elif UNITY_EDITOR\n{0}\n#else\nint enabled = 1;\n#endif\n", + "#if UNITY_EDITOR\n#if true\n/*\n#else\n{0}\n#endif\n#endif\n", }) { data.Add(newline, literal, branch); @@ -329,6 +331,47 @@ public async Task EditInputNewlines_KeepStringCrsInInactiveBranches(string newli } } + [Fact] + public void ApplyNewlines_KeepsDirectiveLookingLinesInClassFieldStrings() + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + const string input = "class C\n{\n#if UNITY_EDITOR\npublic string A = @\"x\r#else\ry\";\r#else\npublic string B = $@\"u\r#else\r{1}\rv\";\r#endif\r}\r"; + const string expected = "class C\n{\n#if UNITY_EDITOR\npublic string A = @\"x\r#else\ry\";\n#else\npublic string B = $@\"u\r#else\r{1}\rv\";\n#endif\n}\n"; + + Assert.Equal(expected, format.ApplyNewlines(input)); + } + + [Fact] + public void ApplyNewlines_DoesNotExtendANestedUnfinishedStringIntoItsSibling() + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + const string input = "#if UNITY_EDITOR\n#if true\n@\"unfinished\n#else\nvar prefix = 1;\rvar a = @\"x\ry\";\r#endif\r#endif\r"; + const string expected = "#if UNITY_EDITOR\n#if true\n@\"unfinished\n#else\nvar prefix = 1;\nvar a = @\"x\ry\";\n#endif\n#endif\n"; + + Assert.Equal(expected, format.ApplyNewlines(input)); + } + + [Fact] + public void ApplyNewlines_HandlesLongConditionalExpressions() + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + var condition = string.Join(" || ", Enumerable.Repeat("UNITY_EDITOR", 80)); + var input = "#if " + condition + "\nvar a = @\"x\ry\";\r#endif\r"; + var expected = "#if " + condition + "\nvar a = @\"x\ry\";\n#endif\n"; + + Assert.Equal(expected, format.ApplyNewlines(input)); + } + + [Fact] + public void ApplyNewlines_DoesNotExtendAnInactiveUnfinishedStringIntoOtherBranches() + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + const string input = "#if false\n@\"unfinished\n#else\nvar prefix = 1;\rvar a = @\"x\ry\";\r#endif\rvar b = 1;\r"; + const string expected = "#if false\n@\"unfinished\n#else\nvar prefix = 1;\nvar a = @\"x\ry\";\n#endif\nvar b = 1;\n"; + + Assert.Equal(expected, format.ApplyNewlines(input)); + } + [Fact] public void ApplyNewlines_NormalizesCrsInInactiveCommentsAndDirectiveMessages() { From 06d77657d02966ee3ccd56b810e0c4485bebecf4 Mon Sep 17 00:00:00 2001 From: akiojin Date: Wed, 14 Oct 2026 12:50:13 +0900 Subject: [PATCH 65/73] chore(work): record issue 516 pull request delivery --- ...1c392fb6ab24eed7a8bead0ff63e7d879103f14a870fafe4afe199f.jsonl | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gwt/work/events/7c/7c838c2d01c392fb6ab24eed7a8bead0ff63e7d879103f14a870fafe4afe199f.jsonl diff --git a/.gwt/work/events/7c/7c838c2d01c392fb6ab24eed7a8bead0ff63e7d879103f14a870fafe4afe199f.jsonl b/.gwt/work/events/7c/7c838c2d01c392fb6ab24eed7a8bead0ff63e7d879103f14a870fafe4afe199f.jsonl new file mode 100644 index 00000000..a1f86530 --- /dev/null +++ b/.gwt/work/events/7c/7c838c2d01c392fb6ab24eed7a8bead0ff63e7d879103f14a870fafe4afe199f.jsonl @@ -0,0 +1 @@ +{"id":"a99fa910-87a9-44e9-a447-239027e7729a","work_item_id":"work-work-issue-516-59f2c1be","kind":"pr","title":null,"intent":null,"summary":null,"progress_summary":null,"status_category":"done","owner":null,"next_action":null,"agent_session_id":"7dec144f-cdc1-4a98-b90f-fe2f1f41e128","agent_id":null,"display_name":null,"board_entry_id":null,"execution_container":{"branch":"work/issue-516","worktree_path":"E:\\unity-cli\\work\\issue-516","pr_number":519,"pr_url":"https://github.com/akiojin/unity-cli/pull/519","pr_state":"OPEN"},"related_work_item_id":null,"updated_at":"2026-10-14T03:28:14.901672800Z"} From 2b03c7efa2b49e15ff3486c93ba3d3d1cda586b3 Mon Sep 17 00:00:00 2001 From: akiojin Date: Wed, 14 Oct 2026 13:07:44 +0900 Subject: [PATCH 66/73] fix(lsp): align closed-string preservation with newline input matrix --- lsp/Server.Core/LspSourceFile.cs | 10 ++-------- lsp/SourceFileFormatTests.cs | 31 ++++++++++++++++++++----------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index ddbf314c..e5b205f1 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -113,14 +113,8 @@ public void Collect(int offset, SyntaxNode root, TextSpan scope) private static bool HasError(SyntaxToken token) { var literal = token.IsKind(SyntaxKind.InterpolatedStringTextToken) ? token.Parent?.Parent : null; - if (token.GetDiagnostics().Any(d => d.Id is "CS1039" or "CS8997") || - literal is InterpolatedStringExpressionSyntax interpolated && interpolated.StringEndToken.IsMissing) return true; - // An unfinished verbatim string can steal a sibling's opening quote. Roslyn - // closes the token there, leaving the sibling's content attached as an identifier - // after a missing semicolon. That recovered boundary is not a valid literal extent. - var next = token.GetNextToken(includeSkipped: true); - return token.Parent?.Parent is ExpressionStatementSyntax { SemicolonToken.IsMissing: true } && - next.IsKind(SyntaxKind.IdentifierToken) && next.SpanStart == token.Span.End; + return token.GetDiagnostics().Any(d => d.Id is "CS1039" or "CS8997") || + literal is InterpolatedStringExpressionSyntax interpolated && interpolated.StringEndToken.IsMissing; } // Parses the text from a skipped branch's directive onward, with that directive rewritten in place diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 06d896f6..0d4e43b8 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -273,10 +273,11 @@ public void ApplyNewlines_ActivatesBranchesWithDirectivesLongerThanTheFirstWindo } } - public static TheoryData InactiveBranchStrings() + public static TheoryData InactiveBranchStrings() { - var data = new TheoryData(); + var data = new TheoryData(); foreach (var newline in new[] { "\n", "\r\n", "\r" }) + foreach (var inputNewline in new[] { "\n", "\r\n", "\r" }) foreach (var literal in new[] { "@\"x\ry\"", @@ -300,20 +301,26 @@ public static TheoryData InactiveBranchStrings() "#if UNITY_EDITOR\n#if true\n/*\n#else\n{0}\n#endif\n#endif\n", }) { - data.Add(newline, literal, branch); + data.Add(newline, inputNewline, literal, branch); } return data; } [Theory] [MemberData(nameof(InactiveBranchStrings))] - public async Task EditInputNewlines_KeepStringCrsInInactiveBranches(string newline, string literal, string branch) + public async Task EditInputNewlines_KeepStringCrsInInactiveBranches(string newline, string inputNewline, string literal, string branch) { // Construct expected bytes separately: source line breaks follow the original convention, - // while the lone CRs in the literal remain part of its value. + // while lone CRs inside the literal (including CR input line breaks) are retained. var declaration = "var text = " + literal + ";"; - var input = branch.Replace("{0}", declaration); - var expected = branch.Replace("\n", newline).Replace("{0}", declaration.Replace("\n", newline)); + var input = branch.Replace("\n", inputNewline).Replace("{0}", declaration.Replace("\n", inputNewline)); + var literalNewline = inputNewline == "\r" ? "\r" : newline; + var expectedDeclaration = declaration.Replace("\n", literalNewline); + // The interpolated raw fixture's first/last line breaks delimit the content; + // only its explicit CRs between x, the interpolation, and y belong to the value. + if (inputNewline == "\r" && literal.StartsWith("$\"\"\"\n", StringComparison.Ordinal)) + expectedDeclaration = declaration.Replace("\n", newline); + var expected = branch.Replace("\n", newline).Replace("{0}", expectedDeclaration); foreach (var operation in new[] { "write", "apply", "create_overwrite" }) { var root = Path.Combine(Path.GetTempPath(), "unity-cli-format-" + Path.GetRandomFileName()); @@ -354,11 +361,13 @@ public void ApplyNewlines_KeepsDirectiveLookingLinesInClassFieldStrings() } [Fact] - public void ApplyNewlines_DoesNotExtendANestedUnfinishedStringIntoItsSibling() + public void ApplyNewlines_KeepsClosedStringCrsAcrossMalformedNestedBranches() { var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); const string input = "#if UNITY_EDITOR\n#if true\n@\"unfinished\n#else\nvar prefix = 1;\rvar a = @\"x\ry\";\r#endif\r#endif\r"; - const string expected = "#if UNITY_EDITOR\n#if true\n@\"unfinished\n#else\nvar prefix = 1;\nvar a = @\"x\ry\";\n#endif\n#endif\n"; + // Activating the inner #if closes its string at the sibling's opening quote. + // The PM union policy protects that closed token despite the malformed statement. + const string expected = "#if UNITY_EDITOR\n#if true\n@\"unfinished\n#else\nvar prefix = 1;\rvar a = @\"x\ry\";\n#endif\n#endif\n"; Assert.Equal(expected, format.ApplyNewlines(input)); } @@ -375,11 +384,11 @@ public void ApplyNewlines_HandlesLongConditionalExpressions() } [Fact] - public void ApplyNewlines_DoesNotExtendAnInactiveUnfinishedStringIntoOtherBranches() + public void ApplyNewlines_KeepsClosedStringCrsAcrossMalformedSiblingBranches() { var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); const string input = "#if false\n@\"unfinished\n#else\nvar prefix = 1;\rvar a = @\"x\ry\";\r#endif\rvar b = 1;\r"; - const string expected = "#if false\n@\"unfinished\n#else\nvar prefix = 1;\nvar a = @\"x\ry\";\n#endif\nvar b = 1;\n"; + const string expected = "#if false\n@\"unfinished\n#else\nvar prefix = 1;\rvar a = @\"x\ry\";\n#endif\nvar b = 1;\n"; Assert.Equal(expected, format.ApplyNewlines(input)); } From 9b30e3961e994b48e0ed74cd163bcf49af44c954 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 14:07:11 +0900 Subject: [PATCH 67/73] fix(lsp): keep closed-string CRs in branches hidden by unterminated literals Replace the per-branch reparse with a walk over every preprocessor state some configuration reaches (each #if/#elif condition free). Active code is lexed from the line after a directive, so an unterminated literal in a taken branch no longer hides its sibling #else/#elif/#endif; skipped branches are scanned line by line as Roslyn does, including bad #elif/#else after a group's #else. Cost follows the directive count, not the configurations. Add the #520 regression cases and an all-configurations oracle generator test (1000 generated sources, 0 mismatches). Refs #520 Co-Authored-By: Claude Opus 5.5 --- lsp/Server.Core/LspSourceFile.cs | 245 +++++++++++++++++++---------- lsp/SourceFileFormatOracleTests.cs | 138 ++++++++++++++++ lsp/SourceFileFormatTests.cs | 30 +++- 3 files changed, 330 insertions(+), 83 deletions(-) create mode 100644 lsp/SourceFileFormatOracleTests.cs diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index e5b205f1..0a289468 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -62,116 +62,197 @@ private static bool HasLoneCr(string text) return false; } - private const string ActiveSymbol = "_"; - private const string ActiveDirective = "#if " + ActiveSymbol; - private static readonly CSharpParseOptions ActiveBranchOptions = CSharpParseOptions.Default.WithPreprocessorSymbols(ActiveSymbol); + private static HashSet FindLoneCrsInStringLiterals(string text) => new LiteralCrScan(text).Run(); - private static HashSet FindLoneCrsInStringLiterals(string text) - { - var scan = new LiteralCrScan(text, new HashSet(), new HashSet()); - scan.Collect(0, CSharpSyntaxTree.ParseText(text).GetRoot(), new TextSpan(0, text.Length)); - return scan.Positions; - } + private enum DirectiveKind { Other, If, Elif, Else, EndIf } - // Inspects every preprocessor branch, independent of the current project's symbols. Each branch a - // parse skipped is parsed again on its own with that branch active, so the parser decides where the - // branch really ends (a directive-looking line inside its strings is string content) and no other - // branch's lexical state (an unterminated comment or string) reaches it. A lone CR is kept when any - // of these parses reads it inside a well-formed string; an unterminated string token is not valid C# - // in that configuration and keeps nothing. Positions are - // offsets into Text; Activated holds the branch directives already parsed, so each is parsed once. - private readonly record struct LiteralCrScan(string Text, HashSet Positions, HashSet Activated) + // Walks every lexer state that some preprocessor configuration reaches, independent of the current + // project's symbols: each #if/#elif condition may be true or false. Code is lexed only from the line + // after a directive, where the lexer state is fresh, so an unterminated comment or string in one + // branch never decides how another branch is lexed. A skipped branch is scanned line by line as + // Roslyn does, so a directive-looking line inside its strings ends the branch, while the same line + // lexed as active code is string content. A lone CR is kept when any reached state reads it inside + // a well-formed string; an unterminated string token is not valid C# in that configuration and keeps + // nothing. States are a position plus the open #if groups, so the cost follows the directive count + // rather than the number of configurations. + private sealed class LiteralCrScan { - public void Collect(int offset, SyntaxNode root, TextSpan scope) + private static readonly CSharpParseOptions Options = CSharpParseOptions.Default; + private readonly string _text; + private readonly HashSet _positions = new(); + private readonly Dictionary _nextDirective = new(); + private readonly HashSet<(int Position, string Groups)> _active = new(); + private readonly HashSet<(int Position, string Groups, bool Taken)> _skipped = new(); + private readonly Stack<(int Position, string Groups, bool? Taken)> _pending = new(); + + public LiteralCrScan(string text) => _text = text; + + public HashSet Run() { - foreach (var token in root.DescendantTokens(descendIntoTrivia: true)) + Active(0, ""); + while (_pending.TryPop(out var state)) { - if (!IsMultiLineStringContent(token.Kind()) || HasError(token)) continue; - var span = token.Span.Intersection(scope); - if (span is null) continue; - for (var i = offset + span.Value.Start; i < offset + span.Value.End; i++) - { - if (Text[i] == '\r' && (i + 1 >= Text.Length || Text[i + 1] != '\n')) Positions.Add(i); - } + if (state.Taken is { } taken) ScanSkipped(state.Position, state.Groups, taken); + else ScanActive(state.Position, state.Groups); } + return _positions; + } - foreach (var directive in root.DescendantNodes(descendIntoTrivia: true).OfType()) - { - if (!scope.Contains(directive.Span)) continue; - var group = directive.GetRelatedDirectives(); - for (var b = 0; b < group.Count; b++) - { - var end = b + 1 < group.Count ? group[b + 1].FullSpan.Start : scope.End; - if (group[b] is BranchingDirectiveTriviaSyntax { BranchTaken: false }) Activate(offset, group[b], offset + end); - } - } + // Groups holds one char per open #if, outermost first: Else once the group has passed its #else. + private const char Open = 'i'; + private const char Else = 'e'; + + private void Active(int position, string groups) + { + if (_active.Add((position, groups))) _pending.Push((position, groups, null)); } - // An unterminated literal (CS1039, CS8997) runs past where the string really ends, so its extent is - // wrong; other errors, such as raw-string indentation, leave the extent intact. An interpolated - // string's text token is well-formed even when the enclosing literal is not closed. - private static bool HasError(SyntaxToken token) + // A skipped branch of the innermost open #if; Taken records whether an earlier branch was taken. + private void Skipped(int position, string groups, bool taken) { - var literal = token.IsKind(SyntaxKind.InterpolatedStringTextToken) ? token.Parent?.Parent : null; - return token.GetDiagnostics().Any(d => d.Id is "CS1039" or "CS8997") || - literal is InterpolatedStringExpressionSyntax interpolated && interpolated.StringEndToken.IsMissing; + if (_skipped.Add((position, groups, taken))) _pending.Push((position, groups, taken)); } - // Parses the text from a skipped branch's directive onward, with that directive rewritten in place - // to an always-true "#if" (every #if/#elif/#else directive is at least as long). The window doubles - // until the branch's next directive is fully inside it, so the cost follows the branch size. That - // next #elif/#else is followed too: a directive inside a string can hide it from the outer parse. - // A branch that never closes once active is not valid C# that way; it keeps the outer extent. - private void Activate(int offset, DirectiveTriviaSyntax directive, int outerEnd) + // Roslyn reports a stray #elif/#else/#endif, or an #elif/#else after the group's #else, as a bad + // directive and keeps lexing in the same state. + private void ScanActive(int position, string groups) { - // A malformed directive (a bare "#if") is too short to rewrite; it is not valid C# anyway. - var start = offset + directive.Span.Start; - if (directive.Span.Length < ActiveDirective.Length || !Activated.Add(start)) return; - // The window always holds the whole directive, however long its condition or comment is. - for (var length = directive.Span.Length + 256; ; length *= 2) + if (NextDirective(position) is not var (kind, end)) return; + var inGroup = groups.Length > 0; + var afterElse = inGroup && groups[^1] == Else; + switch (kind) { - var end = (int)Math.Min(Text.Length, (long)start + length); - var window = ActiveDirective + new string(' ', directive.Span.Length - ActiveDirective.Length) + Text[(start + directive.Span.Length)..end]; - var root = CSharpSyntaxTree.ParseText(window, ActiveBranchOptions).GetRoot(); - var opening = root.DescendantNodes(descendIntoTrivia: true).OfType().First(); - var group = BranchDirectives(root, opening); - var complete = end == Text.Length; - if (group.Count > 1 && (complete || group[1].FullSpan.End < window.Length)) + case DirectiveKind.If: + Active(end, groups + Open); + Skipped(end, groups + Open, taken: false); + break; + case DirectiveKind.Elif when inGroup && !afterElse: + Skipped(end, groups, taken: true); + break; + case DirectiveKind.Else when inGroup && !afterElse: + Skipped(end, groups[..^1] + Else, taken: true); + break; + case DirectiveKind.EndIf when inGroup: + Active(end, groups[..^1]); + break; + default: + Active(end, groups); + break; + } + } + + private void ScanSkipped(int position, string groups, bool taken) + { + var nested = 0; + var afterElse = groups[^1] == Else; + for (var line = position; line < _text.Length; line = LineEnd(line)) + { + var kind = Classify(line); + if (kind == DirectiveKind.If) nested++; + else if (kind == DirectiveKind.EndIf && nested > 0) nested--; + else if (nested > 0 || afterElse && kind is DirectiveKind.Elif or DirectiveKind.Else) continue; + else if (kind == DirectiveKind.EndIf) { - Collect(start, root, TextSpan.FromBounds(opening.FullSpan.End, group[1].FullSpan.Start)); - var next = group.Count > 2 ? group[2].FullSpan.Start : window.Length; - if (group[1] is BranchingDirectiveTriviaSyntax) Activate(start, group[1], start + next); + Active(LineEnd(line), groups[..^1]); return; } - if (complete) + else if (kind == DirectiveKind.Elif && !taken) Active(LineEnd(line), groups); + else if (kind == DirectiveKind.Else && taken) afterElse = true; + else if (kind == DirectiveKind.Else) { - Collect(start, root, TextSpan.FromBounds(opening.FullSpan.End, Math.Max(opening.FullSpan.End, outerEnd - start))); + Active(LineEnd(line), groups[..^1] + Else); return; } } } - // A fragment can be parsed as a field outside its containing class. Roslyn can then - // attach its directives to separate skipped-token trivia and omit related directives. - // Their lexical kinds still identify the opening's siblings and closing directive. - private static List BranchDirectives(SyntaxNode root, IfDirectiveTriviaSyntax opening) + // Lexes active code from a line start up to the next directive and records the CRs of the + // well-formed strings on the way. Lexing is independent of the depth, so it runs once per start. + private (DirectiveKind Kind, int End)? NextDirective(int position) + { + if (_nextDirective.TryGetValue(position, out var cached)) return cached; + (DirectiveKind, int)? next = null; + foreach (var token in SyntaxFactory.ParseTokens(_text, position, position, Options)) + { + var directive = token.LeadingTrivia.FirstOrDefault(trivia => trivia.IsDirective); + if (directive.IsDirective) + { + var start = directive.SpanStart; + while (start > 0 && !SyntaxFacts.IsNewLine(_text[start - 1])) start--; + next = (Classify(start), LineEnd(start)); + break; + } + if (token.IsKind(SyntaxKind.EndOfFileToken)) break; + CollectString(token); + } + _nextDirective[position] = next; + return next; + } + + private void CollectString(SyntaxToken token) { - var related = opening.GetRelatedDirectives(); - if (related.Count > 1) return related; - var group = new List { opening }; - var depth = 0; - foreach (var directive in root.DescendantNodes(descendIntoTrivia: true).OfType()) + if (token.IsKind(SyntaxKind.InterpolatedStringToken)) { - if (directive.SpanStart <= opening.SpanStart) continue; - if (directive is IfDirectiveTriviaSyntax) depth++; - else if (directive is EndIfDirectiveTriviaSyntax) + if (IsUnterminated(token)) return; + // The lexer reads an interpolated string as one token; its holes are code, not content. + foreach (var part in SyntaxFactory.ParseExpression(token.Text, options: Options).DescendantTokens()) { - if (depth == 0) { group.Add(directive); break; } - depth--; + if (IsMultiLineStringContent(part.Kind()) && !HasError(part)) Add(token.SpanStart + part.SpanStart, token.SpanStart + part.Span.End); } - else if (depth == 0 && directive is ElifDirectiveTriviaSyntax or ElseDirectiveTriviaSyntax) group.Add(directive); } - return group; + else if (IsMultiLineStringContent(token.Kind()) && !HasError(token)) Add(token.SpanStart, token.Span.End); + } + + private void Add(int start, int end) + { + for (var i = start; i < end; i++) + { + if (_text[i] == '\r' && (i + 1 >= _text.Length || _text[i + 1] != '\n')) _positions.Add(i); + } + } + + // An unterminated literal (CS1039, CS8997) runs past where the string really ends, so its extent is + // wrong; other errors, such as raw-string indentation, leave the extent intact. An interpolated + // string's text token is well-formed only when the enclosing literal is closed. Only the token's + // own diagnostics count: trailing trivia can hold a later, unrelated literal's. + private static bool IsUnterminated(SyntaxToken token) => token.WithoutTrivia().GetDiagnostics().Any(d => d.Id is "CS1039" or "CS8997"); + + private static bool HasError(SyntaxToken token) + { + var literal = token.IsKind(SyntaxKind.InterpolatedStringTextToken) ? token.Parent?.Parent : null; + return IsUnterminated(token) || literal is InterpolatedStringExpressionSyntax interpolated && interpolated.StringEndToken.IsMissing; + } + + // The conditional directive starting a line: '#' and its name after optional whitespace. + private DirectiveKind Classify(int line) + { + var i = SkipWhitespace(line); + if (i >= _text.Length || _text[i] != '#') return DirectiveKind.Other; + var nameStart = SkipWhitespace(i + 1); + var nameEnd = nameStart; + while (nameEnd < _text.Length && SyntaxFacts.IsIdentifierPartCharacter(_text[nameEnd])) nameEnd++; + return _text[nameStart..nameEnd] switch + { + "if" => DirectiveKind.If, + "elif" => DirectiveKind.Elif, + "else" => DirectiveKind.Else, + "endif" => DirectiveKind.EndIf, + _ => DirectiveKind.Other, + }; + } + + private int SkipWhitespace(int i) + { + while (i < _text.Length && SyntaxFacts.IsWhitespace(_text[i])) i++; + return i; + } + + // The start of the next line; CRLF is one line break. + private int LineEnd(int i) + { + while (i < _text.Length && !SyntaxFacts.IsNewLine(_text[i])) i++; + if (i < _text.Length && _text[i] == '\r' && i + 1 < _text.Length && _text[i + 1] == '\n') i++; + return Math.Min(i + 1, _text.Length); } } diff --git a/lsp/SourceFileFormatOracleTests.cs b/lsp/SourceFileFormatOracleTests.cs new file mode 100644 index 00000000..729a7a77 --- /dev/null +++ b/lsp/SourceFileFormatOracleTests.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using UnityCli.Lsp.Core; +using Xunit; + +// #520: compares ApplyNewlines with an oracle that parses every branch-selection configuration. +public sealed class SourceFileFormatOracleTests +{ + private static readonly LspSourceFileFormat LfFile = new(new UTF8Encoding(false), "\n"); + + // Rewrites every #if/#elif condition to its own symbol and parses each subset of those symbols. A lone + // CR is kept iff some configuration reads it inside a closed multi-line string literal. + private static string Oracle(string text) + { + var builder = new StringBuilder(text); + var symbols = 0; + foreach (Match line in Regex.Matches(text, @"(?<=^|[\r\n])[ \t]*#[ \t]*(if|elif)[ \t]+[^\r\n]*")) + { + var head = Regex.Match(line.Value, @"^[ \t]*#[ \t]*(if|elif)[ \t]+"); + if (line.Length == head.Length) continue; + var symbol = ((char)('a' + symbols++)).ToString(); + var replacement = symbol.PadRight(line.Length - head.Length); + for (var k = 0; k < replacement.Length; k++) builder[line.Index + head.Length + k] = replacement[k]; + } + + var rewritten = builder.ToString(); + var keep = new HashSet(); + for (var mask = 0; mask < 1 << symbols; mask++) + { + var defined = Enumerable.Range(0, symbols).Where(i => (mask & (1 << i)) != 0).Select(i => ((char)('a' + i)).ToString()); + var root = CSharpSyntaxTree.ParseText(rewritten, CSharpParseOptions.Default.WithPreprocessorSymbols(defined)).GetRoot(); + foreach (var token in root.DescendantTokens(descendIntoTrivia: true)) Keep(token, 0); + } + + // Error recovery can leave a closed literal in skipped-token trivia, where an interpolated string + // stays one lexer token; the lexer still reads it as a closed literal, so it counts as well. + void Keep(SyntaxToken token, int offset) + { + if (token.IsKind(SyntaxKind.InterpolatedStringToken)) + { + foreach (var part in SyntaxFactory.ParseExpression(token.Text).DescendantTokens()) Keep(part, offset + token.SpanStart); + return; + } + if (!token.IsKind(SyntaxKind.StringLiteralToken) && !token.IsKind(SyntaxKind.Utf8StringLiteralToken) && + !token.IsKind(SyntaxKind.MultiLineRawStringLiteralToken) && !token.IsKind(SyntaxKind.Utf8MultiLineRawStringLiteralToken) && + !token.IsKind(SyntaxKind.InterpolatedStringTextToken)) return; + var literal = token.IsKind(SyntaxKind.InterpolatedStringTextToken) ? token.Parent?.Parent : null; + // Only the token's own diagnostics: its trailing trivia can hold a later skipped literal's. + if (token.WithoutTrivia().GetDiagnostics().Any(d => d.Id is "CS1039" or "CS8997") || + literal is InterpolatedStringExpressionSyntax interpolated && interpolated.StringEndToken.IsMissing) return; + for (var i = offset + token.Span.Start; i < offset + token.Span.End; i++) + { + if (text[i] == '\r' && (i + 1 >= text.Length || text[i + 1] != '\n')) keep.Add(i); + } + } + + var result = new StringBuilder(); + for (var i = 0; i < text.Length; i++) + { + var c = text[i]; + if (c == '\n') result.Append('\n'); + else if (c != '\r') result.Append(c); + else if (i + 1 < text.Length && text[i + 1] == '\n') { result.Append('\n'); i++; } + else result.Append(keep.Contains(i) ? "\r" : "\n"); + } + return result.ToString(); + } + + private static readonly string[] Fragments = + { + "var s = @\"x\ry\";\n", "var t = @\"\n", "var x = \"\";\n", "var u = \"\"\"\n", "\"\"\";\n", + "int a = 1;\rint b = 2;\n", "var v = @\"p\r#else\rq\";\n", "var w = @\"p\r#endif\rq\";\n", + "class C { string f = @\"a\r#else\rb\"; }\n", "/*\n", "*/\n", "var z = $@\"k\r{1}\";\n", + }; + + private static readonly string[] Conditions = { "A", "B", "false", "true", "C" }; + + private static string Block(Random random, int depth) + { + var builder = new StringBuilder(); + for (var n = random.Next(1, 4); n > 0; n--) + { + if (depth < 3 && random.Next(3) == 0) + { + builder.Append("#if " + Conditions[random.Next(Conditions.Length)] + "\n").Append(Block(random, depth + 1)); + if (random.Next(2) == 0) builder.Append("#elif " + Conditions[random.Next(Conditions.Length)] + "\n").Append(Block(random, depth + 1)); + if (random.Next(2) == 0) builder.Append("#else\n").Append(Block(random, depth + 1)); + builder.Append("#endif\n"); + } + else builder.Append(Fragments[random.Next(Fragments.Length)]); + } + return builder.ToString(); + } + + private static string Show(string text) => text.Replace("\r", "\\r").Replace("\n", "\\n"); + + [Fact] + public void ApplyNewlines_MatchesTheAllConfigurationsOracleOnGeneratedSources() + { + var random = new Random(516); + var compared = 0; + var mismatches = new List(); + for (var iteration = 0; iteration < 50000 && compared < 1000; iteration++) + { + var text = Block(random, 0); + if (!text.Contains('\r') || Regex.Matches(text, "#if|#elif").Count > 7) continue; + compared++; + var expected = Oracle(text); + var actual = LfFile.ApplyNewlines(text); + if (expected != actual) mismatches.Add(Show(text) + "\n oracle: " + Show(expected) + "\n actual: " + Show(actual)); + } + + Assert.True(compared >= 400, "compared " + compared); + Assert.True(mismatches.Count == 0, mismatches.Count + " of " + compared + " mismatched:\n" + string.Join("\n", mismatches.Take(10))); + } + + // Representative minimal mismatches the generator reported against develop 74806ad1. + [Theory] + [InlineData("#if true\nvar t = @\"\n#else\nvar s = @\"x\ry\";\n#endif\n")] + [InlineData("#if true\n/*\n#else\nvar v = @\"p\r#else\rq\";\n#endif\n")] + [InlineData("#if true\n/*\n#elif C\nvar w = @\"p\r#endif\rq\";\n#endif\n")] + [InlineData("#if true\n/*\n#endif\nvar w = @\"p\r#endif\rq\";\n")] + [InlineData("#if B\n#elif true\nvar t = @\"\n#endif\nvar z = $@\"k\r{1}\";\n")] + [InlineData("#if A\nvar v = @\"p\r#else\rq\";\n/*\n#endif\n")] + [InlineData("#if C\n/*\n#if C\n*/\n#endif\nvar v = @\"p\r#else\rq\";\n#endif\n")] + [InlineData("#if B\nvar v = @\"p\r#else\rq\";\n#elif true\nvar z = $@\"k\r{1}\";\n#endif\n")] + [InlineData("#if false\nvar a = \"\"\"\n x\r #if B\r \"\"\";\n#else\nvar a = $@\"x\r#else\r{1}\";\n#endif\n")] + public void ApplyNewlines_MatchesTheOracleOnMinimalMismatches(string input) + { + Assert.Equal(Oracle(input), LfFile.ApplyNewlines(input)); + } +} diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 0d4e43b8..8cd8d8b7 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -218,7 +218,10 @@ public async Task EditInputNewlines_AreSavedInTheOriginalConvention(string origi [InlineData("\n", "#if A\nvar a = @\"x\r#elif false\r\";\n#endif\n", "#if A\nvar a = @\"x\r#elif false\r\";\n#endif\n")] [InlineData("\n", "#if A\nvar a = @\"x\r#else\ry\";\n#endif\n", "#if A\nvar a = @\"x\r#else\ry\";\n#endif\n")] [InlineData("\n", "#if A\nvar a = @\"x\r#endif\ry\";\n#endif\n", "#if A\nvar a = @\"x\r#endif\ry\";\n#endif\n")] - [InlineData("\r\n", "#if false\nvar a = \"\"\"\n x\r #if B\r \"\"\";\n#else\nvar a = $@\"x\r#else\r{1}\";\n#endif\n", "#if false\r\nvar a = \"\"\"\r\n x\r #if B\r \"\"\";\r\n#else\r\nvar a = $@\"x\r#else\r{1}\";\r\n#endif\r\n")] + // No configuration reaches this #else: when the #if is skipped, the raw string's "#if B" line opens a + // nested group that swallows the #else, so only the raw string's CRs are string content. + [InlineData("\r\n", "#if false\nvar a = \"\"\"\n x\r #if B\r \"\"\";\n#else\nvar a = $@\"x\r#else\r{1}\";\n#endif\n", "#if false\r\nvar a = \"\"\"\r\n x\r #if B\r \"\"\";\r\n#else\r\nvar a = $@\"x\r\n#else\r\n{1}\";\r\n#endif\r\n")] + [InlineData("\r\n", "#if false\nvar a = \"\"\"\n x\r \"\"\";\n#else\nvar a = $@\"x\r#else\r{1}\";\n#endif\n", "#if false\r\nvar a = \"\"\"\r\n x\r \"\"\";\r\n#else\r\nvar a = $@\"x\r#else\r{1}\";\r\n#endif\r\n")] [InlineData("\n", "#if A\n#if B\nvar a = @\"x\r#elif C\r#endif\ry\";\n#endif\n#endif\n", "#if A\n#if B\nvar a = @\"x\r#elif C\r#endif\ry\";\n#endif\n#endif\n")] // An unterminated comment or string in one branch must not change how another branch is lexed. [InlineData("\n", "#if false\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\rvar b = 2;\n#endif\n", "#if false\nvar s = @\"\n#endif\nx\"\"@\"\";\nvar a = 1;\nvar b = 2;\n#endif\n")] @@ -402,6 +405,31 @@ public void ApplyNewlines_NormalizesCrsInInactiveCommentsAndDirectiveMessages() Assert.Equal(input.Replace("\r", "\n"), format.ApplyNewlines(input)); } + // #520: an unterminated literal in one branch must not hide a sibling branch, and a directive-looking + // line inside a nested branch's string must not close the wrong group. Each input keeps its CRs + // because some branch-selection configuration reads them inside a closed string. + [Theory] + [InlineData("#if true\n#if C\nvar w = @\"p\r#endif\rq\";\n#endif\n#endif\nvar s = @\"x\ry\";\n")] + [InlineData("#if B\n#if A\nvar v = @\"p\r#else\rq\";\n#endif\nvar w = @\"p\r#endif\rq\";\n#endif\n")] + [InlineData("#if true\n#if false\nvar w = @\"p\r#endif\rq\";\n#endif\nvar s = @\"x\ry\";\n#endif\n")] + [InlineData("#if B\n#if A\n#if true\nvar t = @\"\n#endif\nvar z = $@\"k\r{1}\";\n#endif\n#endif\n")] + [InlineData("#if true\nvar t = @\"\n#else\nvar s = @\"x\ry\";\n#endif\n")] + [InlineData("#if true\nvar t = @\"\n#elif false\nvar w = @\"p\r#endif\rq\";\n#endif\n")] + [InlineData("#if true\nvar u = \"\"\"\n#endif\nclass C { string f = @\"a\r#else\rb\"; }\n")] + [InlineData("#if A\nclass C { string f = @\"a\r#else\rb\"; }\n#endif\nvar z = $@\"k\r{1}\";\n")] + [InlineData("#if B\nclass C { string f = @\"a\r#else\rb\"; }\nvar u = \"\"\"\n#endif\n")] + // Minimal generator mismatches: an unterminated "/*" or "@\"" in a taken branch hides the next branch. + [InlineData("#if true\n/*\n#else\nvar v = @\"p\r#else\rq\";\n#endif\n")] + [InlineData("#if true\n/*\n#elif C\nvar w = @\"p\r#endif\rq\";\n#endif\n")] + [InlineData("#if true\n/*\n#endif\nvar w = @\"p\r#endif\rq\";\n")] + [InlineData("#if B\n#elif true\nvar t = @\"\n#endif\nvar z = $@\"k\r{1}\";\n")] + public void ApplyNewlines_KeepsClosedStringCrsInBranchesHiddenByUnterminatedLiterals(string input) + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + + Assert.Equal(input, format.ApplyNewlines(input)); + } + private static byte[] Encode(string lfText, string encoding, string newline) { Encoding target = encoding switch From 93109dc5f32ea2fe10638693f749d2802063a98f Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Wed, 14 Oct 2026 15:34:11 +0900 Subject: [PATCH 68/73] perf(lsp): solve each preprocessor group once and bound the CR scan Carrying every open group's #else flag in the state made a string whose "#else" line splits a group double the work per nesting level (depth 30 never finished). Each #if group is now solved once and its exits reused by every caller, so the cost follows the directive count. Remove the quadratic paths in the directive count: skipped groups use a precomputed line index instead of rescanning, the lexer reads a doubling window so a run of directives or an unterminated comment is not lexed to the end of the file from every state, and plain #if conditions are rewritten in place to a defined symbol so a false #if does not make the lexer read its whole skipped group. Past 200,000 states the scan keeps every lone CR (fail-safe). Refs #520 Co-Authored-By: Claude Opus 5.5 --- lsp/Server.Core/LspSourceFile.cs | 283 ++++++++++++++++++++++------- lsp/Server.Core/Server.Core.csproj | 3 + lsp/SourceFileFormatTests.cs | 62 +++++++ 3 files changed, 278 insertions(+), 70 deletions(-) diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 0a289468..187c9ae8 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -36,10 +36,15 @@ public static (string Text, LspSourceFileFormat Format) Decode(byte[] bytes) /// file's convention; mixed or unknown conventions are left as given. A lone CR inside a string /// literal is part of the string's value and is kept. /// - public string ApplyNewlines(string text) + public string ApplyNewlines(string text) => ApplyNewlines(text, MaxScanStates); + + internal string ApplyNewlines(string text, int maxScanStates) { if (NewLine is null) return text; - var literalCrs = HasLoneCr(text) ? FindLoneCrsInStringLiterals(text) : null; + var hasLoneCr = HasLoneCr(text); + var literalCrs = hasLoneCr ? FindLoneCrsInStringLiterals(text, maxScanStates) : null; + // A scan over its state budget keeps every lone CR: rewriting one inside a string changes its value. + var keepAll = hasLoneCr && literalCrs is null; var result = new StringBuilder(text.Length); for (var i = 0; i < text.Length; i++) { @@ -47,7 +52,7 @@ public string ApplyNewlines(string text) if (c == '\n') result.Append(NewLine); else if (c != '\r') result.Append(c); else if (i + 1 < text.Length && text[i + 1] == '\n') { result.Append(NewLine); i++; } - else result.Append(literalCrs?.Contains(i) == true ? "\r" : NewLine); + else result.Append(keepAll || literalCrs?.Contains(i) == true ? "\r" : NewLine); } return result.ToString(); } @@ -62,7 +67,10 @@ private static bool HasLoneCr(string text) return false; } - private static HashSet FindLoneCrsInStringLiterals(string text) => new LiteralCrScan(text).Run(); + private const int MaxScanStates = 200_000; + + // Returns null when the scan exceeds maxStates. + private static HashSet? FindLoneCrsInStringLiterals(string text, int maxStates) => new LiteralCrScan(text, maxStates).Run(); private enum DirectiveKind { Other, If, Elif, Else, EndIf } @@ -73,122 +81,159 @@ private enum DirectiveKind { Other, If, Elif, Else, EndIf } // Roslyn does, so a directive-looking line inside its strings ends the branch, while the same line // lexed as active code is string content. A lone CR is kept when any reached state reads it inside // a well-formed string; an unterminated string token is not valid C# in that configuration and keeps - // nothing. States are a position plus the open #if groups, so the cost follows the directive count - // rather than the number of configurations. + // nothing. + // + // A state is the innermost open #if group, a position at its level, and whether the group has passed + // its #else; nothing below the innermost group decides what happens at that level. Each group is + // solved once: the positions after its #endif are its exits, and every caller resumes at each exit + // with its own state. The cost therefore follows the directive count rather than the number of + // configurations or the nesting depth. private sealed class LiteralCrScan { - private static readonly CSharpParseOptions Options = CSharpParseOptions.Default; + private const int Root = -1; + private static readonly CSharpParseOptions Options = CSharpParseOptions.Default.WithPreprocessorSymbols(Lines.TakenSymbol); private readonly string _text; + private readonly string _lexText; + private readonly int _lastCommentEnd; + private readonly int _maxStates; private readonly HashSet _positions = new(); private readonly Dictionary _nextDirective = new(); - private readonly HashSet<(int Position, string Groups)> _active = new(); - private readonly HashSet<(int Position, string Groups, bool Taken)> _skipped = new(); - private readonly Stack<(int Position, string Groups, bool? Taken)> _pending = new(); + private readonly Lines _lines; + private readonly HashSet<(int Group, int Position, bool AfterElse)> _active = new(); + private readonly Stack<(int Group, int Position, bool AfterElse)> _pending = new(); + private readonly Dictionary> _exits = new(); + private readonly Dictionary> _callers = new(); - public LiteralCrScan(string text) => _text = text; + public LiteralCrScan(string text, int maxStates) + { + _text = text; + _maxStates = maxStates; + _lines = new Lines(text); + _lexText = _lines.WithTakenConditions(); + _lastCommentEnd = text.LastIndexOf("*/", StringComparison.Ordinal); + } - public HashSet Run() + public HashSet? Run() { - Active(0, ""); + Active(Root, 0, afterElse: false); while (_pending.TryPop(out var state)) { - if (state.Taken is { } taken) ScanSkipped(state.Position, state.Groups, taken); - else ScanActive(state.Position, state.Groups); + if (_active.Count + _exits.Count > _maxStates) return null; + ScanActive(state.Group, state.Position, state.AfterElse); } return _positions; } - // Groups holds one char per open #if, outermost first: Else once the group has passed its #else. - private const char Open = 'i'; - private const char Else = 'e'; - - private void Active(int position, string groups) + // Group is the position after the innermost open #if, or Root at the file level. + private void Active(int group, int position, bool afterElse) { - if (_active.Add((position, groups))) _pending.Push((position, groups, null)); - } - - // A skipped branch of the innermost open #if; Taken records whether an earlier branch was taken. - private void Skipped(int position, string groups, bool taken) - { - if (_skipped.Add((position, groups, taken))) _pending.Push((position, groups, taken)); + if (_active.Add((group, position, afterElse))) _pending.Push((group, position, afterElse)); } // Roslyn reports a stray #elif/#else/#endif, or an #elif/#else after the group's #else, as a bad // directive and keeps lexing in the same state. - private void ScanActive(int position, string groups) + private void ScanActive(int group, int position, bool afterElse) { if (NextDirective(position) is not var (kind, end)) return; - var inGroup = groups.Length > 0; - var afterElse = inGroup && groups[^1] == Else; + var inGroup = group != Root; switch (kind) { case DirectiveKind.If: - Active(end, groups + Open); - Skipped(end, groups + Open, taken: false); - break; - case DirectiveKind.Elif when inGroup && !afterElse: - Skipped(end, groups, taken: true); + Enter(end, group, afterElse); break; - case DirectiveKind.Else when inGroup && !afterElse: - Skipped(end, groups[..^1] + Else, taken: true); + case DirectiveKind.Elif or DirectiveKind.Else when inGroup && !afterElse: + // The rest of the group is skipped; only its #endif matters. + if (_lines.MatchingEndIf(end) is { } endIf) Exit(group, _lines.LineEnd(endIf)); break; case DirectiveKind.EndIf when inGroup: - Active(end, groups[..^1]); + Exit(group, end); break; default: - Active(end, groups); + Active(group, end, afterElse); break; } } - private void ScanSkipped(int position, string groups, bool taken) + // Opens the group whose #if ends at start; the caller resumes after each of its exits. + private void Enter(int start, int caller, bool callerAfterElse) { - var nested = 0; - var afterElse = groups[^1] == Else; - for (var line = position; line < _text.Length; line = LineEnd(line)) + var isNew = !_exits.TryGetValue(start, out var exits); + if (isNew) _exits[start] = exits = new List(); + if (!_callers.TryGetValue(start, out var callers)) _callers[start] = callers = new List<(int, bool)>(); + if (callers.Contains((caller, callerAfterElse))) return; + callers.Add((caller, callerAfterElse)); + foreach (var exit in exits!) Active(caller, exit, callerAfterElse); + if (!isNew) return; + + // Taken: the #if branch. Skipped: each later #elif may be the first branch taken, and an #else is + // taken once every earlier condition is false. + Active(start, start, afterElse: false); + foreach (var (kind, line) in _lines.Branches(start)) { - var kind = Classify(line); - if (kind == DirectiveKind.If) nested++; - else if (kind == DirectiveKind.EndIf && nested > 0) nested--; - else if (nested > 0 || afterElse && kind is DirectiveKind.Elif or DirectiveKind.Else) continue; - else if (kind == DirectiveKind.EndIf) - { - Active(LineEnd(line), groups[..^1]); - return; - } - else if (kind == DirectiveKind.Elif && !taken) Active(LineEnd(line), groups); - else if (kind == DirectiveKind.Else && taken) afterElse = true; + var next = _lines.LineEnd(line); + if (kind == DirectiveKind.Elif) Active(start, next, afterElse: false); else if (kind == DirectiveKind.Else) { - Active(LineEnd(line), groups[..^1] + Else); + Active(start, next, afterElse: true); return; } + else Exit(start, next); } } + private void Exit(int group, int position) + { + var exits = _exits[group]; + if (exits.Contains(position)) return; + exits.Add(position); + foreach (var (caller, afterElse) in _callers[group]) Active(caller, position, afterElse); + } + // Lexes active code from a line start up to the next directive and records the CRs of the - // well-formed strings on the way. Lexing is independent of the depth, so it runs once per start. + // well-formed strings on the way. Lexing is independent of the group, so it runs once per start. + // The lexer reads a token's whole leading trivia before returning it, so it lexes a window that + // doubles until the next directive's line is inside it; tokens before that line end before it, + // so the window does not change them. private (DirectiveKind Kind, int End)? NextDirective(int position) { if (_nextDirective.TryGetValue(position, out var cached)) return cached; - (DirectiveKind, int)? next = null; - foreach (var token in SyntaxFactory.ParseTokens(_text, position, position, Options)) + for (var length = 512; ; length *= 2) { - var directive = token.LeadingTrivia.FirstOrDefault(trivia => trivia.IsDirective); - if (directive.IsDirective) + var end = (int)Math.Min(_text.Length, (long)position + length); + var complete = end == _text.Length; + var strings = new List(); + (DirectiveKind, int)? next = null; + var found = false; + foreach (var token in SyntaxFactory.ParseTokens(_lexText.Substring(position, end - position), 0, position, Options)) { - var start = directive.SpanStart; - while (start > 0 && !SyntaxFacts.IsNewLine(_text[start - 1])) start--; - next = (Classify(start), LineEnd(start)); - break; + var directive = token.LeadingTrivia.FirstOrDefault(trivia => trivia.IsDirective); + if (directive.IsDirective) + { + var start = directive.SpanStart; + while (start > 0 && !SyntaxFacts.IsNewLine(_text[start - 1])) start--; + var lineEnd = _lines.LineEnd(start); + found = complete || lineEnd < end; + next = (_lines.Classify(start), lineEnd); + break; + } + if (token.IsKind(SyntaxKind.EndOfFileToken)) + { + found = complete || IsUnterminatedComment(token.LeadingTrivia.LastOrDefault()); + break; + } + strings.Add(token); } - if (token.IsKind(SyntaxKind.EndOfFileToken)) break; - CollectString(token); + if (!found) continue; + foreach (var token in strings) CollectString(token); + _nextDirective[position] = next; + return next; } - _nextDirective[position] = next; - return next; } + // A block comment with no "*/" after its opening runs to the end of the file, hiding everything after it. + private bool IsUnterminatedComment(SyntaxTrivia trivia) => + trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) && _lastCommentEnd < trivia.SpanStart + 2; + private void CollectString(SyntaxToken token) { if (token.IsKind(SyntaxKind.InterpolatedStringToken)) @@ -223,8 +268,106 @@ private static bool HasError(SyntaxToken token) return IsUnterminated(token) || literal is InterpolatedStringExpressionSyntax interpolated && interpolated.StringEndToken.IsMissing; } + } + + // The lines as Roslyn's scan of skipped text sees them, indexed so that a skipped group's #elif, #else, + // and #endif lines are found without rescanning the group. A skipped group ends at the first #endif + // that brings the #if/#endif count back below its level. + private sealed class Lines + { + private readonly string _text; + private readonly List _starts = new(); + private readonly Dictionary _index = new(); + private readonly List _kinds = new(); + // The #if minus #endif count before each line. + private readonly List _levels = new(); + private readonly Dictionary> _endIfsByLevel = new(); + private readonly Dictionary> _branchesByLevel = new(); + + public Lines(string text) + { + _text = text; + var level = 0; + for (var position = 0; position < text.Length; position = LineEnd(position)) + { + var line = _starts.Count; + var kind = Classify(position); + _index[position] = line; + _starts.Add(position); + _kinds.Add(kind); + _levels.Add(level); + if (kind == DirectiveKind.EndIf) Lookup(_endIfsByLevel, level).Add(line); + else if (kind is DirectiveKind.Elif or DirectiveKind.Else) Lookup(_branchesByLevel, level).Add(line); + if (kind == DirectiveKind.If) level++; + else if (kind == DirectiveKind.EndIf) level--; + } + } + + public const string TakenSymbol = "_"; + + // The lexer reads a whole skipped group before the token after a false #if, which would make + // lexing up to the next directive cost the rest of a deeply nested file. The copy it lexes has each + // #if condition made only of plain characters replaced, in place, by a defined symbol. Such + // characters lex the same as the symbol and spaces inside a string, comment, or skipped text, + // so token boundaries and offsets are unchanged. + public string WithTakenConditions() + { + var copy = _text.ToCharArray(); + for (var line = 0; line < _starts.Count; line++) + { + if (_kinds[line] != DirectiveKind.If) continue; + var start = SkipWhitespace(_text.IndexOf('#', _starts[line]) + 1) + "if".Length; + var end = start; + while (end < _text.Length && !SyntaxFacts.IsNewLine(_text[end])) end++; + // At least two characters: a space keeps the symbol apart from "if". + if (end - start < 2 || _text[start..end].Trim().Length == 0 || !_text[start..end].All(IsPlainConditionCharacter)) continue; + for (var i = start; i < end; i++) copy[i] = ' '; + copy[end - 1] = TakenSymbol[0]; + } + return new string(copy); + } + + private static bool IsPlainConditionCharacter(char c) => + char.IsAsciiLetterOrDigit(c) || c is '_' or '!' or '&' or '|' or '(' or ')' or '=' or ' ' or '\t'; + + // The start of the #endif line that closes the skipped group starting at position, if any. + public int? MatchingEndIf(int position) => + _index.TryGetValue(position, out var line) && EndIfLine(line) is { } endIf ? _starts[endIf] : null; + + // The #elif and #else lines at the level of the skipped group starting at position, then its #endif. + public IEnumerable<(DirectiveKind Kind, int Start)> Branches(int position) + { + if (!_index.TryGetValue(position, out var line)) yield break; + var endIf = EndIfLine(line); + if (_branchesByLevel.TryGetValue(_levels[line], out var branches)) + { + for (var i = FirstAtOrAfter(branches, line); i < branches.Count && (endIf is null || branches[i] < endIf); i++) + yield return (_kinds[branches[i]], _starts[branches[i]]); + } + if (endIf is { } end) yield return (DirectiveKind.EndIf, _starts[end]); + } + + private int? EndIfLine(int line) + { + if (!_endIfsByLevel.TryGetValue(_levels[line], out var endIfs)) return null; + var i = FirstAtOrAfter(endIfs, line); + return i < endIfs.Count ? endIfs[i] : null; + } + + private static int FirstAtOrAfter(List sorted, int value) + { + var i = sorted.BinarySearch(value); + return i >= 0 ? i : ~i; + } + + private static List Lookup(Dictionary> map, int key) + { + if (!map.TryGetValue(key, out var list)) map[key] = list = new List(); + return list; + } + // The conditional directive starting a line: '#' and its name after optional whitespace. - private DirectiveKind Classify(int line) + public DirectiveKind Classify(int line) { var i = SkipWhitespace(line); if (i >= _text.Length || _text[i] != '#') return DirectiveKind.Other; @@ -248,7 +391,7 @@ private int SkipWhitespace(int i) } // The start of the next line; CRLF is one line break. - private int LineEnd(int i) + public int LineEnd(int i) { while (i < _text.Length && !SyntaxFacts.IsNewLine(_text[i])) i++; if (i < _text.Length && _text[i] == '\r' && i + 1 < _text.Length && _text[i + 1] == '\n') i++; diff --git a/lsp/Server.Core/Server.Core.csproj b/lsp/Server.Core/Server.Core.csproj index 6dbc53fb..2fd19655 100644 --- a/lsp/Server.Core/Server.Core.csproj +++ b/lsp/Server.Core/Server.Core.csproj @@ -7,4 +7,7 @@ + + + diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 8cd8d8b7..bc9402db 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -430,6 +430,68 @@ public void ApplyNewlines_KeepsClosedStringCrsInBranchesHiddenByUnterminatedLite Assert.Equal(input, format.ApplyNewlines(input)); } + // #520: each nested group is solved once, so a string whose "#else" line splits a group in two does + // not double the work per nesting level. + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ApplyNewlines_StaysFastAcrossDeeplyNestedBranches(bool nestInElif) + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + const string literal = "var v = @\"p\r#else\rq\";\n"; + var input = "int x = 1;\r\n"; + for (var depth = 1; depth <= 30; depth++) + { + input = nestInElif + ? "#if A" + depth + "\nint y;\n#elif B" + depth + "\n" + literal + input + "#endif\n" + : "#if A" + depth + "\n" + literal + input + "#elif B" + depth + "\n" + literal + "#endif\n"; + } + + var watch = System.Diagnostics.Stopwatch.StartNew(); + var actual = format.ApplyNewlines(input); + watch.Stop(); + + Assert.Equal(input.Replace("\r\n", "\n"), actual); + Assert.True(watch.Elapsed < TimeSpan.FromSeconds(1), "took " + watch.Elapsed); + } + + // #520: the cost follows the directive count: no state rescans a skipped group, a run of directives, + // or an unterminated comment that the lexer reads to the end of the file. + [Theory] + [InlineData("nested")] + [InlineData("elif")] + [InlineData("comment")] + [InlineData("stray")] + public void ApplyNewlines_StaysFastWithThousandsOfDirectives(string shape) + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + var input = shape switch + { + "nested" => string.Concat(Enumerable.Repeat("#if A\nint a;\r", 2000)) + string.Concat(Enumerable.Repeat("#endif\n", 2000)), + "elif" => "#if A\nint a;\r" + string.Concat(Enumerable.Range(0, 4000).Select(i => "#elif S" + i + "\nint a;\r")) + "#endif\n", + "comment" => string.Concat(Enumerable.Repeat("#if A\n/*\n#endif\nint a;\r", 1000)), + _ => string.Concat(Enumerable.Repeat("#endif\n#else\nint a;\r", 2000)), + }; + + var watch = System.Diagnostics.Stopwatch.StartNew(); + var actual = format.ApplyNewlines(input); + watch.Stop(); + + Assert.Equal(input.Replace("\r", "\n"), actual); + Assert.True(watch.Elapsed < TimeSpan.FromSeconds(3), "took " + watch.Elapsed); + } + + // #520: past its state budget the scan cannot tell string CRs from line breaks, so it keeps every lone CR. + [Fact] + public void ApplyNewlines_KeepsEveryLoneCrWhenTheScanExceedsItsBudget() + { + var format = LspSourceFileFormat.Detect(Encoding.UTF8.GetBytes("a\nb\n")); + const string input = "#if A\nvar a = @\"x\ry\";\r#else\nint b;\r\n#endif\n"; + + Assert.Equal("#if A\nvar a = @\"x\ry\";\r#else\nint b;\n#endif\n", format.ApplyNewlines(input, maxScanStates: 1)); + Assert.Equal("#if A\nvar a = @\"x\ry\";\n#else\nint b;\n#endif\n", format.ApplyNewlines(input)); + } + private static byte[] Encode(string lfText, string encoding, string newline) { Encoding target = encoding switch From ac865dead7aeb11a47b8f685325233e8e71a9afd Mon Sep 17 00:00:00 2001 From: akiojin Date: Wed, 14 Oct 2026 15:43:11 +0900 Subject: [PATCH 69/73] fix(lsp): preserve nested literals and oracle string content --- ...5c466f58f19e0e1cedbf2ea8d401b8997bb6.jsonl | 1 + ...4f8a90bb135ccb359e85f7e6397f7fc58eb8.jsonl | 1 + ...841b3d7856a820d69ac429ec5bf75a28e795.jsonl | 1 + ...c8f5cb6a847000ce98d4708bdaea7aba04f5.jsonl | 1 + ...fed6e26722b1ce0ec23d228c83b5c83b3a3e.jsonl | 1 + ...3cf50965552eabe0e82ef77cf38ee5d807db.jsonl | 1 + ...0fd3f858a6e97fab37f8e1ccb58aaab139f5.jsonl | 1 + ...15642e69200aa39bc8d29606d04659920fdf.jsonl | 1 + ...267f332f994b79ee25d09d60ddbb45310c8f.jsonl | 1 + lsp/Server.Core/LspSourceFile.cs | 12 ++- lsp/SourceFileFormatOracleTests.cs | 93 +++++++++++++------ lsp/SourceFileFormatTests.cs | 26 ++++++ 12 files changed, 108 insertions(+), 32 deletions(-) create mode 100644 .gwt/work/events/03/03bbaa8914b9928f4ba937590b265c466f58f19e0e1cedbf2ea8d401b8997bb6.jsonl create mode 100644 .gwt/work/events/1c/1c40465646d8f462527102859bfc4f8a90bb135ccb359e85f7e6397f7fc58eb8.jsonl create mode 100644 .gwt/work/events/2f/2fb1ab5f402ffab8b0f4a5c7bb32841b3d7856a820d69ac429ec5bf75a28e795.jsonl create mode 100644 .gwt/work/events/37/3723641c1ce4c73b4f89b1ee25efc8f5cb6a847000ce98d4708bdaea7aba04f5.jsonl create mode 100644 .gwt/work/events/73/73b467d1e0a3cc013a72b0652e38fed6e26722b1ce0ec23d228c83b5c83b3a3e.jsonl create mode 100644 .gwt/work/events/7b/7b6b4995bb17c553187016b9b3c83cf50965552eabe0e82ef77cf38ee5d807db.jsonl create mode 100644 .gwt/work/events/ab/abc231a6dd43be48ac970c69e1d90fd3f858a6e97fab37f8e1ccb58aaab139f5.jsonl create mode 100644 .gwt/work/events/bd/bd8505d24c63b97797a97e0499fe15642e69200aa39bc8d29606d04659920fdf.jsonl create mode 100644 .gwt/work/events/f6/f63643df3e6f6ed1256f4c39c188267f332f994b79ee25d09d60ddbb45310c8f.jsonl diff --git a/.gwt/work/events/03/03bbaa8914b9928f4ba937590b265c466f58f19e0e1cedbf2ea8d401b8997bb6.jsonl b/.gwt/work/events/03/03bbaa8914b9928f4ba937590b265c466f58f19e0e1cedbf2ea8d401b8997bb6.jsonl new file mode 100644 index 00000000..7c3a344c --- /dev/null +++ b/.gwt/work/events/03/03bbaa8914b9928f4ba937590b265c466f58f19e0e1cedbf2ea8d401b8997bb6.jsonl @@ -0,0 +1 @@ +{"id":"7cb0a09c-e15c-431f-b271-67f29b647da0","work_item_id":"work-work-issue-520-2c5b16f7","kind":"update","title":null,"intent":"2,000生成件一致を確認し、全LSP・coverageの正式検証","summary":null,"progress_summary":"AC-1を含む未配送ソースを保全。AC-2固定RED8件と拡張生成器11不一致を最小修正し、2,000件不一致0。","status_category":null,"owner":"Issue #520","next_action":null,"agent_session_id":"fad8f3f5-654a-4ea4-b0c6-e65546d2f5bb","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:\\unity-cli\\work\\issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T06:29:26.841141500Z"} diff --git a/.gwt/work/events/1c/1c40465646d8f462527102859bfc4f8a90bb135ccb359e85f7e6397f7fc58eb8.jsonl b/.gwt/work/events/1c/1c40465646d8f462527102859bfc4f8a90bb135ccb359e85f7e6397f7fc58eb8.jsonl new file mode 100644 index 00000000..768bb288 --- /dev/null +++ b/.gwt/work/events/1c/1c40465646d8f462527102859bfc4f8a90bb135ccb359e85f7e6397f7fc58eb8.jsonl @@ -0,0 +1 @@ +{"id":"c412255e-4eff-4fa9-9b63-27824161bde8","work_item_id":"work-work-issue-520-2c5b16f7","kind":"resume","title":"fix(lsp): keep closed-string CRs in sibling branches hidden by an unterminated literal (#516 follow-up)","intent":"3 active agents","summary":"3 active agents","progress_summary":null,"status_category":"active","owner":"Issue #520","next_action":"Check Board for latest updates","agent_session_id":"fad8f3f5-654a-4ea4-b0c6-e65546d2f5bb","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:/unity-cli/work/issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T06:13:18.980268300Z"} diff --git a/.gwt/work/events/2f/2fb1ab5f402ffab8b0f4a5c7bb32841b3d7856a820d69ac429ec5bf75a28e795.jsonl b/.gwt/work/events/2f/2fb1ab5f402ffab8b0f4a5c7bb32841b3d7856a820d69ac429ec5bf75a28e795.jsonl new file mode 100644 index 00000000..6c611089 --- /dev/null +++ b/.gwt/work/events/2f/2fb1ab5f402ffab8b0f4a5c7bb32841b3d7856a820d69ac429ec5bf75a28e795.jsonl @@ -0,0 +1 @@ +{"id":"c1ba1255-13f1-49a2-8bd8-44a812e57911","work_item_id":"work-work-issue-520-2c5b16f7","kind":"done","title":null,"intent":"実装と正式検証済み。PR #521への配送と新SHA独立レビュー・CI確認","summary":null,"progress_summary":"AC-2のoracle条件置換とliteral単位の終端判定、回復trivia再帰走査を修正。2,000生成件不一致0、839 LSP/15 Python、coverage99.62%、400分岐約34ms。次はcommit/push→fresh verify→PM独立レビュー→Ready/CI auto-merge。Issueはdevelop配送まで完了扱いにしない。","status_category":"done","owner":"Issue #520","next_action":null,"agent_session_id":"fad8f3f5-654a-4ea4-b0c6-e65546d2f5bb","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:\\unity-cli\\work\\issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T06:43:07.812719400Z"} diff --git a/.gwt/work/events/37/3723641c1ce4c73b4f89b1ee25efc8f5cb6a847000ce98d4708bdaea7aba04f5.jsonl b/.gwt/work/events/37/3723641c1ce4c73b4f89b1ee25efc8f5cb6a847000ce98d4708bdaea7aba04f5.jsonl new file mode 100644 index 00000000..7ac31081 --- /dev/null +++ b/.gwt/work/events/37/3723641c1ce4c73b4f89b1ee25efc8f5cb6a847000ce98d4708bdaea7aba04f5.jsonl @@ -0,0 +1 @@ +{"id":"af94df37-d68b-45cd-a50e-847052424e98","work_item_id":"work-work-issue-520-2c5b16f7","kind":"update","title":"Issue #520 閉じたソースの整合性修正","intent":"要件・未配送差分と実行契約の確認","summary":null,"progress_summary":null,"status_category":null,"owner":"Issue #520","next_action":null,"agent_session_id":"fad8f3f5-654a-4ea4-b0c6-e65546d2f5bb","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:\\unity-cli\\work\\issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T06:15:34.019590200Z"} diff --git a/.gwt/work/events/73/73b467d1e0a3cc013a72b0652e38fed6e26722b1ce0ec23d228c83b5c83b3a3e.jsonl b/.gwt/work/events/73/73b467d1e0a3cc013a72b0652e38fed6e26722b1ce0ec23d228c83b5c83b3a3e.jsonl new file mode 100644 index 00000000..1c17cb37 --- /dev/null +++ b/.gwt/work/events/73/73b467d1e0a3cc013a72b0652e38fed6e26722b1ce0ec23d228c83b5c83b3a3e.jsonl @@ -0,0 +1 @@ +{"id":"555af658-147e-45ed-a0fd-81dbc39e0299","work_item_id":"work-work-issue-520-2c5b16f7","kind":"resume","title":"fix(lsp): keep closed-string CRs in sibling branches hidden by an unterminated literal (#516 follow-up)","intent":"3 active agents","summary":"3 active agents","progress_summary":null,"status_category":"active","owner":"Issue #520","next_action":"Check Board for latest updates","agent_session_id":"f97055a1-cd47-43bf-9694-0bf7ec2bc1a4","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:/unity-cli/work/issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T05:56:32.056995800Z"} diff --git a/.gwt/work/events/7b/7b6b4995bb17c553187016b9b3c83cf50965552eabe0e82ef77cf38ee5d807db.jsonl b/.gwt/work/events/7b/7b6b4995bb17c553187016b9b3c83cf50965552eabe0e82ef77cf38ee5d807db.jsonl new file mode 100644 index 00000000..3dd34dbf --- /dev/null +++ b/.gwt/work/events/7b/7b6b4995bb17c553187016b9b3c83cf50965552eabe0e82ef77cf38ee5d807db.jsonl @@ -0,0 +1 @@ +{"id":"f4286761-bffe-484b-ae2d-4f86d9e2317f","work_item_id":"work-work-issue-520-2c5b16f7","kind":"start","title":"fix(lsp): keep closed-string CRs in sibling branches hidden by an unterminated literal (#516 follow-up)","intent":"Check Board for latest updates","summary":"Codex is running","progress_summary":null,"status_category":"active","owner":"Issue #520","next_action":"Check Board for latest updates","agent_session_id":"6acf4230-981e-436f-be5c-c4f470ebbee7","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:\\unity-cli\\work\\issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T05:17:01.340837900Z"} diff --git a/.gwt/work/events/ab/abc231a6dd43be48ac970c69e1d90fd3f858a6e97fab37f8e1ccb58aaab139f5.jsonl b/.gwt/work/events/ab/abc231a6dd43be48ac970c69e1d90fd3f858a6e97fab37f8e1ccb58aaab139f5.jsonl new file mode 100644 index 00000000..6e2e8bd9 --- /dev/null +++ b/.gwt/work/events/ab/abc231a6dd43be48ac970c69e1d90fd3f858a6e97fab37f8e1ccb58aaab139f5.jsonl @@ -0,0 +1 @@ +{"id":"5f11c1c6-23c4-4103-9d81-6225112a154c","work_item_id":"work-work-issue-520-2c5b16f7","kind":"resume","title":"fix(lsp): keep closed-string CRs in sibling branches hidden by an unterminated literal (#516 follow-up)","intent":"Codex is ready for the next instruction on Issue #520 fix(lsp): keep closed-string CRs in sibling branches hidden by an unterminated literal (#516 follow-up) (work/issue-520)","summary":"3 active agents","progress_summary":null,"status_category":"active","owner":"Issue #520","next_action":"Check Board for latest updates","agent_session_id":"24541411-db4e-4036-b84a-7d3017c8757e","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:/unity-cli/work/issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T05:52:06.788146100Z"} diff --git a/.gwt/work/events/bd/bd8505d24c63b97797a97e0499fe15642e69200aa39bc8d29606d04659920fdf.jsonl b/.gwt/work/events/bd/bd8505d24c63b97797a97e0499fe15642e69200aa39bc8d29606d04659920fdf.jsonl new file mode 100644 index 00000000..388a6119 --- /dev/null +++ b/.gwt/work/events/bd/bd8505d24c63b97797a97e0499fe15642e69200aa39bc8d29606d04659920fdf.jsonl @@ -0,0 +1 @@ +{"id":"ba79a513-351f-426e-88c3-b67b4a7fc2ee","work_item_id":"work-work-issue-520-2c5b16f7","kind":"update","title":null,"intent":"AC-2拡張生成器で検出した構文回復の不一致を修正","summary":null,"progress_summary":"実行権限復旧。固定RED8件確認、元の1000生成件は一致。拡張生成器11不一致の原因を特定。","status_category":null,"owner":"Issue #520","next_action":null,"agent_session_id":"fad8f3f5-654a-4ea4-b0c6-e65546d2f5bb","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:\\unity-cli\\work\\issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T06:22:38.931324900Z"} diff --git a/.gwt/work/events/f6/f63643df3e6f6ed1256f4c39c188267f332f994b79ee25d09d60ddbb45310c8f.jsonl b/.gwt/work/events/f6/f63643df3e6f6ed1256f4c39c188267f332f994b79ee25d09d60ddbb45310c8f.jsonl new file mode 100644 index 00000000..499b7dff --- /dev/null +++ b/.gwt/work/events/f6/f63643df3e6f6ed1256f4c39c188267f332f994b79ee25d09d60ddbb45310c8f.jsonl @@ -0,0 +1 @@ +{"id":"17033026-3813-4a43-a7d9-5667e4424725","work_item_id":"work-work-issue-520-2c5b16f7","kind":"resume","title":"fix(lsp): keep closed-string CRs in sibling branches hidden by an unterminated literal (#516 follow-up)","intent":"Codex started work on Issue #520 fix(lsp): keep closed-string CRs in sibling branches hidden by an unterminated literal (#516 follow-up) (work/issue-520)","summary":"2 active agents","progress_summary":null,"status_category":"active","owner":"Issue #520","next_action":"Check Board for latest updates","agent_session_id":"b2230ae6-4256-4a85-b63c-c8a3a6dd9132","agent_id":"codex","display_name":"Codex","board_entry_id":null,"execution_container":{"branch":"work/issue-520","worktree_path":"E:/unity-cli/work/issue-520","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T05:31:52.463721300Z"} diff --git a/lsp/Server.Core/LspSourceFile.cs b/lsp/Server.Core/LspSourceFile.cs index 0a289468..00bc0dc2 100644 --- a/lsp/Server.Core/LspSourceFile.cs +++ b/lsp/Server.Core/LspSourceFile.cs @@ -189,18 +189,20 @@ private void ScanSkipped(int position, string groups, bool taken) return next; } - private void CollectString(SyntaxToken token) + private void CollectString(SyntaxToken token, int offset = 0) { if (token.IsKind(SyntaxKind.InterpolatedStringToken)) { - if (IsUnterminated(token)) return; // The lexer reads an interpolated string as one token; its holes are code, not content. - foreach (var part in SyntaxFactory.ParseExpression(token.Text, options: Options).DescendantTokens()) + // Judge each parsed literal separately: a closed literal in a hole still counts when + // the outer interpolation is unterminated. HasError rejects only the outer text. + // Error recovery may put a closed inner literal in skipped-token trivia. + foreach (var part in SyntaxFactory.ParseExpression(token.Text, options: Options).DescendantTokens(descendIntoTrivia: true)) { - if (IsMultiLineStringContent(part.Kind()) && !HasError(part)) Add(token.SpanStart + part.SpanStart, token.SpanStart + part.Span.End); + CollectString(part, offset + token.SpanStart); } } - else if (IsMultiLineStringContent(token.Kind()) && !HasError(token)) Add(token.SpanStart, token.Span.End); + else if (IsMultiLineStringContent(token.Kind()) && !HasError(token)) Add(offset + token.SpanStart, offset + token.Span.End); } private void Add(int start, int end) diff --git a/lsp/SourceFileFormatOracleTests.cs b/lsp/SourceFileFormatOracleTests.cs index 729a7a77..99feeeb3 100644 --- a/lsp/SourceFileFormatOracleTests.cs +++ b/lsp/SourceFileFormatOracleTests.cs @@ -14,27 +14,39 @@ public sealed class SourceFileFormatOracleTests { private static readonly LspSourceFileFormat LfFile = new(new UTF8Encoding(false), "\n"); - // Rewrites every #if/#elif condition to its own symbol and parses each subset of those symbols. A lone - // CR is kept iff some configuration reads it inside a closed multi-line string literal. + // Enumerates independent choices for every candidate #if/#elif, letting Roslyn decide which lines + // are directives in each configuration. A lone CR is kept iff some configuration reads it inside a + // closed multi-line string literal. private static string Oracle(string text) { - var builder = new StringBuilder(text); - var symbols = 0; - foreach (Match line in Regex.Matches(text, @"(?<=^|[\r\n])[ \t]*#[ \t]*(if|elif)[ \t]+[^\r\n]*")) - { - var head = Regex.Match(line.Value, @"^[ \t]*#[ \t]*(if|elif)[ \t]+"); - if (line.Length == head.Length) continue; - var symbol = ((char)('a' + symbols++)).ToString(); - var replacement = symbol.PadRight(line.Length - head.Length); - for (var k = 0; k < replacement.Length; k++) builder[line.Index + head.Length + k] = replacement[k]; - } - - var rewritten = builder.ToString(); + var candidates = Regex.Matches(text, @"(?<=^|[\r\n])[ \t]*#[ \t]*(if|elif)[ \t]+[^\r\n]*"); + Assert.InRange(candidates.Count, 0, 7); // Exhaustive enumeration is deliberately test-only and bounded. var keep = new HashSet(); - for (var mask = 0; mask < 1 << symbols; mask++) + for (var mask = 0; mask < 1 << candidates.Count; mask++) { - var defined = Enumerable.Range(0, symbols).Where(i => (mask & (1 << i)) != 0).Select(i => ((char)('a' + i)).ToString()); - var root = CSharpSyntaxTree.ParseText(rewritten, CSharpParseOptions.Default.WithPreprocessorSymbols(defined)).GetRoot(); + var defined = Enumerable.Range(0, candidates.Count).Where(i => (mask & (1 << i)) != 0).Select(i => ((char)('a' + i)).ToString()); + var options = CSharpParseOptions.Default.WithPreprocessorSymbols(defined); + var builder = new StringBuilder(text); + var root = CSharpSyntaxTree.ParseText(text, options).GetRoot(); + for (var i = 0; i < candidates.Count; i++) + { + var line = candidates[i]; + var hash = text.IndexOf('#', line.Index); + var directive = root.DescendantTrivia(descendIntoTrivia: true) + .FirstOrDefault(trivia => trivia.IsDirective && trivia.SpanStart == hash).GetStructure(); + var condition = directive switch + { + IfDirectiveTriviaSyntax ifDirective => ifDirective.Condition, + ElifDirectiveTriviaSyntax elifDirective => elifDirective.Condition, + _ => null, + }; + if (condition is null || condition.Span.IsEmpty) continue; + // Apply choices in source order, re-parsing before the next candidate. An earlier choice + // can expose a string containing a later '#if'; never overwrite that string's contents. + var replacement = ((char)('a' + i)).ToString().PadRight(condition.Span.Length); + for (var k = 0; k < replacement.Length; k++) builder[condition.SpanStart + k] = replacement[k]; + root = CSharpSyntaxTree.ParseText(builder.ToString(), options).GetRoot(); + } foreach (var token in root.DescendantTokens(descendIntoTrivia: true)) Keep(token, 0); } @@ -44,7 +56,7 @@ void Keep(SyntaxToken token, int offset) { if (token.IsKind(SyntaxKind.InterpolatedStringToken)) { - foreach (var part in SyntaxFactory.ParseExpression(token.Text).DescendantTokens()) Keep(part, offset + token.SpanStart); + foreach (var part in SyntaxFactory.ParseExpression(token.Text).DescendantTokens(descendIntoTrivia: true)) Keep(part, offset + token.SpanStart); return; } if (!token.IsKind(SyntaxKind.StringLiteralToken) && !token.IsKind(SyntaxKind.Utf8StringLiteralToken) && @@ -81,34 +93,61 @@ void Keep(SyntaxToken token, int offset) private static readonly string[] Conditions = { "A", "B", "false", "true", "C" }; - private static string Block(Random random, int depth) + private static readonly string[] RegressionFragments = Fragments.Concat(new[] + { + "var s = @\"x\r#if A\";\n", "var s = $@\"x\r#elif A\";\n", + "var s = $@\"outer\n{ @\"inner\rtext\" }\n", "var s = $@\"outer\n{ $@\"inner\r{1}\" }\n", + }).ToArray(); + + private static string Block(Random random, int depth, bool includeRegressions) { var builder = new StringBuilder(); for (var n = random.Next(1, 4); n > 0; n--) { if (depth < 3 && random.Next(3) == 0) { - builder.Append("#if " + Conditions[random.Next(Conditions.Length)] + "\n").Append(Block(random, depth + 1)); - if (random.Next(2) == 0) builder.Append("#elif " + Conditions[random.Next(Conditions.Length)] + "\n").Append(Block(random, depth + 1)); - if (random.Next(2) == 0) builder.Append("#else\n").Append(Block(random, depth + 1)); + builder.Append("#if " + Conditions[random.Next(Conditions.Length)] + "\n").Append(Block(random, depth + 1, includeRegressions)); + if (random.Next(2) == 0) builder.Append("#elif " + Conditions[random.Next(Conditions.Length)] + "\n").Append(Block(random, depth + 1, includeRegressions)); + if (random.Next(2) == 0) builder.Append("#else\n").Append(Block(random, depth + 1, includeRegressions)); builder.Append("#endif\n"); } - else builder.Append(Fragments[random.Next(Fragments.Length)]); + else + { + var fragments = includeRegressions ? RegressionFragments : Fragments; + builder.Append(fragments[random.Next(fragments.Length)]); + } } return builder.ToString(); } private static string Show(string text) => text.Replace("\r", "\\r").Replace("\n", "\\n"); - [Fact] - public void ApplyNewlines_MatchesTheAllConfigurationsOracleOnGeneratedSources() + [Theory] + [InlineData("var s = @\"x\r#if A\";\n")] + [InlineData("var s = @\"x\r#elif A\";\n")] + [InlineData("#if A\nvar s = @\"x\r#if B\";\n#endif\n")] + [InlineData("#if A\nvar s = $@\"x\r#if B\";\n#endif\n")] + [InlineData("#if A\nvar s = \"\"\"\nx\r#if B\r\"\"\";\n#endif\n")] + [InlineData("var s = $@\"outer\n{ @\"inner\rtext\" }\n")] + [InlineData("var s = $@\"outer\n{ $@\"inner\r{1}\" }\n")] + [InlineData("var s = $$\"\"\"\nouter\n{{ @\"inner\rtext\" }}\n")] + public void Oracle_PreservesClosedLiteralContent(string input) + { + Assert.Equal(input, Oracle(input)); + Assert.Equal(input, LfFile.ApplyNewlines(input)); + } + + [Theory] + [InlineData(516, false)] + [InlineData(520, true)] + public void ApplyNewlines_MatchesTheAllConfigurationsOracleOnGeneratedSources(int seed, bool includeRegressions) { - var random = new Random(516); + var random = new Random(seed); var compared = 0; var mismatches = new List(); for (var iteration = 0; iteration < 50000 && compared < 1000; iteration++) { - var text = Block(random, 0); + var text = Block(random, 0, includeRegressions); if (!text.Contains('\r') || Regex.Matches(text, "#if|#elif").Count > 7) continue; compared++; var expected = Oracle(text); diff --git a/lsp/SourceFileFormatTests.cs b/lsp/SourceFileFormatTests.cs index 8cd8d8b7..ff9de4b7 100644 --- a/lsp/SourceFileFormatTests.cs +++ b/lsp/SourceFileFormatTests.cs @@ -405,6 +405,32 @@ public void ApplyNewlines_NormalizesCrsInInactiveCommentsAndDirectiveMessages() Assert.Equal(input.Replace("\r", "\n"), format.ApplyNewlines(input)); } + [Theory] + [InlineData("var s = $@\"outer\n{ @\"inner\rtext\" }\n")] + [InlineData("var s = $@\"outer\n{ $@\"inner\r{1}\" }\n")] + [InlineData("var s = $$\"\"\"\nouter\n{{ @\"inner\rtext\" }}\n")] + public void ApplyNewlines_KeepsClosedInnerLiteralCrsInUnterminatedInterpolation(string input) + { + var format = new LspSourceFileFormat(new UTF8Encoding(false), "\n"); + Assert.Equal(input, format.ApplyNewlines(input)); + } + + [Fact] + public void ApplyNewlines_NormalizesOnlyUnterminatedOuterInterpolationCrs() + { + var format = new LspSourceFileFormat(new UTF8Encoding(false), "\n"); + Assert.Equal("var s = $@\"outer\n{ @\"inner\rtext\" }\n", + format.ApplyNewlines("var s = $@\"outer\r{ @\"inner\rtext\" }\r")); + } + + [Fact] + public void ApplyNewlines_KeepsRecoveredFieldLiteralAfterUnterminatedInterpolation() + { + const string input = "var s = $@\"outer\n{ @\"inner\rtext\" }\nclass C { string f = @\"a\r#else\rb\"; }\n"; + var format = new LspSourceFileFormat(new UTF8Encoding(false), "\n"); + Assert.Equal(input, format.ApplyNewlines(input)); + } + // #520: an unterminated literal in one branch must not hide a sibling branch, and a directive-looking // line inside a nested branch's string must not close the wrong group. Each input keeps its CRs // because some branch-selection configuration reads them inside a closed string. From 69d5d8d3dd3427ea043c985d499fbd087dff1968 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 00:08:37 +0000 Subject: [PATCH 70/73] chore(deps): bump the npm_and_yarn group with 3 updates --- updated-dependencies: - dependency-name: "@google/gemini-cli" dependency-version: 0.64.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm_and_yarn - dependency-name: "@openai/codex" dependency-version: 0.163.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm_and_yarn - dependency-name: prettier dependency-version: 3.9.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package.json | 6 ++-- pnpm-lock.yaml | 80 +++++++++++++++++++++++++------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 34f8142b..2bfea999 100644 --- a/package.json +++ b/package.json @@ -18,13 +18,13 @@ "@commitlint/cli": "^21.1.0", "@commitlint/config-conventional": "^21.1.0", "@eslint/js": "^10.0.1", - "@google/gemini-cli": "^0.63.0", - "@openai/codex": "^0.162.0", + "@google/gemini-cli": "^0.64.0", + "@openai/codex": "^0.163.0", "eslint": "^10.12.0", "globals": "^17.13.0", "husky": "^9.1.7", "markdownlint-cli": "^0.49.0", - "prettier": "^3.9.1" + "prettier": "^3.9.10" }, "overrides": { "markdownlint-cli": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84ce9760..a16356cd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,11 +28,11 @@ importers: specifier: ^10.0.1 version: 10.0.1(eslint@10.12.0(jiti@2.6.1)) '@google/gemini-cli': - specifier: ^0.63.0 - version: 0.63.0 + specifier: ^0.64.0 + version: 0.64.0 '@openai/codex': - specifier: ^0.162.0 - version: 0.162.0 + specifier: ^0.163.0 + version: 0.163.0 eslint: specifier: ^10.12.0 version: 10.12.0(jiti@2.6.1) @@ -46,8 +46,8 @@ importers: specifier: ^0.49.0 version: 0.49.1 prettier: - specifier: ^3.9.1 - version: 3.9.9 + specifier: ^3.9.10 + version: 3.9.10 packages: @@ -192,8 +192,8 @@ packages: '@github/keytar@7.10.6': resolution: {integrity: sha512-mRW6cUsSG+nj4jp5gp8e91zPySaT73r+2JM6VyMZfrEgksjPmjSMr+tPGNOK3HUHV+GUU9B1LAiiYy/wmAnIxA==} - '@google/gemini-cli@0.63.0': - resolution: {integrity: sha512-mmhqMmAdsoplCzrLQQC4yJBqr4uSKXghnrLspgUU6N9drmsaq7pi7oF09skRYzEq2dYK6eMT4UpFQP6rG2o/ew==} + '@google/gemini-cli@0.64.0': + resolution: {integrity: sha512-FHrZ1NPf9QszyVMaa/BP3SsPy40ogBLnbZNWkv/PMi1Uz2zoDNMLGiBzBGmx4Bl7iLRq01K9PY/5kmloXFTpsA==} engines: {node: '>=20'} hasBin: true @@ -259,43 +259,43 @@ packages: '@lydell/node-pty@1.1.0': resolution: {integrity: sha512-VDD8LtlMTOrPKWMXUAcB9+LTktzuunqrMwkYR1DMRBkS6LQrCt+0/Ws1o2rMml/n3guePpS7cxhHF7Nm5K4iMw==} - '@openai/codex@0.162.0': - resolution: {integrity: sha512-qWWckMfknyVym1lD5y2rTwPJA2sgHkzePF2l/Uevss4hVpqbt23rMIHKNTrqECdnv82denylHWEzrAmDnCYNIw==} + '@openai/codex@0.163.0': + resolution: {integrity: sha512-HNd7vR9oTK6M2ikxFnvNDCdYUgAsyo9VVnd5KnEd2ON0GYI++7MiX9XNPUkhtdgGKFPsWS+CEppQ1UU63uVhUw==} engines: {node: '>=16'} hasBin: true - '@openai/codex@0.162.0-darwin-arm64': - resolution: {integrity: sha512-hyiGlMCbZog7IY2TcSWzXbsmtUnynT93QA4utqGlVmFlmz8TurADk3LV28zqUIdgh9GLOzumDIdHQbYieo9Nqw==} + '@openai/codex@0.163.0-darwin-arm64': + resolution: {integrity: sha512-i7Dzk2a5aGmuGM9aNZgaUVTojZ/4bc5lRfosz++Y7X2BGhDkz+cySgbD+NYS1pOxfm0VEbLi9PZ3pAulI4kchw==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@openai/codex@0.162.0-darwin-x64': - resolution: {integrity: sha512-4XzCUJgEDDdme6VWDEKvbWDA6f+470d4xhhorYUgNBZwY8Dq5NYqvWkO33rnc1vjxkqSj+SwkymHxRMxL6h1CA==} + '@openai/codex@0.163.0-darwin-x64': + resolution: {integrity: sha512-Ioj7h+B1ME9ZU1PH1ATfvFV5DiototEpFFaSSbg3kfDifB9djhl5fcJ++g5mpcL/+uVbcnReei+RiSXEx8o+kw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@openai/codex@0.162.0-linux-arm64': - resolution: {integrity: sha512-6NYWwy09FsZ+/0Dz/bvV/yz3aFhkNzj86fSiux9Ax9VMBOID5nPdwd51OySm7fy8TMRud4fgJFELSi3Enc1s7Q==} + '@openai/codex@0.163.0-linux-arm64': + resolution: {integrity: sha512-IH2/R+4OarjGvsAf1ll3fdyLwrPgYLl3uzp6u9CyD9sj2Lw+ViDSe3QBZVHdcHJs0eIiZFg6Wprcuy4CRZaUGw==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@openai/codex@0.162.0-linux-x64': - resolution: {integrity: sha512-qHWp6oKpf456PqjberGN8avs8zChv2oS+UuDiqVFYAuDOhq6vBc1drh8jEsnR7dBX+zcw03PN5VLtePGlMcC3w==} + '@openai/codex@0.163.0-linux-x64': + resolution: {integrity: sha512-uwRaOsrYogLQhcxAM/GoeWrw0QIWEMRo7c9gM8sKAviVkZQHlu9kRLJ5PkufbV+ABGjyZgIwiFdJ0LCJ0N6e8w==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@openai/codex@0.162.0-win32-arm64': - resolution: {integrity: sha512-scdBHlUz4AfLOUWT4r4kwe3GFvjbBbWxreLDGoLSyMFf566e7sHSJvlJuV7uha2S7uRoQnMmWwmqYMJuT322UQ==} + '@openai/codex@0.163.0-win32-arm64': + resolution: {integrity: sha512-QnLn3gR2dExcdTThE/HAo5BrUq0/C8zDGQ0UZL3hNzfqt9ZklT6jGTyt8JhDyNZX4uSB4HhcJtbcOWucZGC0VQ==} engines: {node: '>=16'} cpu: [arm64] os: [win32] - '@openai/codex@0.162.0-win32-x64': - resolution: {integrity: sha512-W8kqHaqpW0qPz71E0rRT5dq+socGz1BbJyYN7o3SP1TWQt8Zl6ML74R9Hvt/xn1NNLVlDTRfXqNmaMkte6yEMQ==} + '@openai/codex@0.163.0-win32-x64': + resolution: {integrity: sha512-QQGQ/q9dCJ5C5jqhgFrwycpWG3szIyFNThMiKl6hYtu6N/eM3Qd7StesgnCFAfzVED8IkE3N3oH71szzcludqw==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -868,8 +868,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.9.9: - resolution: {integrity: sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==} + prettier@3.9.10: + resolution: {integrity: sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==} engines: {node: '>=14'} hasBin: true @@ -1169,7 +1169,7 @@ snapshots: node-addon-api: 8.9.2 optional: true - '@google/gemini-cli@0.63.0': + '@google/gemini-cli@0.64.0': optionalDependencies: '@github/keytar': 7.10.6 '@lydell/node-pty': 1.1.0 @@ -1232,31 +1232,31 @@ snapshots: '@lydell/node-pty-win32-x64': 1.1.0 optional: true - '@openai/codex@0.162.0': + '@openai/codex@0.163.0': optionalDependencies: - '@openai/codex-darwin-arm64': '@openai/codex@0.162.0-darwin-arm64' - '@openai/codex-darwin-x64': '@openai/codex@0.162.0-darwin-x64' - '@openai/codex-linux-arm64': '@openai/codex@0.162.0-linux-arm64' - '@openai/codex-linux-x64': '@openai/codex@0.162.0-linux-x64' - '@openai/codex-win32-arm64': '@openai/codex@0.162.0-win32-arm64' - '@openai/codex-win32-x64': '@openai/codex@0.162.0-win32-x64' - - '@openai/codex@0.162.0-darwin-arm64': + '@openai/codex-darwin-arm64': '@openai/codex@0.163.0-darwin-arm64' + '@openai/codex-darwin-x64': '@openai/codex@0.163.0-darwin-x64' + '@openai/codex-linux-arm64': '@openai/codex@0.163.0-linux-arm64' + '@openai/codex-linux-x64': '@openai/codex@0.163.0-linux-x64' + '@openai/codex-win32-arm64': '@openai/codex@0.163.0-win32-arm64' + '@openai/codex-win32-x64': '@openai/codex@0.163.0-win32-x64' + + '@openai/codex@0.163.0-darwin-arm64': optional: true - '@openai/codex@0.162.0-darwin-x64': + '@openai/codex@0.163.0-darwin-x64': optional: true - '@openai/codex@0.162.0-linux-arm64': + '@openai/codex@0.163.0-linux-arm64': optional: true - '@openai/codex@0.162.0-linux-x64': + '@openai/codex@0.163.0-linux-x64': optional: true - '@openai/codex@0.162.0-win32-arm64': + '@openai/codex@0.163.0-win32-arm64': optional: true - '@openai/codex@0.162.0-win32-x64': + '@openai/codex@0.163.0-win32-x64': optional: true '@simple-libs/child-process-utils@2.0.0': @@ -1909,7 +1909,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.9.9: {} + prettier@3.9.10: {} punycode.js@2.3.1: {} From 593bb7cebf9d94e43d9926d0cfe0a6739e3c481f Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Mon, 19 Oct 2026 10:27:34 +0900 Subject: [PATCH 71/73] fix(deps): migrate to zip 9 and bump cargo group (#525) Supersedes Dependabot #523: zip 8 -> 9, serde_json 1.0.154, tokio 1.53.3, toml_edit 0.25.17, sha2 0.11.1. zip 9 returns Result from ZipFile::name(); propagate failures with anyhow context instead of panicking. Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 76 ++++++++++++++++++++++++---------------- Cargo.toml | 2 +- src/reference/fetcher.rs | 9 +++-- 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e995432..dee21f8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,7 +84,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -95,7 +95,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -332,9 +332,12 @@ checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" [[package]] name = "constant_time_eq" -version = "0.4.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" +checksum = "9eb6feb175df65d0a3ccd3e73484e940d0ac664e8034f0519fd49a93db3071d9" +dependencies = [ + "rustversion", +] [[package]] name = "cookie" @@ -594,7 +597,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -642,7 +645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -1283,9 +1286,9 @@ checksum = "e20f57f9918e5bd7bc58c22cdd70a6afc7375d4dd9683af5f2b34bd3d2bba619" [[package]] name = "lzma-rust2" -version = "0.16.5" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca93e534d1142d1d0dcca6d25fe302508a5dfb40b302802904577725ea0b695b" +checksum = "7277c9742229dc25243236d578b6471a798c554512c6f6a04365ec2e87c2a3bb" dependencies = [ "sha2", ] @@ -1412,6 +1415,18 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1441,7 +1456,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1939,7 +1954,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2082,9 +2097,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -2128,9 +2143,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19" dependencies = [ "cfg-if", "cpufeatures", @@ -2186,7 +2201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -2288,7 +2303,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2412,9 +2427,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.53.2" +version = "1.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044" +checksum = "ce3335fa71841cda333a58d7615b03901380ecf09d59b3296d21f8bbac0dde4e" dependencies = [ "bytes", "libc", @@ -2470,9 +2485,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.16+spec-1.1.0" +version = "0.25.17+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88f38f3af8bf71841c67a990f4e2b52143b2d0a1a994c72513ff4c14977fc722" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" dependencies = [ "indexmap", "toml_datetime", @@ -2990,7 +3005,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3369,9 +3384,9 @@ dependencies = [ [[package]] name = "zip" -version = "8.6.0" +version = "9.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +checksum = "6e04976da629d3b04204ba8105b396a193af8ad2583b2c79bfb3ab8af580a11e" dependencies = [ "aes", "bzip2", @@ -3382,8 +3397,9 @@ dependencies = [ "getrandom 0.4.1", "hmac", "indexmap", - "lzma-rust2 0.16.5", + "lzma-rust2 0.22.0", "memchr", + "nix", "pbkdf2", "ppmd-rust", "sha1", @@ -3420,27 +3436,27 @@ dependencies = [ [[package]] name = "zstd" -version = "0.13.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +checksum = "db3ae9bf90af6e40197bef767eeefc46ad6397420fe873830bd85e5fbbfb3c70" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.4" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +checksum = "ded520f16b29e1a9b771c722221b2b0a0398c2316d9bb3c42b458a5414d7434b" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.16+zstd.1.5.7" +version = "2.1.2+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +checksum = "481ada9c543b2323cbb7bbdbb5249177fbf0188ed959ed2c15e4b22421c84ed3" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index a1d01cce..74d31ce3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ serde_yml = "0.0.13" similar = "3" tempfile = "3.27" socket2 = "0.6" -zip = "8" +zip = "9" # bincode 3.0.0 intentionally compile_error!s; retain the existing index format (#342). bincode = "=1.3.3" diff --git a/src/reference/fetcher.rs b/src/reference/fetcher.rs index 449de131..5cf6134e 100644 --- a/src/reference/fetcher.rs +++ b/src/reference/fetcher.rs @@ -284,7 +284,10 @@ pub fn extract_zip_to(archive_bytes: &[u8], dest: &Path) -> Result<()> { let mut file = archive .by_index(i) .with_context(|| format!("failed to read zip entry {i}"))?; - let raw_name = file.name().to_string(); + let raw_name = file + .name() + .with_context(|| format!("failed to read name of zip entry {i}"))? + .into_owned(); let stripped = match strip_prefix(&raw_name, &prefix) { Some(s) if !s.is_empty() => s.to_string(), _ => continue, @@ -317,7 +320,9 @@ fn detect_top_level_prefix(archive: &mut zip::ZipArchive>) -> Resu return Err(anyhow!("zip archive is empty")); } let first = archive.by_index(0).context("zip archive has no entries")?; - let name = first.name(); + let name = first + .name() + .context("failed to read name of first zip entry")?; if let Some(idx) = name.find('/') { Ok(name[..=idx].to_string()) } else { From c15b84fcfc9820739c80f40e43915d43e121ee35 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Mon, 19 Oct 2026 12:27:28 +0900 Subject: [PATCH 72/73] chore(work): record issue 522 release work events Co-Authored-By: Claude Opus 5.5 --- ...d25d9bcae6025bbcd40e04d6543ceb284a0bc51a44876a1b770977b.jsonl | 1 + ...f68ca691272799a90a4ea9bd17ebae147163b8a35388a9f9b57d637.jsonl | 1 + ...b35785f3b585ceb5284f62720976c36da133b2d981dc39c025d09f4.jsonl | 1 + ...3a1c3e31e07a5d7cf63fc3405b0c956e64ae2f81009a29370d69499.jsonl | 1 + ...a2cf0525bc69558d25091debc7dc318add5d26c4167e598616b4ef6.jsonl | 1 + 5 files changed, 5 insertions(+) create mode 100644 .gwt/work/events/05/05e8edbe8d25d9bcae6025bbcd40e04d6543ceb284a0bc51a44876a1b770977b.jsonl create mode 100644 .gwt/work/events/38/3834654f5f68ca691272799a90a4ea9bd17ebae147163b8a35388a9f9b57d637.jsonl create mode 100644 .gwt/work/events/47/475c64b51b35785f3b585ceb5284f62720976c36da133b2d981dc39c025d09f4.jsonl create mode 100644 .gwt/work/events/85/85330751a3a1c3e31e07a5d7cf63fc3405b0c956e64ae2f81009a29370d69499.jsonl create mode 100644 .gwt/work/events/b3/b3e7a05f2a2cf0525bc69558d25091debc7dc318add5d26c4167e598616b4ef6.jsonl diff --git a/.gwt/work/events/05/05e8edbe8d25d9bcae6025bbcd40e04d6543ceb284a0bc51a44876a1b770977b.jsonl b/.gwt/work/events/05/05e8edbe8d25d9bcae6025bbcd40e04d6543ceb284a0bc51a44876a1b770977b.jsonl new file mode 100644 index 00000000..53aa0ab6 --- /dev/null +++ b/.gwt/work/events/05/05e8edbe8d25d9bcae6025bbcd40e04d6543ceb284a0bc51a44876a1b770977b.jsonl @@ -0,0 +1 @@ +{"id":"43a20342-fb94-4066-b0ad-312627a7f2ab","work_item_id":"work-work-issue-522-b9f798d4","kind":"resume","title":"chore(release): LSP 既定化と LSP 書き込み信頼性修正を含む v0.19.0 をリリースする","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #522","next_action":"Check Board for latest updates","agent_session_id":"17d778c4-6063-4b7f-85f1-78dab6102c83","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-522","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-522","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-19T01:15:30.750424Z"} diff --git a/.gwt/work/events/38/3834654f5f68ca691272799a90a4ea9bd17ebae147163b8a35388a9f9b57d637.jsonl b/.gwt/work/events/38/3834654f5f68ca691272799a90a4ea9bd17ebae147163b8a35388a9f9b57d637.jsonl new file mode 100644 index 00000000..1072af18 --- /dev/null +++ b/.gwt/work/events/38/3834654f5f68ca691272799a90a4ea9bd17ebae147163b8a35388a9f9b57d637.jsonl @@ -0,0 +1 @@ +{"id":"04fd7df6-803a-403b-8ffa-91b4ee165336","work_item_id":"work-work-issue-522-b9f798d4","kind":"update","title":null,"intent":"性能ゲート待機(load1 < 8.5 待ち)","summary":null,"progress_summary":"origin/develop (2a79fbfd) へ ff し、前セッションのリリース差分(5 ファイル, v0.19.0)を再適用。release CLI 0.19.0 をビルド済み。","status_category":null,"owner":"Issue #522","next_action":null,"agent_session_id":"17d778c4-6063-4b7f-85f1-78dab6102c83","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-522","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-522","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-19T01:19:03.159869Z"} diff --git a/.gwt/work/events/47/475c64b51b35785f3b585ceb5284f62720976c36da133b2d981dc39c025d09f4.jsonl b/.gwt/work/events/47/475c64b51b35785f3b585ceb5284f62720976c36da133b2d981dc39c025d09f4.jsonl new file mode 100644 index 00000000..68611b74 --- /dev/null +++ b/.gwt/work/events/47/475c64b51b35785f3b585ceb5284f62720976c36da133b2d981dc39c025d09f4.jsonl @@ -0,0 +1 @@ +{"id":"a6337369-8166-4e96-80c5-f65b2cd287ef","work_item_id":"work-work-issue-522-b9f798d4","kind":"start","title":"chore(release): LSP 既定化と LSP 書き込み信頼性修正を含む v0.19.0 をリリースする","intent":"Check Board for latest updates","summary":"Claude Code is running","progress_summary":null,"status_category":"active","owner":"Issue #522","next_action":"Check Board for latest updates","agent_session_id":"c270a89f-b89c-48d0-a8ba-b3d897512283","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-522","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-522","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T10:02:26.974713Z"} diff --git a/.gwt/work/events/85/85330751a3a1c3e31e07a5d7cf63fc3405b0c956e64ae2f81009a29370d69499.jsonl b/.gwt/work/events/85/85330751a3a1c3e31e07a5d7cf63fc3405b0c956e64ae2f81009a29370d69499.jsonl new file mode 100644 index 00000000..58110bc7 --- /dev/null +++ b/.gwt/work/events/85/85330751a3a1c3e31e07a5d7cf63fc3405b0c956e64ae2f81009a29370d69499.jsonl @@ -0,0 +1 @@ +{"id":"2b0fa7d0-3c4d-429a-b8a6-678fe8ee9aa7","work_item_id":"work-work-issue-522-b9f798d4","kind":"update","title":null,"intent":"性能ゲート 3 回目(静かな時間帯を待って自動開始)","summary":null,"progress_summary":"origin/develop 1e369872 (#526 含む) へ ff、v0.19.0 版数 + CHANGELOG(#524/#526 追記, 日付 2026-10-19)。性能ゲート 2 回は frontmost のみ FAIL(計測中 load1 13〜17)、background は 23/23 PASS。v0.18.1 との A/B で回帰なし。Release PR 本文草稿 .cache/issue-522/release-pr-body.md 作成済み。","status_category":null,"owner":"Issue #522","next_action":null,"agent_session_id":"17d778c4-6063-4b7f-85f1-78dab6102c83","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-522","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-522","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-19T02:51:42.564005Z"} diff --git a/.gwt/work/events/b3/b3e7a05f2a2cf0525bc69558d25091debc7dc318add5d26c4167e598616b4ef6.jsonl b/.gwt/work/events/b3/b3e7a05f2a2cf0525bc69558d25091debc7dc318add5d26c4167e598616b4ef6.jsonl new file mode 100644 index 00000000..503dc792 --- /dev/null +++ b/.gwt/work/events/b3/b3e7a05f2a2cf0525bc69558d25091debc7dc318add5d26c4167e598616b4ef6.jsonl @@ -0,0 +1 @@ +{"id":"33e6ea8d-4da6-4c4d-91dd-c2812be558b5","work_item_id":"work-work-issue-522-b9f798d4","kind":"update","title":null,"intent":"性能ゲート: load1 < 8.5 待ち","summary":null,"progress_summary":"v0.19.0 のバージョン更新 5 ファイルと CHANGELOG(Breaking changes 節含む)を作成、release バイナリをビルド済み。性能ゲート実行待ち(未コミット)","status_category":null,"owner":"Issue #522","next_action":null,"agent_session_id":"c270a89f-b89c-48d0-a8ba-b3d897512283","agent_id":"claude","display_name":"Claude Code","board_entry_id":null,"execution_container":{"branch":"work/issue-522","worktree_path":"/Users/akiojin/Workbench/unity-cli/work/issue-522","pr_number":null,"pr_url":null,"pr_state":null},"related_work_item_id":null,"updated_at":"2026-10-14T10:27:41.248750Z"} From 907d612d1138f92ae6daead77cdbe0d63b05def1 Mon Sep 17 00:00:00 2001 From: Akio Jinsenji Date: Mon, 19 Oct 2026 12:27:33 +0900 Subject: [PATCH 73/73] chore(release): v0.19.0 Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 108 ++++++++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- .../Packages/unity-cli-bridge/package.json | 2 +- package.json | 2 +- 5 files changed, 112 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77d77268..ce5d6e82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,113 @@ ## [Unreleased] +## [0.19.0] - 2026-10-19 + +### Breaking changes and migration + +- `create_class` now writes through the C# LSP write path (the same path as + `create_csharp_file`) instead of writing the file directly + ([#493](https://github.com/akiojin/unity-cli/pull/493)). With + `UNITY_CLI_LSP_MODE=off` it now fails with a "requires LSP" error and writes + nothing; in v0.18.1 it wrote the file silently. Arguments are unchanged, and + the output keeps `success` / `path` / `content` and adds the LSP result fields + (`applied`, `changedFiles`, `diagnostics`, `backend`). + Migration: remove `UNITY_CLI_LSP_MODE=off` (or set it to `auto` / + `required`) and install the LSP with `unity-cli lsp install`. Automation that + must run without the LSP should write the `.cs` file itself, then run + `unity-cli raw refresh_assets` and check `get_compilation_state`. + +### Features + +- *(lsp)* Make LSP the default backend for C# symbol search + (`get_symbols` / `find_symbol` / `find_refs` / `build_index`). An unset + `UNITY_CLI_LSP_MODE` now means `auto`: the LSP is used when available, and the + local index is used otherwise, with `backend: "index"` and a `fallbackReason` + (`lsp_not_installed`, `lsp_unavailable`, `lsp_timeout`, `lsp_disabled`). + `UNITY_CLI_LSP_AUTO_TIMEOUT_MS` (default 10000) sets the fallback timeout. A + missing LSP is installed in the background + ([#495](https://github.com/akiojin/unity-cli/pull/495)). +- *(scripts)* Add `scripts/install-from-source.sh` / `.ps1` to install a source + build as the managed binary ([#481](https://github.com/akiojin/unity-cli/pull/481)). +- *(skills)* Route C# script creation and compile-error fixes through the LSP + write tools, with a documented fallback when the LSP write path fails + ([#493](https://github.com/akiojin/unity-cli/pull/493), + [#496](https://github.com/akiojin/unity-cli/pull/496)). + +### 🐛 Bug Fixes + +- *(lsp)* Keep the original BOM (UTF-8, UTF-16 LE/BE, UTF-32 LE/BE) and newline + convention (LF, CRLF, lone CR) when the C# LSP write tools save a file + ([#507](https://github.com/akiojin/unity-cli/pull/507), + [#513](https://github.com/akiojin/unity-cli/pull/513)). +- *(lsp)* Normalize a lone CR in edits to the file's newline style in LF and + CRLF files, while keeping CRs that are part of string values, including in + inactive and malformed preprocessor branches + ([#517](https://github.com/akiojin/unity-cli/pull/517), + [#518](https://github.com/akiojin/unity-cli/pull/518), + [#519](https://github.com/akiojin/unity-cli/pull/519), + [#521](https://github.com/akiojin/unity-cli/pull/521)). +- *(lsp)* Keep trailing comments when `replace_symbol_body` replaces a method + body ([#503](https://github.com/akiojin/unity-cli/pull/503)). +- *(lsp)* Add `using UnityEngine;` to ScriptableObject classes from + `create_class` ([#502](https://github.com/akiojin/unity-cli/pull/502)). +- *(lsp)* Resolve canonical file URIs across Windows and Unix, so Assets symbol + search works with `file:///C:/...` roots + ([#512](https://github.com/akiojin/unity-cli/pull/512)). +- *(lsp)* Wait for a live auto-started lspd (up to + `UNITY_CLI_LSPD_START_TIMEOUT_MS`, default 60000) instead of failing after + 5 seconds, log lspd stderr to `lspd.log`, and bound Windows cold-start TCP + connection waits ([#505](https://github.com/akiojin/unity-cli/pull/505), + [#506](https://github.com/akiojin/unity-cli/pull/506)). +- *(update)* Keep the installed CLI on `unityd start` / `lspd` when + `UNITY_CLI_NO_AUTO_UPDATE=1` ([#479](https://github.com/akiojin/unity-cli/pull/479)). +- *(install)* Retry transient download errors in `install.sh` / `install.ps1` + ([#515](https://github.com/akiojin/unity-cli/pull/515)). +- *(windows)* Harden Editor launches, `\\?\` path handling, MCP profile + isolation, reference fetch and bake validation on Windows + ([#471](https://github.com/akiojin/unity-cli/pull/471)). + +### 🧪 Testing + +- *(lsp)* Measure C# write reliability on macOS, Linux and Windows + ([#497](https://github.com/akiojin/unity-cli/pull/497), + [#508](https://github.com/akiojin/unity-cli/pull/508), + [#510](https://github.com/akiojin/unity-cli/pull/510)). +- *(ci)* Check the published install on Windows, Wayland `grim` screenshots and + the global skills install ([#466](https://github.com/akiojin/unity-cli/pull/466)). + +### 📚 Documentation + +- *(readme)* Split install instructions into an LLM-agent prompt and a manual + path; the prompt also updates the CLI and the Unity bridge + ([#485](https://github.com/akiojin/unity-cli/pull/485), + [#489](https://github.com/akiojin/unity-cli/pull/489)). +- *(skills)* Document per-tool GameObject parameter names + ([#478](https://github.com/akiojin/unity-cli/pull/478)). + +### ⚙️ Miscellaneous Tasks + +- *(ci)* Auto-merge reviewed external PRs pinned to the labeled head SHA + ([#492](https://github.com/akiojin/unity-cli/pull/492)); make the Codecov + upload non-fatal ([#473](https://github.com/akiojin/unity-cli/pull/473)). +- *(deps)* Update cargo, npm and GitHub Actions dependencies, keeping bincode 1 + so existing embedding indexes still load, and move to zip 9 for reference + archive extraction + ([#467](https://github.com/akiojin/unity-cli/pull/467), + [#469](https://github.com/akiojin/unity-cli/pull/469), + [#476](https://github.com/akiojin/unity-cli/pull/476), + [#482](https://github.com/akiojin/unity-cli/pull/482), + [#483](https://github.com/akiojin/unity-cli/pull/483), + [#524](https://github.com/akiojin/unity-cli/pull/524), + [#526](https://github.com/akiojin/unity-cli/pull/526), for + [#525](https://github.com/akiojin/unity-cli/issues/525)). + +### Acknowledgements + +- Thanks to @arghhhhh for + [#478](https://github.com/akiojin/unity-cli/pull/478), + [#479](https://github.com/akiojin/unity-cli/pull/479) and + [#481](https://github.com/akiojin/unity-cli/pull/481). + ## [0.18.1] - 2026-10-03 ### 📦 Distribution diff --git a/Cargo.lock b/Cargo.lock index dee21f8b..f0d523b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2682,7 +2682,7 @@ checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" [[package]] name = "unity-cli" -version = "0.18.1" +version = "0.19.0" dependencies = [ "anyhow", "base64 0.23.1", diff --git a/Cargo.toml b/Cargo.toml index 74d31ce3..cad5cc7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "unity-cli" -version = "0.18.1" +version = "0.19.0" edition = "2021" description = "Rust CLI for Unity Editor automation over the Unity TCP protocol" readme = "README.md" diff --git a/UnityCliBridge/Packages/unity-cli-bridge/package.json b/UnityCliBridge/Packages/unity-cli-bridge/package.json index 8815dbec..12cb6b40 100644 --- a/UnityCliBridge/Packages/unity-cli-bridge/package.json +++ b/UnityCliBridge/Packages/unity-cli-bridge/package.json @@ -1,7 +1,7 @@ { "name": "com.akiojin.unity-cli-bridge", "displayName": "Unity CLI Bridge", - "version": "0.18.1", + "version": "0.19.0", "unity": "2022.3", "description": "Unity Editor bridge package for unity-cli automation (screenshots, video capture, scene analysis, input automation).", "keywords": [ diff --git a/package.json b/package.json index 2bfea999..43d14cf5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "unity-cli-workspace", - "version": "0.18.1", + "version": "0.19.0", "private": true, "packageManager": "pnpm@10.33.0", "description": "Development environment for unity-cli",