# Changelog

All notable changes to MooseRunner are documented in this file.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [2.2.3] - 2026-06-12

### Added
- **Autonomous Unity-editor lifecycle from the CLI (`unity_*`, Windows).** An AI agent
  can now stop, start, and recover a blocked Unity by itself — no human at the keyboard.
  - `unity_stop [<pid>] [--no-clones] [--timeout 10]` — stops THIS project's editor (and
    its ParrelSync clones by default), scoped by `-projectPath` so it never touches an
    unrelated editor. With a pid, stops just that process. After killing, it clears each
    editor's `Temp/UnityLockfile` and `Temp/__Backupscenes` so the next start doesn't hang
    on Unity's blocking "Recover scene backups?" modal.
  - `unity_start [--timeout 120]` — launches the editor for this project and waits until
    `ping`→`PONG` (the worker connected). Safe Mode is surfaced as `COMPILE_ERROR:` lines
    + exit 1; benign recovery/backup dialogs are auto-dismissed.
  - `unity_check_modal [--poll N] [--timeout 60]` — reports any blocking dialog (title +
    buttons) on this project's editor, and `unity_modal_click "<button>"` clicks one
    (e.g. `"Don't Load"`, `"OK"`, `"Close"`).
  - **Long-running commands now auto-detect a stall.** While `test` / `force-recompile` /
    `edit-asset` / the recording commands wait for the worker, if nothing arrives for 60s
    they scan for a blocking modal; on a hit they return early with the dialog's title,
    buttons, and the exact `unity_modal_click` to dismiss it — instead of silently waiting
    out the full timeout. A healthy long test is unaffected.
  - Windows-only (PowerShell + Win32 window APIs); on other platforms the commands return
    a clear "supported on Windows only" message and the auto-stall check is a no-op.

## [2.2.2] - 2026-06-12

