Skip to content

docs(roadmap): propose PHPickerViewController image selection - #2008

Open
0x0c wants to merge 3 commits into
mainfrom
claude/ios-phpicker-image-selection-067559
Open

0x0c wants to merge 3 commits into
mainfrom
claude/ios-phpicker-image-selection-067559

Conversation

@0x0c

@0x0c 0x0c commented Sep 16, 2026

Copy link
Copy Markdown
Member

Summary

Investigates adding selectPhotos, a step to pick images from a presented PHPickerViewController's grid by ordinal position, plus a seedPhotos precondition to seed the Simulator's photo library with known fixture images. On-device investigation found that every actuation technique tried against the picker's grid cells — a handle-based tap, a handle-based press at two durations, a raw coordinate tap, and a coordinate press (the generalization of BE-0396's own frame-centre-tap fix) — fails to reliably select a cell on an Apple silicon Simulator, matching independently reported limitations on Apple's own developer forums. Bajutsu retired its one alternative iOS actuator (idb) in BE-0290, leaving no existing fallback path around this.

This PR records the proposal as Deferred rather than Implemented: the design for the buildable parts (seeding, the DSL action, capability plumbing) is kept as the starting point for whoever resumes the item, and the blocked actuation investigation is recorded in full, with sources, so resuming does not start from scratch.

What changed

  • roadmaps/BE-XXXX-phpicker-select-photos/ (new) — the bilingual proposal (English + Japanese). Introduction/Motivation state the gap and the two facts (non-deterministic grid content by default, cells that cannot be actuated reliably) that decided the design. Detailed design covers Units 1 (photo seeding), 2 (the SelectPhotos DSL action), 3 (actuation — blocked, with the four attempts and results tabulated), and 4 (capability + showcase fixture). Alternatives, Progress, and References close it out.

Scope

No product code in this PR. Every actuation technique tried failed on-device (Unit 3), so nothing is shippable yet — shipping the seeding/DSL/capability units alone would land a DSL surface that parses and then fails every run, which is worse than not shipping it. This PR is the investigation and proposal only.

Prime-directive compliance

Docs-only change; no runtime behavior is touched.

Verification

make check
  7832 passed, 6 skipped, coverage 94.96% (floor 93.0%)

scripts/lint_roadmap.py: all item links resolve and authors are handle links.

Files

  • roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md + its -ja.md mirror (bilingual pair)

BE ID allocation

BE-XXXX is a placeholder — CI allocates the real id on main after merge. Don't hand-edit it.

🤖 Generated with Claude Code

Investigated selectPhotos, a step to pick images from PHPickerViewController's
grid, along with a seedPhotos precondition for deterministic fixture content.
On-device investigation found that every actuation technique tried against
the picker's grid cells (handle-based tap, handle-based long-press at two
durations, a raw coordinate tap) fails to reliably select a cell on an Apple
silicon Simulator, matching independently reported limitations on Apple's own
developer forums. Bajutsu retired its one alternative iOS actuator (idb) in
BE-0290, leaving no existing fallback path around this. The item is recorded
as Deferred with the full investigation, rather than shipped with a core
mechanism that does not work on the architecture most contributors run.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@0x0c
0x0c requested review from a team and a lite review from Copilot September 16, 2026 03:04
@0x0c
0x0c deployed to claude-review September 16, 2026 03:04 — with GitHub Actions Active
@github-actions github-actions Bot added the topic:platform Platform expansion (Android / Web / Flutter) (roadmap topic) label Sep 16, 2026
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Outdated

Copilot AI 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.

🟡 Changes recommended

Unresolved design issues affect fixture seeding, scenario determinism, and lifecycle metadata.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This documentation-only PR adds a bilingual deferred roadmap item for PHPickerViewController image selection.

Changes:

  • Proposes selectPhotos and seedPhotos behavior.
  • Records Simulator actuation failures and deferral rationale.
  • Adds English and Japanese roadmap documentation.
