Skip to content

feat: Expose raw captured pause point variables while Unity is paused#1717

Merged
hatayama merged 2 commits into
feat/pause-point-observabilityfrom
feat/pause-point-raw-capture-holder
Jul 12, 2026
Merged

feat: Expose raw captured pause point variables while Unity is paused#1717
hatayama merged 2 commits into
feat/pause-point-observabilityfrom
feat/pause-point-raw-capture-holder

Conversation

@hatayama

@hatayama hatayama commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Refs: 2026-07-12_uloop検証フィードバック改善 実装計画.md#PR 2-3 (B-2 案2)

Summary

  • Demangled capture frames are shared between the string formatter and a latest-hit-only raw holder.
  • UloopPausePoint.TryGetCapturedValue returns (bool Found, object Value); GetCapturedNames() and GetCapturedPausePointId() expose snapshot metadata.
  • Resume clearing uses pauseStateChanged + delayCall re-check so PlayMode Step does not drop refs mid-inspection.

User Impact

  • While Unity is paused on a hit, execute-dynamic-code can read live collection/object references (not just string previews).
  • After resume/clear/new hit/PlayMode exit, raw refs are dropped (Found=false).

Design (Fable 5 conditional LGTM)

  • Latest hit only (mirrors _latestHitSnapshot)
  • Tuple TryGetCapturedValue avoids null ambiguity
  • Intermediate UloopPausePointCapturedVariableFrame consumed by Collector + Formatter + Holder
  • No CLI/DTO field additions

Protocol

  • No protocol version bump

Verification

  • uloop compile 0 errors / 0 warnings
  • PausePointTests + SourcePausePointVariableFormatterTests 72 passed

Real-device evidence

Pause中に raw 参照を読める

enable-pause-point --file Assets/Tests/Editor/CollectionPreviewPausePointFixture.cs --line 11
execute-dynamic-code → new CollectionPreviewPausePointFixture().BuildScores()
execute-dynamic-code:
  TryGetCapturedValue("scores") → Found=true, List contents "10,20,30"
  GetCapturedPausePointId() → Assets/Tests/Editor/CollectionPreviewPausePointFixture.cs:11

resume 後は Found=false

control-play-mode --action Play  (resume)
execute-dynamic-code → TryGetCapturedValue("scores").Found → false ("cleared-after-resume")

Step 干渉検証 (PlayMode paused)

control-play-mode Pause → hit fixture → TryGetCapturedValue → "held-before-step"
control-play-mode Step → TryGetCapturedValue → "held-after-step" (holder retained; isPaused stayed true)

Made with Cursor

Review in cubic

Share demangled capture frames between the formatter and a latest-hit-only
raw holder, and add TryGetCapturedValue for execute-dynamic-code inspection.
Resume clearing uses pauseStateChanged with delayCall so Step keeps refs.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds editor-only raw captured-variable frames, collects and formats captured values separately, stores the latest frame through pause-point hits, exposes retrieval APIs, clears data with lifecycle changes, and adds coverage for latest-hit behavior.

Changes

Raw captured-variable flow

Layer / File(s) Summary
Captured-variable frame and collection
Packages/src/Runtime/PausePoints/UloopPausePointCapturedVariableEntry.cs, Packages/src/Runtime/PausePoints/UloopPausePointCapturedVariableFrame.cs, Packages/src/Editor/FirstPartyTools/PausePoint/*
Captured variables are represented as frame entries and collected from pairs, instance fields, and state-machine fields with deduplication and truncation.
Capture and formatting pipeline
Packages/src/Editor/FirstPartyTools/PausePoint/SourcePausePointCapture.cs, Packages/src/Editor/FirstPartyTools/PausePoint/SourcePausePointVariableFormatter.cs
Capture builds a frame, formats it, and records it through HitWithCapturedFrame on both main-thread and deferred paths.
Latest raw capture access and cleanup
Packages/src/Runtime/PausePoints/UloopPausePoint.cs, Packages/src/Runtime/PausePoints/UloopPausePointRawCaptureHolder.cs, Packages/src/Runtime/PausePoints/UloopPausePointRawCaptureLifecycle.cs
Editor-only APIs expose captured values, names, and pause-point ids backed by an atomically replaced latest snapshot; editor and play-mode transitions clear retained data.
Registry lifecycle integration and tests
Packages/src/Runtime/PausePoints/UloopPausePointRegistry.cs, Assets/Tests/Editor/PausePointTests.cs
Registry hit and clear operations update raw capture storage, with tests covering lookup, clearing, replacement, and unrelated pause-point cleanup.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SourcePausePointCapture
  participant SourcePausePointVariableCollector
  participant SourcePausePointVariableFormatter
  participant UloopPausePointRegistry
  participant UloopPausePointRawCaptureHolder
  SourcePausePointCapture->>SourcePausePointVariableCollector: Collect frame
  SourcePausePointCapture->>SourcePausePointVariableFormatter: FormatFrame(frame)
  SourcePausePointCapture->>UloopPausePointRegistry: HitWithCapturedFrame(...)
  UloopPausePointRegistry->>UloopPausePointRawCaptureHolder: Store latest frame
  UloopPausePointRawCaptureHolder-->>UloopPausePointRegistry: Expose latest raw values
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: exposing raw captured pause-point variables while Unity is paused.
Description check ✅ Passed The description is directly related to the changeset and accurately covers the new raw capture APIs, lifecycle, and verification.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pause-point-raw-capture-holder

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Use FormatFrame and HitWithCapturedFrame for the new paths, and only
clear raw captures when Clear targets the latest hit snapshot id.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Packages/src/Runtime/PausePoints/UloopPausePointRegistry.cs`:
- Around line 202-206: Update the capturedFrame handling in HitCore so
null-frame hits explicitly clear UloopPausePointRawCaptureHolder instead of
retaining the previous snapshot; preserve storing capturedFrame with the current
id when it is non-null, keeping GetCapturedPausePointId() and live inspection
aligned with _latestHitSnapshot.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c876925b-420f-45be-b0e9-6106b27fc757

📥 Commits

Reviewing files that changed from the base of the PR and between 5cdbae5 and aa88b1b.

⛔ Files ignored due to path filters (5)
  • Packages/src/Editor/FirstPartyTools/PausePoint/SourcePausePointVariableCollector.cs.meta is excluded by none and included by none
  • Packages/src/Runtime/PausePoints/UloopPausePointCapturedVariableEntry.cs.meta is excluded by none and included by none
  • Packages/src/Runtime/PausePoints/UloopPausePointCapturedVariableFrame.cs.meta is excluded by none and included by none
  • Packages/src/Runtime/PausePoints/UloopPausePointRawCaptureHolder.cs.meta is excluded by none and included by none
  • Packages/src/Runtime/PausePoints/UloopPausePointRawCaptureLifecycle.cs.meta is excluded by none and included by none
📒 Files selected for processing (10)
  • Assets/Tests/Editor/PausePointTests.cs
  • Packages/src/Editor/FirstPartyTools/PausePoint/SourcePausePointCapture.cs
  • Packages/src/Editor/FirstPartyTools/PausePoint/SourcePausePointVariableCollector.cs
  • Packages/src/Editor/FirstPartyTools/PausePoint/SourcePausePointVariableFormatter.cs
  • Packages/src/Runtime/PausePoints/UloopPausePoint.cs
  • Packages/src/Runtime/PausePoints/UloopPausePointCapturedVariableEntry.cs
  • Packages/src/Runtime/PausePoints/UloopPausePointCapturedVariableFrame.cs
  • Packages/src/Runtime/PausePoints/UloopPausePointRawCaptureHolder.cs
  • Packages/src/Runtime/PausePoints/UloopPausePointRawCaptureLifecycle.cs
  • Packages/src/Runtime/PausePoints/UloopPausePointRegistry.cs

Comment on lines +202 to +206
if (capturedFrame != null)
{
UloopPausePointRawCaptureHolder.Store(capturedFrame, id);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant registry and raw capture holder usage
git ls-files | rg 'Packages/src/Runtime/PausePoints/UloopPausePointRegistry\.cs|UloopPausePointRawCaptureHolder|execute-dynamic-code|PausePoint'

echo '--- UloopPausePointRegistry.cs (outline) ---'
ast-grep outline Packages/src/Runtime/PausePoints/UloopPausePointRegistry.cs --view expanded || true

echo '--- Raw capture holder references ---'
rg -n "UloopPausePointRawCaptureHolder|GetCapturedPausePointId|_latestHitSnapshot|capturedFrame != null|Clear\(" Packages/src -S

echo '--- Related pause-point code slices ---'
sed -n '150,260p' Packages/src/Runtime/PausePoints/UloopPausePointRegistry.cs
printf '\n---\n'
sed -n '1,220p' "$(git ls-files | rg 'UloopPausePointRawCaptureHolder\.cs$')"

Repository: hatayama/unity-cli-loop

Length of output: 46622


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- Hit API surface ---'
sed -n '110,190p' Packages/src/Runtime/PausePoints/UloopPausePointRegistry.cs
printf '\n--- Raw capture lifecycle ---\n'
sed -n '1,160p' Packages/src/Runtime/PausePoints/UloopPausePointRawCaptureLifecycle.cs
printf '\n--- UloopPausePoint.cs ---\n'
sed -n '1,120p' Packages/src/Runtime/PausePoints/UloopPausePoint.cs
printf '\n--- Execute-dynamic-code uses of captured pause-point id / names ---\n'
rg -n "GetCapturedPausePointId|TryGetCapturedValue|GetCapturedNames|RawCapture" Packages/src Assets -S
printf '\n--- Tests mentioning raw capture id ---\n'
rg -n "GetCapturedPausePointId|TryGetCapturedValue|GetCapturedNames|RawCapture" Assets/Tests Packages/src/Runtime/PausePoints -S

Repository: hatayama/unity-cli-loop

Length of output: 18637


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '470,590p' Assets/Tests/Editor/PausePointTests.cs

Repository: hatayama/unity-cli-loop

Length of output: 6460


Clear raw capture on null-frame hits

HitCore only stores raw capture when capturedFrame is present, so a marker-only hit or HitWithCapturedVariables can leave the previous live-object snapshot attached to the new latest hit. Clear the raw holder on null-frame hits so GetCapturedPausePointId() and live inspection stay aligned with _latestHitSnapshot.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Packages/src/Runtime/PausePoints/UloopPausePointRegistry.cs` around lines 202
- 206, Update the capturedFrame handling in HitCore so null-frame hits
explicitly clear UloopPausePointRawCaptureHolder instead of retaining the
previous snapshot; preserve storing capturedFrame with the current id when it is
non-null, keeping GetCapturedPausePointId() and live inspection aligned with
_latestHitSnapshot.

@hatayama
hatayama merged commit f278b69 into feat/pause-point-observability Jul 12, 2026
2 checks passed
@hatayama
hatayama deleted the feat/pause-point-raw-capture-holder branch July 12, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant