Repository navigation
Conversation
The new-session profile picker reads its pick and its scope from the bridge the composer writes, so a deep link alone only shows the expired state and no design-gate run can measure the sheet. This adds a development-only fixture path that writes the same bridge and opens the same route, plus a seed topic that creates an organization whose shared profile is its default, so the sheet can be opened with real data in both scopes. No production behavior changes: the fixture is behind the development scheme and a __DEV__ check.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryThe incremental change adds one test asserting that a fixture link with an empty Assumptions: Files Reviewed (1 file)
Previous Review Summaries (4 snapshots, latest commit 32299d4)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 32299d4)Status: No Issues Found | Recommendation: Merge Executive SummaryThe incremental change gives the profile picker sheet's loading, error, and empty states the same Cancel control as the list state so all four share one centred header, and replaces the sheet-only empty copy with the existing Assumptions: Files Reviewed (3 areas)
Previous review (commit 4f3f6ef)Status: No Issues Found | Recommendation: Merge Executive SummaryThe two follow-up commits move the form-sheet header's top-clearance decision from a post-presentation Assumptions: Files Reviewed (6 files)
Previous review (commit 2667773)Status: No Issues Found | Recommendation: Merge Executive SummaryThe follow-up commit Assumptions: Files Reviewed (3 files)
Previous review (commit 9ac9322)Status: 1 Issue Found | Recommendation: Address before merge Executive SummaryThe new dev-only profile-picker fixture cannot open its documented personal-scope link, because the regex's "no match" and "matched without a query" cases are both Assumptions: Overview
Issue Details (click to expand)WARNING
Files Reviewed (3 files)
Reviewed by deepseek-flash-latest · Input: 53.7K · Output: 11.4K · Cached: 641.2K Review guidance: REVIEW.md from base branch |
The fixture matched its path and its query with one optional group, so a link without a query looked like a path that is not the fixture and the personal-scope link was dropped before it reached the route. An empty `org` value also stayed a string, which the sheet read as an organization scope with no id and answered with its error state. Check the path match on its own, and read the query from the optional group, so an absent or empty `org` is the personal scope.
|
bot: Ran the new profile picker fixture on the Android emulator against the local dev stack, signed in as the seeded organization owner.
The seed topic created the user, the organization with that user as its only member, and that organization-owned profile with |
A transformed view moves its descendants and not its own frame, so a natively presented formSheet reports its screen at the window origin while its content sits at the detent. `clipped` compared the child's transformed rect against the parent's untransformed one and reported the whole sheet content as cut. Both sides now use the layout frame, the same space the layout-shift rule already measures in.
…ow inset On Android a form sheet header reserved the status-bar inset on its first frame and dropped it once the sheet settled at its detent, moving the title by the inset. The detent cap already keeps a sheet below the status bar whenever the window reports a top inset, so the window inset alone answers whether the header must clear the status bar itself — the landscape window without one. The measurement that flipped the value after the presentation is gone.
|
bot: Design gate and fixture captures at 4f3f6ef. The profile picker sheet, opened through the development fixture on this VM's Android emulator against the local dev stack (signed in as the seeded organization owner):
The contact sheet is the standard-matrix design gate run over both fixture states and the existing model-picker sheet as a control: exit 0, 0 errors, 0 warnings across 4 cells. |
The profile picker sheet drew two different headers: the list state had Cancel leading and a centred title, while the loading, error and empty states had no Cancel, so SheetHeader left their title leading against the sheet edge and the sheet changed shape as its data arrived. Every state now renders the same header, and the empty state names the condition instead of repeating the sheet title: "No profiles yet" over the shared profiles description, which reuses copy the profiles screen already translates. The sheet-only duplicate is gone from every catalog.
…fixture-tooling # Conflicts: # apps/mobile/src/app/+native-intent.tsx # apps/mobile/src/i18n/locales/et.json
|
bot: Design gate re-run at head 32299d4 on the Android emulator ( The profile picker sheet now keeps one header in every state: Cancel at the start, the centred Design gate: 4 cells (base, dark, compact, rtl), 0 errors, 0 warnings. The merge-base run cannot open either fixture link and still reports the sheet-wide Attaching the run's contact sheet, with the merge-base sheet after it. |
Keep main's sheet-level top-inset declaration alongside this branch's Cancel in every sheet state, and keep the fixture's link parsing that treats an absent or empty `org` value as the personal scope.
…link The fixture now keeps an empty `org` value in the personal scope, so the link the seed prints with no organization still opens the sheet instead of its organization error state. Assert that case next to the other link shapes.
|
bot: Design gate and sheet captures after merging Exercised on this VM's Android emulator, dev client connected to the local Metro bundle, against the local dev stack, signed in as the seeded organization owner with the development fixture links, at this head:
The merge-base run of the same three links reports the clipping and header-shift errors this pull request fixes, including on the model-picker sheet whose code this branch does not change. |
Main now carries the design-gate clipping fix and the form sheet header's window-inset decision from the sibling work, so take main's versions of those files and keep this branch's profile picker header and fixture link parsing.
|
bot: Design gate and sheet captures after the second merge of Exercised on this VM's Android emulator, dev client connected to the local Metro bundle, against the local dev stack, signed in as the seeded organization owner, opening the development fixture links at this head:
The sheet state claims come from the gate's own layout dumps of each capture, taken with the screenshots. |















Evidence
Evidence: demonstrated — ran the design gate and the development fixture links on this VM's Android emulator against the local dev stack, after merging
maininto the branch. At this head both fixture scopes render one header (Cancel, the centredPick a profiletitle,Done) and the empty state names its condition; on the merge base the same personal-scope link renders the sheet with noCanceland repeats the sheet title as the empty-state title. Read from the gate's own dumps of each state, not from the screenshots alone.What changes
mainnow carries most of what this branch originally added — the profile picker fixture, its seed topic, the form sheet header's window-inset decision, and the design-gate clipping fix — so the merge takesmain's versions of those files and this pull request keeps the two pieces that are still its own.apps/mobile/src/components/agents/profile-picker-sheet.tsxkeeps one header across the sheet's states. The list state passed Cancel while the loading, error and empty states did not, and the shared header centres its title only between a leading and a trailing control, so those states redrew the same sheet with a leading title and no way out at the start. All four states now pass Cancel, and the empty state names the empty condition over the profiles screen's existing description instead of repeating the sheet title, which removes the sheet-only catalog string from every locale.apps/mobile/src/lib/profile-picker-fixture.tskeeps an emptyorgvalue in the personal scope. A link whoseorgcarried no value named an organization id of'', which the sheet answered with its organization error state instead of the personal scope.profile-picker-fixture.test.tscovers that link shape next to the others.No production behavior changes: the fixture path is reached only through the development scheme and a
__DEV__check, and the sheet change is presentation and copy only.Verification
--matrix standard, three links (both fixture scopes plus the model-picker sheet as a control): exit 0, 0 errors, 0 warnings across 4 cells;skippedRulesis empty./agent-chat/profile-pickerwithCancel,Pick a profile,Done, thenNo profiles yetover the shared description; the organization link settles on the same route with the same header and the seeded shared profile as the resolved default. The merge-base dumps showPick a profile,Done, thenPick a profileagain with the longer empty-state sentence and noCancel, which is the state this change removes.profile-picker-sheet.mounted.test.tsxasserts one header across all four states (Cancel present, the same title, Cancel closes) plus the empty state's copy;profile-picker-fixture.test.tscovers the link shapes including the emptyorgvalue. Thedev/local/design-gatesuites (140 tests) pass.pnpm --filter kilo-app run check:i18nreports every one of the 87 catalogs matchesen.json.pnpm --filter kilo-app run typecheck, the mobile oxlint config on the touched paths, andoxfmt --list-differenton them are clean.Design gate: 4 cells, 0 errors, 0 warnings
Production prerequisites
None.
Proxy answers
The owner's proxy gave these answers in the owner's place.
clippedone is a design-gate coordinate-space bug (main's model-picker sheet reports it too), and the 51.8 dplayout-shiftis a real title jump in the shared SheetHeader. To get the gate to exit 0 at the fixture head I must touch dev/local/design-gate (compare boxes in one coordinate space, with unit tests) and apps/mobile/src/components/sheet-header.tsx (Android bottom form sheets never reserve the status-bar inset, because the capped full detent always sits below it). How wide should this PR go?Answer: Fix both in this PR
Confidence: 0.66 · Precedent: Put each separate concern in its own PR, but put a small fix that unblocks the current PR's CI into that PR: owner typed "fix in this PR" instead of a separate fix PR (a9522cd75f53). Also: fix the class, not the symptom, and fix gaps you see (00eb2a1d3e4b, 89824a222897).