feat(app-shell): global settle signal + region aria-busy (ADR-0054 Phase 3)#1883
Merged
Conversation
…ase 3)
Gives an automated (AI) browser driver one machine-readable "is the app idle?"
predicate instead of hardcoded waits (ADR-0054 invariant C5).
- **Global in-flight signal.** A module counter (`observability/settleSignal`) is
incremented around every outbound request by wrapping the adapter's `fetch`
with `withSettleSignal()` in AdapterProvider. `installSettleSignalGlobal()`
exposes live `window.__objectui.{pendingRequests, idle}` getters plus
`whenIdle()` and `subscribe()`.
- **React binding.** `useSettleSignal()` returns `{ pending, idle }`; lower-level
`getPendingRequests`/`subscribeSettle`/`whenIdle`/`withSettleSignal`/
`installSettleSignalGlobal` are exported too. 8 unit tests.
- **Region-level state.** The list view root and record-picker results region now
set `aria-busy` while fetching and `data-state="loading|idle"`, complementing
the Radix `data-state` already on overlays.
Verified in-browser (agent-browser/CDP): `window.__objectui.idle` is true at rest;
`pendingRequests` peaks at 8 during app load and during a palette record search,
then settles to 0; `whenIdle()` resolves; the list region reports
`data-state="idle"` when settled. No auth/console regressions (the fetch wrapper
preserves authenticated requests).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This was referenced Jun 22, 2026
xuyushun441-sys
added a commit
that referenced
this pull request
Jun 22, 2026
…ADR-0054 Phase 5) (#1890) Locks in the testability contract so it can't regress ("counts can only go down"). - **Conformance test** (`adr0054-ratchet.test.ts`, runs in the gating `pnpm test` job): fails the build if a new synthetic-event trigger (`dispatchEvent(new KeyboardEvent/MouseEvent/PointerEvent)`) appears anywhere in `packages/*/src` or `apps/*/src`. Legitimate `CustomEvent`/`PopStateEvent` dispatch (event bus / history nudge) stays allowed. - **Local ESLint rule** `object-ui/no-synthetic-event-trigger` flags the same pattern in-editor (the repo `Lint` workflow is manual `workflow_dispatch`, so the test — not lint — is the CI gate). Plain-JS RuleTester unit test. - **Last two offenders fixed**: the sidebar swipe-to-open gestures (`UnifiedSidebar`, `AppSidebar`) dispatched a synthetic click on the trigger; now call the idempotent `setOpenMobile(true)` directly (C1). Tree is clean at zero. - Docs: README "Testability ratchet" section; ADR-0054 marked all five phases shipped. Completes the ADR-0054 rollout (Phases 1 #1879, 2 #1882, 3 #1883, 4 #1887, 5). Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
ADR-0054 "UI testability contract" — Phase 3 (machine-readable async state, C5). Gives an automated (AI) browser driver one predicate — "is the app idle?" — so it can wait for settle instead of hardcoding timeouts or scraping per-component spinners.
Changes
observability/settleSignal): a module counter incremented around every outbound request by wrapping the adapter'sfetchwithwithSettleSignal()inAdapterProvider.installSettleSignalGlobal()installs livewindow.__objectui.{pendingRequests, idle}getters pluswhenIdle(timeoutMs?)andsubscribe().useSettleSignal()→{ pending, idle }(viauseSyncExternalStore). Lower-levelgetPendingRequests/subscribeSettle/whenIdle/withSettleSignal/installSettleSignalGlobalexported. 8 unit tests.aria-busywhile fetching anddata-state="loading|idle"— complementing the Radixdata-statealready on overlays.Verification (browser, agent-browser / CDP)
Worktree console (
:5182, mypackages/*/srcvia HMR) →app-showcasebackend (:3010):window.__objectuipresent with liveidle/pendingRequests+whenIdle/subscribe. ✅pendingRequestspeaks at 8 during app load and during a palette record search, then settles to 0 (idle === true). ✅whenIdle()resolves. ✅data-state="idle"when settled (10 rows live);aria-busycorrectly absent when not busy. ✅Unit/type: settleSignal (8) + app-shell (658) + plugin-list (127) + fields (4236) suites green;
tscbuild green.ADR rollout
Phases 1 (#1879) + 2 (#1882) merged. This is Phase 3. Next: Phase 4 (locator coverage), Phase 5 (ratchet).
🤖 Generated with Claude Code