File summaries
File Description
roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md English proposal and investigation
roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Japanese proposal mirror
Review details

Suppressed comments (18)

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:280

  • この参考文献でも「実演算経路」を使っています。本文と同じく、一般的でないこの語を「操作手段」などの明確な表現に置き換え、文末も文書の敬体にそろえてください。
  — `idb`の廃止。Unit 3のブロッカーを迂回できていた可能性がある、iOSのもう1つの実演算経路で
  あり、現在残っているのはXCUITestだけである。

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:111

  • The Japanese formatting rules prohibit using an em dash as the separator in prose headings. Use a colon here, matching the corrected Unit 1 heading.
### Unit 2 — `selectPhotos` DSLアクション

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:136

  • The Japanese formatting rules prohibit using an em dash as the separator in prose headings. Use a colon here, matching the other corrected Unit headings.
### Unit 3 — セルのアクチュエーション(ブロック中)

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:189

  • The Japanese formatting rules prohibit using an em dash as the separator in prose headings. Use a colon here, matching the other corrected Unit headings.
### Unit 4 — Capability、他バックエンド、showcaseでの実証

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:254

  • The same em-dash separator is used in this Japanese checklist label, but the formatting rules require a colon for this heading-like label. Please apply the same replacement to the other Unit checklist entries.
- [ ] Unit 1 — `addmedia_cmd`、`seedPhotos`プリコンディション、`_prepare_simulator`での

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:256

  • The same em-dash separator is used in this Japanese checklist label, but the formatting rules require a colon for this heading-like label.
- [ ] Unit 2 — `SelectPhotos` DSLアクションとそのバリデーション。

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:257

  • The same em-dash separator is used in this Japanese checklist label, but the formatting rules require a colon for this heading-like label.
