mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
* fix(mobile): name the narrow host header's controls The header renders two toolbars and the phone sees the narrow one, whose controls carried neither a role nor a name. A screen reader could not find them, and C2.9's render check could only assert their absence at 390 px. The wide toolbar already names every control from the same state, so the fix is to say the same thing rather than invent wording: filter, sort, group, accounts, tasks and the search toggle take their wide sibling's role and label expression verbatim. The census names a seventh site the plan did not: the Reconnect button in the status bar above both toolbars, which is shared rather than narrow and has no wide sibling. It announces through its Text child today, so it takes the role and the string it already renders. No layout, style, handler or order changed; the diff is accessibility props only. The census parses the file with the TypeScript API and rules that every Pressable carrying an onPress has a button role and a name, and that a control both toolbars render is named the same way in both. It keys the pairing on the handler, because that is what makes two elements the same control, and asserts each shared handler is found exactly twice, so a control deleted from one toolbar cannot leave the naming rule comparing a group of one with itself. Red first, naming all seven sites by path and line. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): stop the right drawer arming hardware back on web React Native Web logs "BackHandler is not supported on web and should not be used." and returns an inert subscription, so inside the shell's page every open of this drawer put that line on the console and armed nothing. The gate is the one mounted-bottom-drawer and the file preview already carry, with the same comment stating the degradation: there is no hardware back in a WebView, and the shell owns the one the phone has. The drawer had no render test. This one mocks react-native, the safe area, gesture handler and Reanimated the way the bottom drawer's hand-back test does, and reads the call rather than the console: on iOS and on Android the handler is registered once for 'hardwareBackPress' and released when the drawer hides, and on web it is never reached. The three native cases are the control that keeps the web case honest; they passed before the fix, which is what makes the single red meaningful. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): type the right drawer test's element helper The tests-typecheck ratchet was red on the previous commit: the drawer's props declare `children` as required, so passing it as createElement's third argument left no overload matching. It is a prop here, and the helper answers a ReactElement rather than a return type borrowed from createElement. Test files sit outside `tsc --noEmit`, so only the ratchet sees this; it is the gate that exists because a type-level pin in an unchecked test proves nothing. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): write the right drawer test in JSX Lint was red on the previous commit and I ran it in the same command as the commit, so it landed: passing `children` as a prop to satisfy the type checker is exactly what react(no-children-prop) refuses. The canonical form settles both, so the test is JSX in a .tsx file and the drawer takes its body as a child again. The StyleSheet mock's generic needs the trailing comma a .tsx file requires. Re-proved in this form: with the web gate removed the web case fails and the three native cases still pass. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): derive the header's naming groups, and read a spread as unknown Round 1, four folds. The drawer's comment claimed the console line was observed inside the shell's page. It was not: the drawer's one caller is the review screen, whose route C4 serves, so no page closure reaches it today. The gate is pre-emptive and now says so in its own words rather than borrowing the bottom drawer's sentence. The naming rule iterated a hand-written list, so it only ever compared the six controls both toolbars render. Giving the two `actions.openFloatingWorkspace` sites different labels left the census green. The groups are derived from the discovered controls now, keyed by the handler text, so any handler this header presses from more than one place is compared and the failure prints both names. The declared list stays as the precondition it always was: each of the six is found exactly twice, which is what keeps the derived rule from holding vacuously over a file with no repeated handler. The scan read `Pressable` only and dropped any control whose `onPress` read as empty text, which is what a spread reads as. It reads `TouchableOpacity` too now, and a spread answers unknown rather than absent: a control whose handler or whose accessibility props arrive through one is kept, fails both rules, and prints `spread` rather than `none`, so it can never be mistaken for a control the scan judged. Red first on all four: the reviewer's disagreeing-label mutation, a spread over the a11y props, a spread over the handler, an unlabelled TouchableOpacity, and a shared control deleted from one toolbar. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): read a braced-empty label as unnamed, from one shared reader Round 2, two folds. Only a bare `""` or an omitted attribute read as unnamed, so `accessibilityLabel={undefined}`, `{''}` and an empty template all left a control with nothing to announce and the census green. Reproduced on both Tasks sites with each of the three shapes before the fix. The reader unwraps a braced expression now: a string or a no-substitution template answers its own text, and the identifier `undefined` answers empty, so all three read as unnamed. That reader was a near-verbatim copy in both censuses, which is how one of them could have gained this rule and the other kept the hole. It lives in one module under mobile-web-shell now, named for what it reads and typechecked by mobile tsc rather than by the ratchet alone. Both censuses import it and neither changed an assertion; their diffs are the deleted copies and the import. Red first, five mutations: the three empty shapes on both Tasks sites here, and `{undefined}` and `{''}` on the tasks Back, which the page census now catches too and did not before. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb