Skip to content

fix(limrun): normalize variant iOS scalar attributes into snapshot text - #3641

Merged
thymikee merged 3 commits into
mainfrom
fix/limrun-ios-numeric-ax-value
Oct 15, 2026
Merged

thymikee merged 3 commits into
mainfrom
fix/limrun-ios-numeric-ax-value

Conversation

@thymikee

@thymikee thymikee commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Summary

snapshot failed with e?.trim is not a function on any Limrun iOS screen whose nodes report a numeric accessibility value — the system photo picker's segmented tabs report AXValue 1/0 as JSON numbers. iOS AXValue is a variant attribute, but the Limrun raw mapping forwarded it verbatim into RawSnapshotNode.value, which every producer publishes as text; consumers (react-native-overlay, snapshot-state) legitimately call ?.trim() trusting that contract.

The fix repairs the construction path, not the guards: packages/provider-limrun/src/snapshot.ts now normalizes label/value/identifier through one scalarText reader — the same normalization the Apple tree applies to its guest scalars — and widens IosTreeNode's text fields to the JSON union the provider actually sends. The issue's "Related (minor)" is the same seam: Selected in traits now publishes selected: true (omitted otherwise), the shape the Apple tree uses, so picked photos are visible and selected: selectors work. 3 files, no shared-consumer changes.

Closes #3634

Validation

Head 42ab24006. Same script mapping the picker's { AXLabel: 'Photos', AXValue: 1 } node and trimming value (base 8c01a3787 | head):

base head
value: 1 typeof: number / trim threw: value?.trim is not a function value: "1" typeof: string / trim: 1
  • pnpm check:affected --run: all runnable checks passed (128 files, 798 tests).
  • vitest run --project unit-core: 14,288 passed.
  • New tests are revert-sensitive: without the fix checked is not derived from numeric AXValue and Selected yields selected: undefined.
  • Unresolved risk: no live Limrun session locally, so the provider integration lane on the PR head is the live evidence; the fixture reproduces the raw tree from the issue verbatim.

View guided diff Turn on auto-fix

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 4 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/provider-limrun/src/ios-snapshot-adapter.test.ts
Comment thread packages/provider-limrun/src/snapshot.test.ts Outdated
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.24 MB 5.24 MB +144 B
Package (unpacked) 5.24 MB 5.24 MB +144 B
Package (download) 1.57 MB 1.57 MB +49 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.1 ms 26.4 ms -0.7 ms
CLI --help 75.7 ms 77.1 ms +1.4 ms

@thymikee

Copy link
Copy Markdown
Member Author

I found no code problems in 42ab240. The change turns numeric and boolean Limrun iOS attributes into snapshot text, and the shape now matches the Apple tree.

CI is unclear. Coverage failed in run 38724559473 and I could not read its log, so I do not know the cause. That job runs the unit suites, which include the changed provider-limrun tests, so please check whether the failure comes from this diff. Lint, Typecheck, Integration, Repo Guards and two Smoke jobs pass. Compatibility & Provenance, CodeQL and three Smoke jobs were still pending or queued when I looked.

Before merge, please clear the red Coverage job and let the pending checks finish.

Not blocking, and you can take or leave these: the doc comment on scalarText in https://github.com/callstack/agent-device/blob/42ab240/packages/provider-limrun/src/snapshot.ts#L157 says it is "the same normalization" and "the one place". It only mirrors optionalScalar at https://github.com/callstack/agent-device/blob/42ab240/packages/platform-apple/src/snapshot-source/tree.ts#L402, and the two differ on non-scalar input (Apple throws, Limrun stringifies). Softening the comment would be enough. Also, one flattenIosTree case with a numeric AXLabel and AXUniqueId would cover the label and identifier reads at https://github.com/callstack/agent-device/blob/42ab240/packages/provider-limrun/src/snapshot.test.ts#L20.

Two open inline threads from other reviewers still apply and are not blocking: #3641 (comment) (adapter test coverage gap) and #3641 (comment) (label and identifier tests). They are the same gap as the test note above.