- [ ] Unit 3 — ピッカーのグリッドセルを確実にアクチュエーションする手段(ブロック中。

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:259

  • The same em-dash separator is used in this Japanese checklist label, but the formatting rules require a colon for this heading-like label.
- [ ] Unit 4 — `SELECT_PHOTOS`ケーパビリティ、他バックエンドの`UnsupportedAction`、showcase

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:99

  • contained_refはシナリオファイルのディレクトリを基準に参照を解決し、スイートルートは包含境界としてだけ使います。これは現在のdataFileの挙動です。seedPhotosをスイートルート基準と記述すると、ネストしたシナリオのパス規約が既存DSLと異なり、解決方法が曖昧になります。ファイル基準で解決してスイート内に制限する仕様を明記するか、別のルート基準リゾルバーを設計してください。
`seed_photos: list[str]`(YAMLでは`seedPhotos`)を追加します。値はスイートルートを起点とした
相対パスの配列です。`dataFile`がすでに使っているものと同じ`contained_ref`の関所
(`bajutsu/common/scenario/load_expanded.py`)を通して解決するため、スイートの外を指すパスは
投入できません。投入先は`_prepare_simulator`

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:207

  • 設計では投入がcold and pre.eraseの場合に限られますが、showcaseのターゲットは組み込み既定値のerase: falseを継承しており、このシナリオの説明にも消去の前提がありません。このままではseedPhotosが実行されず、Simulatorのサンプル画像を使うため、決定的なフィクスチャになりません。説明するシナリオにpreconditions: { erase: true }を追加してください。
`demos/showcase/scenarios/select_photos.yaml`が`seedPhotos`でこれらを投入し、

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:10

  • 🤖 Claude Code — issue (non-blocking): This is a new BE-XXXX item, but the roadmap workflow requires every new item to start with Status: Proposal; Deferred is a later dashboard state. Keep the Japanese metadata in the same proposal-first state so the two language files do not initialize the item in different lifecycle stages.
| 状態 | **保留** |

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:103

  • 🤖 Claude Code — issue (non-blocking): seedPhotos is silently skipped unless the run is both cold and erasing, but warm resume passes cold=False and the scenario shape does not require an erase. The scenario can therefore pass validation while selecting pre-existing photos instead of its declared fixtures; choose an explicit reset or an early validation error rather than silently ignoring the seed.
投入できません。投入先は`_prepare_simulator`
(`bajutsu/common/platform_lifecycle/environments/xcuitest/xcuitest_environment.py:866-939`)
に限ります。対象は、コールド起動かつ`erase`を伴う経路(`cold and pre.erase`)だけです。この
経路はすでにSimulatorの既存状態を消去する経路であり、ここに乗せることで、ウォーム再開や
`erase`を伴わないリースでの重複投入を防げます。

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:109

  • 🤖 Claude Code — question (non-blocking): The reverse-order contract is based on three separate addmedia calls, but addmedia_cmd accepts a sequence and the planned shape reads as one batch command. Specify whether the implementation must call it once per fixture or establish the batch ordering; otherwise the documented indices may refer to the wrong images.
ピッカーはライブラリを新しい順に並べます。実測では、数秒間隔で3枚のフィクスチャを別々の
`addmedia`呼び出しで追加したところ、追加順とは逆順に並びました。最後に追加したフィクスチャが
インデックス0に来ます。これは、Simulatorにあらかじめ入っているサンプル画像よりも前に来ます。
したがって、シナリオの`indices`は、`seedPhotos`に列挙した順序とは逆順でフィクスチャを指す
ことになります。この対応は、動作から発見させるのではなく、DSLのリファレンスに明記します。

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:160

  • 🤖 Claude Code — suggestion (non-blocking): Realデバイス is an unnatural mixed-language term in Japanese technical prose. Use the established Japanese term 実機 for the contrast with Simulator.
Simulator上のXCUITestでは登録されない一方、Intel SimulatorやRealデバイスでは機能する、

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md:197

  • 🤖 Claude Code — issue (non-blocking): SELECT_PHOTOS is declared by the whole XcuitestDriver, which also supports real devices, while the seeding design only runs through _prepare_simulator. On a real device, seedPhotos would be ignored even though capability preflight succeeds, so ordinal selection is not deterministic. Define whether real devices reject the feature, require an external fixture, or get a separate seeding path before exposing the capability.
`Capability.SELECT_PHOTOS = "selectPhotos"`(`bajutsu/common/drivers/base/capability.py`)は
`XcuitestDriver.CAPABILITIES`(ユニットテスト用に`FakeDriver.CAPABILITIES`にも)だけが宣言
します。`bajutsu/common/capability/capability_preflight.py`で`HANDLE_SYSTEM_ALERT`と同様に
ゲートします。Androidやwebのターゲットが`selectPhotos`を使うと、実行時の不透明なエラーでは
なく、プリフライトの時点で名指しのケーパビリティエラーになります。`playwright_driver.py`・
`adb_driver.py`・`xcuitest_live_driver.py`・`web_context_driver.py`は、それぞれ自身の
`select_photos`から`UnsupportedAction`を送出します。他のiOS専用アクションと同じ扱いです。

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md:10

  • 🤖 Claude Code — issue (non-blocking): This is a new BE-XXXX item, but the roadmap workflow requires every new item to start with Status: Proposal; Deferred is a later dashboard state. Leaving this as Deferred bypasses the proposal-first lifecycle, so change the metadata to Proposal and defer it after the item is allocated.
| Status | **Deferred** |

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md:104

  • 🤖 Claude Code — question (non-blocking): The reverse-order contract was measured with three separate addmedia invocations, while the proposed builder accepts a sequence and emits one argv. Unless seeding explicitly invokes the builder once per file (or the batch ordering is measured), import timestamps can differ and indices can select the wrong fixture; define the invocation granularity before making this ordering part of the DSL contract.
The picker sorts the library newest-first (measured: three fixtures added a few seconds apart, via
three separate `addmedia` invocations, appeared in reverse of their addition order — the
most-recently-added fixture at index 0), *ahead of* the Simulator's own pre-installed sample

roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md:192

  • 🤖 Claude Code — issue (non-blocking): SELECT_PHOTOS is declared by the whole XcuitestDriver, which also supports real devices, but Unit 1 only seeds through _prepare_simulator; real-device setup therefore ignores seedPhotos. A scenario can pass capability preflight and then select ordinal positions from an uncontrolled library, defeating the deterministic fixture contract. Define whether real devices reject seedPhotos/selectPhotos, require an external fixture, or receive a separate seeding path before exposing this capability.
`Capability.SELECT_PHOTOS = "selectPhotos"` (`bajutsu/common/drivers/base/capability.py`) is
declared only by `XcuitestDriver.CAPABILITIES` (and by `FakeDriver.CAPABILITIES` for unit tests),
gated through `bajutsu/common/capability/capability_preflight.py` the same way
`HANDLE_SYSTEM_ALERT` is — an Android or web target using `selectPhotos` fails preflight with a
named-capability error rather than an opaque runtime one. `playwright_driver.py`, `adb_driver.py`,
`xcuitest_live_driver.py`, and `web_context_driver.py` each raise `UnsupportedAction` from their own
`select_photos`, matching every other iOS-only action.
  • Files reviewed: 2/2 changed files
  • Comments generated: 10
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos-ja.md Outdated
Comment thread roadmaps/BE-XXXX-phpicker-select-photos/BE-XXXX-phpicker-select-photos.md Outdated
T and others added 2 commits September 16, 2026 12:20
Prototyped a coordinate press (XCUICoordinate.press(forDuration:)), the
generalization of BE-0396's own frame-centre-tap fix, by extending tapPoint
with an optional duration end to end (Swift + Python + DSL). It fails the
same way the plain coordinate tap does: accepted, no cell marked selected.
Reverted the prototype since it did not unblock the item, and recorded the
result in Unit 3 as the closing of the most obvious remaining avenue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Fix a factual error: `photos` is an ordinary simctl privacy TCC service
  (like camera/location); the gap is that granting it does not pick an item,
  not that no such service exists.
- Move `seed_photos` from `Scenario` to `Preconditions`, beside `erase`/
  `reinstall`, so it reaches `_prepare_simulator` with no new plumbing
  (previously `Scenario`-level fields need threading through `launch_driver`
  the way `permissions` is).
- Require `erase: true` alongside a non-empty `seed_photos` via a loud,
  load-time validator, instead of a silent no-op that would leave
  `selectPhotos` addressing the Simulator's ambient library.
- Seed one path per `addmedia` invocation (matching what was actually
  measured) rather than batching, since batch ordering is unverified.
- Fix `contained_ref`'s description: paths resolve relative to the scenario
  file's own directory, with the suite root only as the containment
  boundary — matching `dataFile`'s existing resolution exactly. Note that
  `bajutsu run`'s own loader shares the same function.
- Fix the confirm-button resolution to identify the picker's navigation bar
  by trait alone, not by its localized "Photos" title, so the rule stays
  locale-independent as advertised.
- Record the exact presentation setup (selectionLimit, UIViewController-
  Representable) Unit 3's measurements used, for reproducibility.
- Add the required `erase: true` precondition to the showcase demo scenario
  description.
- ja: fix em-dash Unit headings to colons, replace the non-standard
  「実演算経路」 wording, remove a duplicate/contradictory BE-0396 reference,
  and bring the log entry's register in line with the rest of the document.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@0x0c
0x0c marked this pull request as draft September 16, 2026 10:28
auto-merge was automatically disabled September 16, 2026 10:28

Pull request was converted to draft

@0x0c
0x0c marked this pull request as ready for review September 18, 2026 07:33
@0x0c 0x0c changed the title docs(roadmap): propose and defer PHPickerViewController image selection docs(roadmap): propose PHPickerViewController image selection Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:platform Platform expansion (Android / Web / Flutter) (roadmap topic)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants