Repository navigation
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 15 files
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
|
I reviewed 6764cfb and found two problems to fix before merge. CI is green: 11 checks, none failing. There are no conflicts. On a remote daemon, a burst delivers one usable frame and N-1 paths the client cannot read. The remote input policy strips the screenshot positional (remote-host-input-policy.ts:160), so The burst also changes live capture dispatch, but the PR body reports only unit tests, typecheck and lint. Please run Could the design be smaller? Keeping the flag pair is a smaller surface than a new record mode. But if every frame went through the existing response-artifact list ( Not blocking, and fine to take or leave: admission assumes 500 ms per frame and allows up to 60 s, but nothing in the loop checks elapsed time (contracts/screenshot.ts:116), so a backend at about 1 s per frame with The open inline threads still apply: the abort check after the inter-frame sleep (I did not trace whether a backend checks the signal itself), config count test, burst temp root cleanup, aggregated notes test, distinct path test, abort during wait test, plus the two lower-priority ones on frame filtering and Before merge, route every burst frame through the response-artifact pipeline (or refuse |
|
This now conflicts with main at 6764cfb. Please rebase onto main. The two problems and the live run from the earlier review still apply. |
|
Tracked in #4318, group C (new public surface). We're reviewing the six feature PRs together for coherence and for performance impact on paths that don't use them, and we'll post a direction there. Please hold changes here until then. |
|
Thanks @strzhao. We reviewed this with the rest of group C in #4318. Bounded frame sampling is useful for remote devices, but every frame has to be a managed, downloadable artifact.
What we need:
Could you open an issue with this contract and rebase onto main? We'll pick up the PR once the artifact mapping lands. |
…n one request A burst repeats the single capture path N times inside one admitted plan, so evidence for an animation no longer needs repeated single-shot calls. The flags reuse the shared count/intervalMs keys (press/swipe series own the same tokens), so the parser, dispatch pass-through, session recorder, and script round-trip carry them without new flag vocabulary. - contracts: burst limits (count 2-200, interval 100-10000, scheduled wait capped at 30s inside the standard request budget), one shared admission that also refuses --crop-on/--overlay-refs beside --count, frame destination helper (<base>-0001.<ext> sequence), and per-frame result records (path + capture wall clock) - command surface: count/intervalMs input fields, burst admission beside scale validation, help prose for the burst - daemon: sequential frame loop over the bound runtime, default interval 100ms when --interval-ms is absent, shared temp root for a burst without an explicit path, cancellation between frames through the request signal Co-Authored-By: Claude Code <[email protected]>
…ound the burst run Review follow-up on e406a40: - client: normalizeScreenshotCaptureResult and pickScreenshotResultData keep the burst frames, so the SDK default path and the CLI default --json output report every frame path and capture time as the help promises; a frame without a path and a wall clock is dropped and the array stays within the burst ceiling - burst admission models the whole run, not just the waits: count 2-100, and count * (intervalMs + 500 ms capture allowance per frame) within 60 s, so an admitted burst cannot outrun the screenshot request envelope and reset the daemon - screenshot reads count/intervalMs only when the invocation names them (explicit-only in the CLI parser and in the MCP config defaults): a repository count tuned for press and swipe series no longer arms a burst nor refuses --crop-on beside it - burst warnings dedupe across frames and stay within one note per frame - the scripted --pixel-density error text keeps its released wording Co-Authored-By: Claude Code <[email protected]>
…ol-input result Co-Authored-By: Claude Code <[email protected]>
6764cfb to
2ecce95
Compare
Co-Authored-By: Claude Code <[email protected]>
|
Rebased onto main (through 0.21.37). Three semantic merges: the screenshot help now carries the burst text grafted onto the newer prose (screen-sharing window detail and the iOS status-bar wait stay); the CLI-options tests keep #4298's device-selector block beside the burst explicit-only block; and the MCP tool-input merge keeps the structured |
|
The rebase to e5ea581 does not change the two problems from the earlier review (#4291 (comment)), so both still need work. CI is green on this head (14 checks, 0 not passing), and there are no conflicts. On a remote daemon, the input policy strips screenshot positionals (https://github.com/callstack/agent-device/blob/e5ea581/packages/daemon/src/server/remote-host-input-policy.ts#L172), so The burst adds a device-facing capture loop (https://github.com/callstack/agent-device/blob/e5ea581/packages/daemon/src/execution/screenshot-runtime.ts#L304). The PR reports only unit tests, typecheck and lint. Nothing shows that frames differ on a real device, that per-frame capture fits the 500 ms admission budget, or that all frames land on disk. Please run These open threads still apply: the cancel check before the sleep (#4291 (comment)), and the missing cleanup on throw or abort (#4291 (comment)). The other six open review threads also still apply. I reviewed the range-diff and the 4 head commits, not the full upstream delta. I did not run tests or a device, so burst behavior and remote artifact mapping come from reading the code. I did not check whether Before merge, the burst frames must reach the client through the artifact pipeline (or |
…lean its implicit root, and refuse remote bursts The inter-frame sleep resolves on an abort too, so the loop re-checks the signal before the next capture. A failed or canceled burst without an explicit path removes the implicit temp root it created. A remote daemon returns only the first frame as a downloadable artifact, so a burst there refuses with REMOTE_SCREENSHOT_BURST_DENIED instead of shipping N-1 unreadable paths. The client requires a finite capture timestamp, and the burst tests now prove the cross-frame warning aggregation, distinct implicit paths, and an abort that lands between frames. Co-Authored-By: Claude Code <[email protected]>
There was a problem hiding this comment.
2 issues found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/daemon/src/server/__tests__/remote-host-input-policy.test.ts">
<violation number="1" location="packages/daemon/src/server/__tests__/remote-host-input-policy.test.ts:37">
P2: This “single screenshot” test does not use the production request shape: screenshot paths are sent as positionals, but the fixture supplies `input.outPath` and hard-codes an empty positional list. It can pass while remote positional handling regresses; make the helper accept positionals and cover a real screenshot path (also asserting the sanitized result).</violation>
</file>
<file name="packages/daemon/src/server/remote-host-input-policy.ts">
<violation number="1" location="packages/daemon/src/server/remote-host-input-policy.ts:175">
P2: This path silently accepts a remote screenshot with `intervalMs` but no `count`: the destructuring removes the interval, so the daemon never enforces the contract that `intervalMs` requires `count` and captures one frame instead. Reject interval-only requests before stripping the input field.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
| }); | ||
|
|
||
| test('a remote single screenshot without count still passes the capture lane', () => { | ||
| const restricted = restrictRemoteHostInputs(remoteRequest({ outPath: '/tmp/x.png' })); |
There was a problem hiding this comment.
P2: This “single screenshot” test does not use the production request shape: screenshot paths are sent as positionals, but the fixture supplies input.outPath and hard-codes an empty positional list. It can pass while remote positional handling regresses; make the helper accept positionals and cover a real screenshot path (also asserting the sanitized result).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/daemon/src/server/__tests__/remote-host-input-policy.test.ts, line 37:
<comment>This “single screenshot” test does not use the production request shape: screenshot paths are sent as positionals, but the fixture supplies `input.outPath` and hard-codes an empty positional list. It can pass while remote positional handling regresses; make the helper accept positionals and cover a real screenshot path (also asserting the sanitized result).</comment>
<file context>
@@ -0,0 +1,40 @@
+});
+
+test('a remote single screenshot without count still passes the capture lane', () => {
+ const restricted = restrictRemoteHostInputs(remoteRequest({ outPath: '/tmp/x.png' }));
+ assert.equal((restricted.input as Record<string, unknown>).count, undefined);
+ assert.equal(restricted.command, 'screenshot');
</file context>
| ((request.input as Record<string, unknown> | undefined)?.count !== undefined || | ||
| request.flags?.count !== undefined) |
There was a problem hiding this comment.
P2: This path silently accepts a remote screenshot with intervalMs but no count: the destructuring removes the interval, so the daemon never enforces the contract that intervalMs requires count and captures one frame instead. Reject interval-only requests before stripping the input field.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/daemon/src/server/remote-host-input-policy.ts, line 175:
<comment>This path silently accepts a remote screenshot with `intervalMs` but no `count`: the destructuring removes the interval, so the daemon never enforces the contract that `intervalMs` requires `count` and captures one frame instead. Reject interval-only requests before stripping the input field.</comment>
<file context>
@@ -158,7 +158,33 @@ function restrictRemoteBatchSteps(request: DaemonRequest): DaemonRequest {
+ // beats shipping N-1 unreadable paths.
+ if (
+ request.command === 'screenshot' &&
+ ((request.input as Record<string, unknown> | undefined)?.count !== undefined ||
+ request.flags?.count !== undefined)
+ ) {
</file context>
| ((request.input as Record<string, unknown> | undefined)?.count !== undefined || | |
| request.flags?.count !== undefined) | |
| ((request.input as Record<string, unknown> | undefined)?.count !== undefined || | |
| (request.input as Record<string, unknown> | undefined)?.intervalMs !== undefined || | |
| request.flags?.count !== undefined || | |
| request.flags?.intervalMs !== undefined) |
Co-Authored-By: Claude Code <[email protected]>
Co-Authored-By: Claude Code <[email protected]>
|
Both problems are addressed at the pushed head, plus every open thread. Remote bursts refuse with a typed reason. The remote capture lane refuses a screenshot request carrying Live burst run attached. Threads. The abort-during-wait now re-checks the signal before the next capture (P1); a failed or canceled burst removes its implicit temp root (failure-only finally); the cancel test aborts from inside the first capture and asserts exactly one frame; the warning-bound test uses distinguishable cross-frame contributions against the bound; the temp-root test asserts distinct implicit paths; the client filters an inside-the-bound malformed frame (and requires a finite |
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
Co-Authored-By: Claude Code <[email protected]>
|
Thanks for the update. At 77cc16f the earlier review findings (#4291 (comment)) are fixed in code, and I found nothing that must change before merge. CI is green: 14 checks, none failing. There are no conflicts. Nothing blocks merge now, apart from the open inline threads below that still apply. Not blocking, and you can take or leave these: (1) the cancel test in Of the open inline threads, these still apply: the remote policy test request shape (#4291 (comment)), which matches note 3 above. Two lower-priority threads on the evidence doc still apply (missing md5 hashes and missing I did not run tests or a device. The live burst result comes from the evidence doc, which names no SHA. I checked the remote refusal through the unit test and by reading both |
…ter-frame abort The daemon arms the burst from flags.count, so the remote policy judges that key and the policy tests drive flags and positionals as the remote client sends them. The cancel test aborts from a timer during the interval wait and asserts the abort reason with exactly one capture. The screenshot help names the remote refusal, the evidence names the SHA and frames the observed per-frame interval against the budget, the cleanup test reads the captured frame directly, and the evidence carries the md5 hashes and the json envelope. Co-Authored-By: Claude Code <[email protected]>
|
All five take-or-leave notes are taken at 3f5ffa8: the cancel test now aborts from a timer during the 1000 ms interval wait and asserts the abort reason with exactly one capture (the post-sleep check is what makes this pass); the screenshot help names |
There was a problem hiding this comment.
2 issues found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="docs/evidence/ios-burst-capture-2026-11-13.md">
<violation number="1" location="docs/evidence/ios-burst-capture-2026-11-13.md:3">
P3: This says `7f3741906` was the format-only commit after the burst fixes, but that SHA is the simulator evidence commit; `77cc16f` is the formatter commit and the current head is later. Describe this as the run commit, or cite the actual head, so readers can reproduce the evidence without ambiguous provenance.</violation>
<violation number="2" location="docs/evidence/ios-burst-capture-2026-11-13.md:6">
P2: The documented interval range contradicts the `capturedAtMs` values in this same evidence: their gaps are 724–909 ms, not 520–710 ms. Update the range or correct the captured timestamps so the budget conclusion is reproducible.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
View guided diff | Re-trigger cubic
| Live evidence for #4291 at head `7f3741906` (the format-only commit after the | ||
| burst fixes; the behavior this documents is unchanged since): the burst path | ||
| (`--count`/`--interval-ms`) captured five frames of an animation on real | ||
| simulator dispatch. The observed per-frame interval here runs about 520-710 ms |
There was a problem hiding this comment.
P2: The documented interval range contradicts the capturedAtMs values in this same evidence: their gaps are 724–909 ms, not 520–710 ms. Update the range or correct the captured timestamps so the budget conclusion is reproducible.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At docs/evidence/ios-burst-capture-2026-11-13.md, line 6:
<comment>The documented interval range contradicts the `capturedAtMs` values in this same evidence: their gaps are 724–909 ms, not 520–710 ms. Update the range or correct the captured timestamps so the budget conclusion is reproducible.</comment>
<file context>
@@ -1,7 +1,12 @@
+Live evidence for #4291 at head `7f3741906` (the format-only commit after the
+burst fixes; the behavior this documents is unchanged since): the burst path
+(`--count`/`--interval-ms`) captured five frames of an animation on real
+simulator dispatch. The observed per-frame interval here runs about 520-710 ms
+— above the plan's 500 ms per-frame budget, because each frame also pays the
+capture round trip the budget's doc comment excludes; the budget bounds the
</file context>
| simulator dispatch. The observed per-frame interval here runs about 520-710 ms | |
| simulator dispatch. The intervals between successive `capturedAtMs` values here run about 724-909 ms |
| Live evidence for #4291 at head `7f3741906` (the format-only commit after the | ||
| burst fixes; the behavior this documents is unchanged since): the burst path |
There was a problem hiding this comment.
P3: This says 7f3741906 was the format-only commit after the burst fixes, but that SHA is the simulator evidence commit; 77cc16f is the formatter commit and the current head is later. Describe this as the run commit, or cite the actual head, so readers can reproduce the evidence without ambiguous provenance.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At docs/evidence/ios-burst-capture-2026-11-13.md, line 3:
<comment>This says `7f3741906` was the format-only commit after the burst fixes, but that SHA is the simulator evidence commit; `77cc16f` is the formatter commit and the current head is later. Describe this as the run commit, or cite the actual head, so readers can reproduce the evidence without ambiguous provenance.</comment>
<file context>
@@ -1,7 +1,12 @@
-Live evidence for #4291: the burst path (`--count`/`--interval-ms`) captured
-five frames of an animation on real simulator dispatch. The screen was a page
+Live evidence for #4291 at head `7f3741906` (the format-only commit after the
+burst fixes; the behavior this documents is unchanged since): the burst path
+(`--count`/`--interval-ms`) captured five frames of an animation on real
</file context>
| Live evidence for #4291 at head `7f3741906` (the format-only commit after the | |
| burst fixes; the behavior this documents is unchanged since): the burst path | |
| Live evidence for #4291 from the simulator run at commit `7f3741906` (not the | |
| current PR head): the burst path |
|
Thanks for the update. Reviewed 3f5ffa8. The code changes since the earlier review are mostly fixed, one test still does not test what it claims, and CI is green on all 14 checks. No conflicts. The test "a configured intervalMs is removed from a screenshot request like the count" in resolve-cli-options.test.ts writes On the open review threads, these still apply and need a fix: the remote policy test input (r4565067930), the evidence interval range (r4571606745), and, as a small note, the evidence commit description. These do not apply and can be resolved: r4565067935 because I read the code and did not run the tests or the live burst again. The live evidence is from 7f37419, and the files that affect behavior are unchanged since then. Once the test fixture, the remote policy test input and the evidence interval range are fixed, nothing else blocks merge. The evidence commit description can go in the same push. |
Summary
Recording an animation today means repeating single screenshots by hand — six separate re-implementations showed up in the audited sessions.
screenshot --count N --interval-ms T(count ≥ 2, interval ≥ 100 ms) captures a frame series in one request and returns per-frameframesentries (path,capturedAtMs,displayRotation) alongside the first frame's usual fields, so motion evidence is one call with timestamps instead of a hand-built loop.10 files changed (contracts flag keys and validation, daemon capture loop, CLI output, tests).
Validation
pnpm run typecheck,pnpm run lint, screenshot and contracts tests, integration-progress--check, fallow, freerange: pass locally.🤖 Generated with Claude Code
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.