I did not run the tests locally or do a live Limrun run, so fidelity to real responses rests on the raw nodes pasted in the issue. I also could not tell whether anything downstream relied on Limrun sending an explicit selected:false. This change now omits it, like the Apple tree.

The Limrun iOS elementTree is JSON, and iOS AXValue is a variant attribute: the system
photo picker's segmented tabs report the numbers 1/0. The raw mapping forwarded the
number into RawSnapshotNode.value, which every producer publishes as text, so a
consumer trusting that contract (the React Native overlay pass calling ?.trim()) threw
and failed the whole snapshot. Normalize label, value, and identifier at the provider
seam, the way the Apple tree normalizes its guest scalars, and derive selected: true
from the Selected trait the picker reports on a tapped photo, matching the shape the
Apple tree publishes.

Closes #3634
A variant scalar can arrive in any text attribute over the provider's untyped JSON
channel, so the mapping test now asserts a numeric label and a boolean identifier, and
the picker adapter fixture carries a numeric AXUniqueId through acquisition. Soften the
scalarText comment: it mirrors the Apple scalar reader's published shape but stringifies
unexpected types instead of throwing.
@thymikee
thymikee force-pushed the fix/limrun-ios-numeric-ax-value branch from 42ab240 to 1fc35b5 Compare October 15, 2026 14:05
@thymikee

Copy link
Copy Markdown
Member Author

Rebased onto main at 1fc35b5 and addressed the review.

Coverage red was not this diff. Run 38724559473 failed on scripts/__tests__/eager-closure-budgets.test.ts > no APPROVED_OVER_CEILING row is stale for packages/daemon/src/index.ts — a stale gate approval that main's #3633 introduced and #3653 removed; the PR lane computed it against the old merge-base. The rebase to current main clears it.

Since the base moved, I reran locally on the new head: pnpm check:affected --run passes, provider-limrun package tests pass (209), tsc -b and oxlint clean.

Non-blocking notes, both taken in 1fc35b5:

  • scalarText's comment now says it mirrors the Apple scalar reader's published shape and states the deliberate difference (stringify vs throw on untrusted JSON) instead of claiming one normalization.
  • The mapping test asserts a numeric label and boolean identifier, and the picker adapter fixture carries numeric AXUniqueId: 12 through acquisition. Inline threads replied and resolved.

On selected: false: I traced every consumer during development — selectors (match.ts, predicates.ts), snapshot markers, and maestro policy all read node.selected === true or ?? false, so omitting explicit false is indistinguishable to them; the digest omitting the key now matches the Apple producer, which is the point of the shape parity.

@thymikee

Copy link
Copy Markdown
Member Author

The earlier findings from the 42ab240 review are fixed at 1fc35b5. The code looks good to me. The picker fixture now carries AXUniqueId:12 and asserts identifier '12' through captureLimrunIosSnapshot. The mapping test now covers numeric label 42 and boolean identifier true.

The diff touches only the pure JSON-to-RawSnapshotNode mapper in provider-limrun and the CHANGELOG. The Smoke Tests failure has no job log at this head, and another run is still queued. Smoke lanes drive local simulators and emulators, not Limrun, so I read the failure as unrelated to this change. The earlier Coverage failure came from a stale eager-closure-budget approval on main, also outside this diff.

I did not run a live Limrun session or the tests locally. I rely on your report of 209 provider-limrun tests and check:affected passing. I also did not re-trace the selected:false consumers myself.

Both cubic-dev-ai threads (#3641 (comment) and #3641 (comment)) are fixed at this head, so you can resolve them.

Nothing is left to change. Let the queued Smoke Tests finish, or re-run the cancelled one, then this is ready to merge.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 15, 2026
@thymikee
thymikee merged commit 1b41f3f into main Oct 15, 2026
19 of 20 checks passed
@thymikee
thymikee deleted the fix/limrun-ios-numeric-ax-value branch October 15, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

snapshot fails with "e?.trim is not a function" when an iOS node has a numeric value (system photo picker)

1 participant