Repository navigation
feat(shell): act on the Console's ready and routeChanged signals; the shell owns the safe area - #166
Conversation
… ready The loading cover and a route held on cold start now wait for the Console's `ready` bridge event instead of the WebView's load end, with an 8 s timeout after load end for Consoles that never post it. The last route a re-created WebView resumes at comes from `routeChanged`; navigation state is only the fallback for Consoles that never post it. One pure state machine (lib/shell/console-load.ts) drives all three. Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
…e area Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
|
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv Seat verdict: ACCEPT — Head-sha: 维护者速读
席位意见: 实现收敛成一个可单测的纯状态机。消融实测:把 席位核对
|
Resolves the docs/HYBRID-SHELL.md Testing-list conflict with #165: both entries kept (the server probe and picker tests, and the load state machine test). #165's Server selection section, Session-and-auth wording and Layout entries merged cleanly beside this branch's Load states and Safe area sections. Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
|
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv ACCEPT re-pinned to head The head moved by one merge of Check-runs on |
Reconciles #167 (installId, pushTokenChanged) with the load state machine: one source of readiness. The held push token moves into lib/shell/console-load.ts as state plus a sendPushToken effect, sent on entering `ready` (the event or the ready timeout) and re-armed by the shell's reload() and a re-created WebView. #167's consoleReadyRef, heldPushTokenRef and onLoadStart re-arm are dropped: on Android react-native-webview 13.16 fires onLoadStart from doUpdateVisitedHistory, i.e. for SPA history changes too. hostInfo and bootstrap stay exactly as #167 wrote them. Docs stack both sides. Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
|
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv ACCEPT re-pinned to head 维护者速读(本轮增量)
席位核对(增量)
|
Reconciles #170 (bridge scan(), per-WebView answer guard) with the load state machine. #170's documentRef and the onMessage answer guard stay; the counter is bumped in the machine's `recreate` effect, the one place a new WebView is created, and nowhere tied to onLoadStart (still unwired, as in the #167 reconcile). Two #170 tests drove a load start through the `onLoadStart` prop; they now deliver it the way react-native-webview's WebViewShared does (onLoadStart if wired, then onNavigationStateChange). Docs stack #170's Scanning codes and wire-format text beside Load states. Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
|
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv ACCEPT re-pinned to head 维护者速读(本轮增量)
席位核对(增量)
|
|
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv Seat landing under the maintainer ruling recorded on the seat post (#160): 「非受管 PR 由席位落地」.
Action: auto-merge enabled, which enqueues the PR in the merge queue behind #172 (the |
Fixes #162
Clause-②: no
Metadata-protocol: none
维护者速读
pushTokenChanged),现在都由同一个加载状态机决定何时放行:等 Console 发出ready,加载结束后 8 秒超时兜底;WebView 重建后回到的「上次路由」改以 Console 的routeChanged为准;文档写明安全区内边距由壳负责。onLoadStart重新挂起令牌,但 Android 上 SPA 内跳转也会触发它,之后不会再有ready,令牌会一直扣着。ready,遮罩会在加载结束后多停最多 8 秒,暂存的路由与令牌也在那时才送出;页面自己发起的整页跳转(旧版回退的location.assign、第三方登录往返)不会重新挂起,期间送出的令牌或路由会随旧页面丢失。回滚即 revert 本 PR,不涉及数据或协议版本。lib/shell/console-load.ts的becomeReady与loadEnd/ready/pushToken分支(:113-175,决定遮罩、路由与令牌何时放行);components/shell/ConsoleWebView.tsx的dispatch与效果执行(:155-191,其中recreate效果在 :183 递增 feat(bridge): scan() — native barcode / QR scanner for Console fields #170 的文档计数)、令牌接入(:279-290);docs/HYBRID-SHELL.md的 Load states 一节。npx jest --ci __tests__/lib/shell/console-load.test.ts __tests__/components/ConsoleWebView.test.tsx,预期 2 个套件、61 个用例全部通过。What changes
lib/shell/console-load.ts, pure):loadingthenloaded(WebView load end) thenready(the Console'sready, orREADY_TIMEOUT_MS= 8 s after load end), plusfailed.ConsoleWebViewkeeps it in a ref and performs the effects it returns: inject a route, send a push token, arm or clear the ready timer, re-create the WebView.ready. The cover stays up past load end untilready. Areadythat arrives before load end counts. The timeout runs only from load end, and never on a failed load.ready. A route asked for beforeready(a notification tap on cold start) is dispatched once, atreadyor at the timeout. Load end no longer dispatches it.readyis held, the latest only, and sent on enteringready: by the event or by the timeout. A held token survives a failure and a re-created WebView. The shell's ownreload()and a re-created WebView re-arm the hold.consoleReadyRef,heldPushTokenRefandonLoadStart={onDocumentStart}are dropped, as feat(bridge): stable installId and pushTokenChanged for device registration; document the no-Service-Worker rule #167's own reconcile note planned. The held token lives in the machine, with asendPushTokeneffect.onLoadStartis not wired as a document start. In react-native-webview 13.16 on Android,topLoadingStartis emitted fromRNCWebViewClient.doUpdateVisitedHistory, which also runs for SPA history changes;onPageStartedemits none. A re-arm there would hold every later token until a secondreadythat never comes.hostInfo(installId,BRIDGE_CAPABILITIES) andbootstrap(buildBootstrapScript(hostInfo, serverUrl), origin-gated) are byte-identical tomain.documentRefand theonMessageguard are unchanged: an answer whose WebView was re-created meanwhile is dropped. The counter is now bumped in the machine'srecreateeffect, the one place a new WebView is created. Nothing tied toonLoadStartbumps it;onLoadStartis still unwired. feat(bridge): scan() — native barcode / QR scanner for Console fields #170'scapabilitiesandscanwiring are unchanged.routeChanged. The payload'sroutepassessafeConsoleRouteand becomes the last route. After the first one,onNavigationStateChangeno longer moves it; before that it is the fallback.docs/HYBRID-SHELL.mdnow says the shell owns the padding and that--os-native-safe-*are informational. It drops the "pad with the safe-area variables" line and the "stopgap" paragraph. Its load-states section and the push-token delivery rule now point at the state machine.readysits behind the cover.Platform facts this rests on, read at objectstack
origin/main2771575:Promise.all([initRuntimeConfig, preflightAuth, seedTenantLanguage]).finally(async …), afterawait preloadBootstrapLocale(ui/apps/console/src/main.tsx:79-100, render at :168-176). So its navigate listener mounts after the document's load. The card's citation holds.useNativeHostRouting(ui/packages/mobile/src/useNativeHost.ts:112-136) postsready, postsrouteChanged, and adds theobjectstack-native:navigatelistener in three effects of one component, flushed in the same commit. By the time the shell receivesready, the listener is mounted.routeChangedcarries{ route }: the router's pathname (basename/_consolestripped), search and hash (ui/apps/console/src/App.tsx:155-158). That is the shell's Console-route form.ui/reads--os-native-safe-*. The Console's fewenv(safe-area-inset-*)uses resolve inside the natively inset WebView frame, so nothing is padded twice.Tests
__tests__/lib/shell/console-load.test.ts(24 cases) covers the machine:readyafter load end and before it, the timeout fallback, and a timeout outsideloaded;readylifts nothing;routeChangedover navigation state;readyafter the held route, sent at the timeout, sent straight whenready, held again after a reload, and kept through a failure and a re-created WebView.__tests__/components/ConsoleWebView.test.tsx(37 cases). The cover now waits forready. New cases cover:readyand not at load end;readybefore load end, and areadyfrom another origin ignored;routeChangedroute, and unsaferouteChangedpayloads dropped;readydelivered on the ready timeout, and a token after an in-app navigation delivered at once.onLoadStartcall after "Try again" is removed, because the re-created WebView re-arms the hold itself. It still asserts nothing is delivered while failed, andfcm-3is delivered at the recovered page'sready.ref.reload(), with a check that the WebView'sreloadran, instead of a bareonLoadStart. It still asserts nothing is delivered before the newreadyandapns-4is delivered at it.loadStart()helper delivers a load start the way react-native-webview'sWebViewShared.onLoadingStartdoes:onLoadStartwhen the host wires one, thenonNavigationStateChange. That replaces a bare call to the now-unwiredonLoadStartprop.openScan()setup: "is injected into the page that asked while that page is still there" and "is dropped when the WebView was re-created meanwhile" run through it.d1.1answer is injected after a same-WebView load start. Ablation leg 3b shows it goes red if a load start bumps the counter.Gate readings at b82e022
Ablations (one-time, not committed)
Leg 1, cover and route (at 2e52b7e): the
loadEndtransition was mutated to "ready at load end" (return becomeReady(state, [])). 8 of 45 failed, including "holds a route asked for on cold start past load end, and dispatches it on ready". Restored; the blob hash matchedHEAD.Leg 2, token flush (at 7246e1e): the
sendPushTokeneffect inbecomeReadywas removed.Leg 3, the answer counter (at b82e022, ConsoleWebView suite, 37 cases). Both legs were restored by
git checkout HEAD; the blob hash matchedHEAD(096d123) andgit diff HEADwas empty.Acceptance notes
ready, such as an older Console'slocation.assignfallback or an identity-provider round trip.onLoadStartcannot be that signal (see What changes).readycurrently fires at the Console's first router commit, which can be its own loading fallback. Native host: makeObjectStackNative.platforman open set and pin it with an App-level test (follow-up to #29140) objectstack#29330 settles that. Lifting the cover onto a spinner the Console painted is accepted by the card.onLoadStartreading comes from the react-native-webview 13.16 source (RNCWebViewClient.java). It was not measured on a device.Verification
Generated by Claude Code