### Fixed
- **Agent debugger hardening from a 30-angle exploratory pass.** All fixes are in
  the optional debugger component; nothing else is affected.
  - `debug_*` `--timeout 0`, negatives, non-numbers, and `2147483647` were
    silently swallowed (fell back to the default; `INT_MAX` overflowed the CLI's
    reply-deadline math into an instant spurious timeout). They now fail fast with
    "must be an integer between 1 and 86400 seconds". `--frame` and `--thread-id`
    likewise reject non-numeric / negative values instead of defaulting.
  - `debug_break_on_exceptions --on --off` (contradictory) is now a usage error.
  - A breakpoint on a line past the end of a resolvable file reported
    "unverified — binds on first load" (a promise that could never be kept). It
    now errors with the file's actual line count. A second breakpoint that
    line-adjusts onto an executable line already occupied is rejected rather than
    creating an undeletable duplicate.
  - **Domain reload while attached now ends the session honestly.** A recompile
    silently unbinds every SDB breakpoint; the session previously stayed "attached"
    so the agent waited a full timeout on a breakpoint that could never hit. The
    session now ends and the next command explains why ("Debug session ended: the
    editor domain-reloaded …"); re-attach is one command. Same for editor/worker
    disconnect. The teardown clean-detaches (never wedges Unity's agent).
  - Attaching while another debugger (Rider / VS Code / HotReload) holds Unity's
    single-client agent slot returned a misleading "debug host" error after a
    60-second hang. It now fails in ~8s with the real cause and the "detach the
    other debugger; an editor restart may be needed" guidance.
  - `debug_eval` on a null mid-path (`a.b.c` where `b` is null) said "Cannot
    access c on a PrimitiveValue"; it now says the value before it is null.
  - Non-ASCII in CLI output (file paths like `Sp ace Å`, eval'd string values)
    was mangled to `?`/`�` by the legacy console codepage — output is now UTF-8.
  - `set-timescale` and `abort` printed success and exited 0 even when the daemon
    rejected the forward (suspended at a breakpoint, or no worker) — an agent
    "resuming" a paused test got a false confirmation. They now surface the
    daemon's rejection and exit non-zero.
  - `debug_breakpoint_show` while not attached now reports the error instead of
    printing an empty list.

## [2.2.1] - 2026-06-12

### Fixed
- The release pipeline now actually ships the optional `mooserunnerDebugHost`
  in the package's `CLI~/` folder. v2.2.0 was published without it (the CI
  publish step predated the debugger and only built the CLI + daemon; the
  packaging script treats a missing host as a warning by design), so all
  `debug_*` commands reported "component not installed" on binary installs.
  v2.2.0 is otherwise identical — skip it and install 2.2.1.

## [2.2.0] - 2026-06-12

### Added
- **Agent debugger (`debug_*` CLI commands)** — AI agents can now debug the live
  Unity editor without human intervention: set breakpoints, step, evaluate
  state, and read call stacks, entirely from the CLI.
  - `debug_instance_list` / `debug_instance_attach [master|cloneN]` /
    `debug_instance_detach` / `debug_instance_poll` /
    `debug_instance_wait_for_breakpoint [--timeout]` — session lifecycle against
    the editor's built-in Mono debugger (exclusive: detach Rider/VS Code first).
  - `debug_breakpoint_add|remove <file>:<line>` (bare name, `Assets/`-relative,
    or absolute; honest verified/unverified with lazy binding on type load) and
    `debug_breakpoint_show`.
  - `debug_step_into|over|out` and `debug_continue` — bounded blocking; stops
    print `[STOP] reason file:line method` plus a numbered `[SOURCE]` window
    only when the stopped method changes.
  - `debug_eval "<expr>" [--frame N]` — member paths + parameterless calls
    (locals, `this`, private field/property chains, fully-qualified statics,
    `x.ToString()`); invokes run real editor code under a watchdog timeout.
  - `debug_threads`, `debug_stack [--thread-id N]`, and
    `debug_break_on_exceptions --on|--off` (first-chance; editor-internal
    `ExitGUIException` auto-skipped).
  - Ships as an OPTIONAL component (`mooserunnerDebugHost`): built/installed
    best-effort; if absent, `debug_*` reports it clearly and nothing else is
    affected. Fully local — no API key, no network beyond loopback.
  - While an instance is suspended at a breakpoint, all worker-bound commands
    are rejected with an actionable error instead of hanging; other terminals
    see `[STATUS] DEBUG_SUSPENDED file:line` / `DEBUG_RESUMED`.
  - The worker now reports its process id on registration (debug-port
    derivation); a `GetDebugMode` round-trip guards attaching in Release
    code-optimization mode.
- Testing guidelines: new "Live debugger" doctrine section + CLI quick-reference
  block (re-run `mooserunnerCli get-testing-guidelines-md` after upgrading).

### Changed
- **BREAKING: SessionRecorder CLI commands renamed into the `recording_` group**
  (no aliases): `extract-frame` → `recording_extract_frame`,
  `extract-and-analyze` → `recording_extract_and_analyze`,
  `set-ffmpeg-path` → `recording_set_ffmpeg_path`,
  `set-gemini-key` → `recording_set_gemini_key`. Update any scripts/docs using
  the old names; they now exit 3 with "Unknown command".

### Fixed
- `recording_extract_frame` / `recording_extract_and_analyze` (and the underlying
  `ExtractFrame`/`AnalyzeVideoSegmentAsync`) no longer report success when the
  requested time is past the end of the recording: ffmpeg exits 0 without
  writing any output in that case, and the CLI printed `[FRAME] …` for a file
  that didn't exist. Both paths now verify the output file exists and is
  non-empty, and throw a clear "beyond the end of the recording" error with
  duration-probing guidance.

### Changed
- **BREAKING (binary package): all public contract types now live in the single
  source-shipped `MooseRunner` assembly.** The Multiplaytest interfaces/DTOs
  (`IMultiplaytest`, `IMultiplaytestAssert`, `MultiplaytestRole`,
  `TransformComparisonSettings`, clone exceptions, …), the SessionRecorder
  public surface (`SessionRecorderFacade`, `ISessionRecorder`,
  `SessionRecordingConfig`, `SessionInfo`, `ObjectState`,
  `VideoAnalysisResult`), and `RecordableObject` moved out of
  `MooseRunner.Multiplaytest.Types.dll`, `MooseRunner.SessionRecorder.Public.dll`,
  and `MooseRunner.SessionRecorder.Runtime.dll` (all three no longer ship) into
  `Runtime/Public/`. **One rule now: `references: ["MooseRunner"]`** — works
  under any `overrideReferences` setting. Migration:
  - Asmdefs referencing the three removed names (or listing the DLLs in
    `precompiledReferences`): replace with `references: ["MooseRunner"]`.
  - `Type.GetType`/reflection strings using those assembly names: the assembly
    qualifier is now `MooseRunner`.
  - Scene/prefab-placed `RecordableObject` components from previous binary
    installs become missing-scripts on upgrade (the script moved from a DLL to
    source) — re-add the component where used.
  - Delete `Assets/Samples/MooseRunner/<old-version>/` and re-import the Demos
    sample — stale imported samples reference the removed assembly names.
- **SessionRecorder now requires an activated MooseRunner license**
  (`SessionRecorderFacade.Instance` validates on first use).

### Fixed
- **Integration DLLs (HotReload, SessionRecorder) now actually load in binary
  installs.** Unity evaluates plugin `defineConstraints` only against
  PlayerSettings Scripting Define Symbols — asmdef `versionDefines` never reach
  them — so both gated integration DLLs were silently dead for all binary
  customers since v2.1.12 (SessionRecorder threw "requires the Unity Recorder
  package" even with Recorder installed). A new `IntegrationDefineSync` editor
  bootstrap keeps `UNITY_RECORDER_PRESENT` / `HOT_RELOAD_PRESENT` in
  PlayerSettings in sync with host-package presence. Note: the first editor
  load after installing/uninstalling `com.unity.recorder` or HotReload performs
  ONE extra script recompile (the define being applied/removed), and the sync
  writes to `ProjectSettings/ProjectSettings.asset` (one-time VCS diff).
  `com.unity.recorder` is NOT auto-installed — install it from the Package
  Manager to use SessionRecorder.
- Package import no longer logs "has no meta file, but it's in an immutable
  folder" errors: the build now generates `.meta` files for every shipped file
  and folder (root docs, `package.json`, and all plain directories were
  previously meta-less), with stable per-path GUIDs and importer formats
  matching Unity's own packages. A build-time assertion prevents regressions.

### Changed
- **BREAKING (binary package):** the public facade and contract types
  (`MooseRunnerFacade`, `MethodTestStatus`, `TestStatusValues`, `TestMethodInfo`,
  `TestSelection`) now ship as **source** under `Runtime/Public/` with an asmdef
  named `MooseRunner`, instead of as the precompiled `Runtime/MooseRunner.dll`.
  The assembly name `MooseRunner` is now identical in source and binary mode, so
  asmdefs that reference it by name work against both. Migration for existing
  binary-package consumers:
  - Asmdefs that reached facade types via `references: ["MooseRunner.Runtime"]`:
    add `"MooseRunner"` to `references`. (`MooseRunner.Runtime` still exposes the
    remaining precompiled runtime DLLs.)
  - Asmdefs with `overrideReferences: true` and
    `precompiledReferences: ["MooseRunner.dll"]`: that DLL no longer exists —
    replace with `references: ["MooseRunner"]`.
  - Asmdefs with no MooseRunner reference that picked the facade up via plugin
    auto-referencing: add `references: ["MooseRunner"]`. (Scripts outside any
    asmdef, e.g. Assembly-CSharp, keep working unchanged.)

### Added
- New package dependency `com.unity.test-framework` (the source-shipped
  `TestMethodInfo.cs` references `NUnit.Framework` attributes at compile time;
  the package is free, Unity-official, and present in default projects).
- `MooseRunnerFacade.Log(string)` and `MooseRunnerFacade.ResetTestLog()` —
  customer-facing test logging (the buffer `mooserunnerCli test-log` reads).
  Previously the guidelines pointed at `MooseRunner.Internal.LogDaemon`, which
  customer test asmdefs cannot reach in the binary distribution. The facade
  methods are static, work from master and clones, and silently no-op when the
  worker isn't connected.
- Testing guidelines (`mooserunnerCli get-testing-guidelines-md`) now mandate:
  check the console for errors after every run (green is not enough); repeated
  runs of the same test must be idempotent (no GameObject buildup across runs);
  and simulated input must enter through the game's input facade/control API —
  behaving exactly as if the user acted — never synthesized into the Unity
  Input System.
- Binary distribution pipeline producing a UPM package with pre-built DLLs
  (`Build~/` build harness, `Build~/tools/build.ps1`).
- Wrapper asmdefs `MooseRunner.Editor` and `MooseRunner.Runtime` exposing the
  shipped DLLs to consumer asmdefs by name reference.
- `CliPackageInstaller` `[InitializeOnLoad]` class auto-copies the CLI EXEs
  from the package's `CLI~/` folder into `<projectRoot>/MooseRunner/` on first
  Editor load.
- Reference samples shipped under `Samples~/Demos` (importable from the
  Package Manager UI).

## [2.1.3] - 2026-05

Initial versioned baseline for the commercial release pipeline.
