From f2f602812e6b6b63e6e4fa9535d74dd1ed1d70d4 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Thu, 12 Nov 2026 16:16:15 +0000 Subject: [PATCH 1/3] Backport upstream Fabric native-props synchronization Minimal backport of MIT-licensed upstream React Native code by OrfeasZ from 923e7ddcaf4d2de45ca7dedafbb84c6b87dbffc4 (facebook/react-native#52646). Original source copyright and license remain intact. F16 defect 1's oversized-preview qualification exposed the renderer race in the unchanged PGB-006 NativeSemantics window-resize callback. Both Fabric full lanes lost the app; a clean native rebuild still failed. The owned ASan report fabric-progress-asan-report.86816 records BUS while ShadowNode::clone copies nativeProps_DEPRECATED during AppKit layout. Guard both writers and the cloning reader with the upstream family mutex and preserve props precedence. Validated after fresh Pods and a clean Fabric native build with ASan retained: forced PGB-006 1/1, run 61d2dce4-5980-49b9-a727-412da47fca71; Apple module and Office-style bridging-header probe 3/3. Evidence: artifacts/desktop/f16-macos-physical/native-props-clean-build-green.log. FluentTester and other native app hosts were not built locally. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/calm-fabric-props.md | 5 + ...native-macos-npm-0.81.9-native-props.patch | 202 ++++++++++++++++++ package.json | 2 +- .../native-core/references/remaining-work.md | 5 +- .../native-core/references/rnmacos-patch.md | 44 ++++ yarn.lock | 6 +- 6 files changed, 259 insertions(+), 5 deletions(-) create mode 100644 .changeset/calm-fabric-props.md create mode 100644 .yarn/patches/react-native-macos-npm-0.81.9-native-props.patch diff --git a/.changeset/calm-fabric-props.md b/.changeset/calm-fabric-props.md new file mode 100644 index 0000000000..a1c5c9a883 --- /dev/null +++ b/.changeset/calm-fabric-props.md @@ -0,0 +1,5 @@ +--- +'@fluentui-react-native/native-core': patch +--- + +Document the repository-local RNmacOS native-props synchronization backport and its clean-build requirement for animated Fabric window resizing. Publishing Native Core does not install this renderer patch in a consumer. diff --git a/.yarn/patches/react-native-macos-npm-0.81.9-native-props.patch b/.yarn/patches/react-native-macos-npm-0.81.9-native-props.patch new file mode 100644 index 0000000000..ff30d085af --- /dev/null +++ b/.yarn/patches/react-native-macos-npm-0.81.9-native-props.patch @@ -0,0 +1,202 @@ +diff --git a/ReactCommon/react/renderer/core/ShadowNode.cpp b/ReactCommon/react/renderer/core/ShadowNode.cpp +--- a/ReactCommon/react/renderer/core/ShadowNode.cpp ++++ b/ReactCommon/react/renderer/core/ShadowNode.cpp +@@ -140,27 +140,32 @@ + const ShadowNodeFragment& fragment) const { + const auto& family = *family_; + const auto& componentDescriptor = family.componentDescriptor_; +- if (family.nativeProps_DEPRECATED != nullptr) { ++ ++ std::optional propsOverride; ++ { ++ std::lock_guard lock(family.nativePropsMutex); ++ if (family.nativeProps_DEPRECATED != nullptr) { ++ if (fragment.props == ShadowNodeFragment::propsPlaceholder()) { ++ propsOverride.emplace(*family.nativeProps_DEPRECATED); ++ } else { ++ // TODO: We might need to merge fragment.props with ++ // `family.nativeProps_DEPRECATED`. ++ } ++ } ++ } ++ ++ if (propsOverride) { ++ // Copy under the family lock, then parse and clone without holding it. + auto propsParserContext = PropsParserContext{family_->getSurfaceId(), {}}; +- if (fragment.props == ShadowNodeFragment::propsPlaceholder()) { +- // Clone existing `props_` with `family.nativeProps_DEPRECATED` to apply +- // previously set props via `setNativeProps` API. +- auto props = componentDescriptor.cloneProps( +- propsParserContext, props_, RawProps(*family.nativeProps_DEPRECATED)); +- auto clonedNode = componentDescriptor.cloneShadowNode( +- *this, +- {.props = props, +- .children = fragment.children, +- .state = fragment.state}); +- return clonedNode; +- } else { +- // TODO: We might need to merge fragment.priops with +- // `family.nativeProps_DEPRECATED`. +- return componentDescriptor.cloneShadowNode(*this, fragment); +- } +- } else { +- return componentDescriptor.cloneShadowNode(*this, fragment); +- } ++ return componentDescriptor.cloneShadowNode( ++ *this, ++ {.props = componentDescriptor.cloneProps( ++ propsParserContext, props_, std::move(*propsOverride)), ++ .children = fragment.children, ++ .state = fragment.state}); ++ } ++ ++ return componentDescriptor.cloneShadowNode(*this, fragment); + } + + ContextContainer::Shared ShadowNode::getContextContainer() const { +diff --git a/ReactCommon/react/renderer/core/ShadowNodeFamily.h b/ReactCommon/react/renderer/core/ShadowNodeFamily.h +--- a/ReactCommon/react/renderer/core/ShadowNodeFamily.h ++++ b/ReactCommon/react/renderer/core/ShadowNodeFamily.h +@@ -8,6 +8,7 @@ + #pragma once + + #include ++#include + #include + + #include +@@ -116,6 +117,7 @@ + * architecture and will be removed in the future. + */ + mutable std::unique_ptr nativeProps_DEPRECATED; ++ mutable std::mutex nativePropsMutex; + + /** + * @return tag for the ShadowNodeFamily. +diff --git a/ReactCommon/react/renderer/uimanager/UIManager.cpp b/ReactCommon/react/renderer/uimanager/UIManager.cpp +--- a/ReactCommon/react/renderer/uimanager/UIManager.cpp ++++ b/ReactCommon/react/renderer/uimanager/UIManager.cpp +@@ -118,46 +118,48 @@ + auto props = ShadowNodeFragment::propsPlaceholder(); + + if (!rawProps.isEmpty()) { +- if (family.nativeProps_DEPRECATED != nullptr) { +- // 1. update the nativeProps_DEPRECATED props. +- // +- // In this step, we want the most recent value for the props +- // managed by setNativeProps. +- // Values in `rawProps` patch (take precedence over) +- // `nativeProps_DEPRECATED`. For example, if both +- // `nativeProps_DEPRECATED` and `rawProps` contain key 'A'. +- // Value from `rawProps` overrides what was previously in +- // `nativeProps_DEPRECATED`. Notice that the `nativeProps_DEPRECATED` +- // patch will not get more props from `rawProps`: if the key is not +- // present in `nativeProps_DEPRECATED`, it will not be added. +- // +- // The result of this operation is the new `nativeProps_DEPRECATED`. +- family.nativeProps_DEPRECATED = +- std::make_unique(mergeDynamicProps( +- *family.nativeProps_DEPRECATED, // source +- (folly::dynamic)rawProps, // patch +- NullValueStrategy::Ignore)); +- +- // 2. Compute the final set of props. +- // +- // This step takes the new props handled by `setNativeProps` and +- // merges them in the `rawProps` managed by React. +- // The new props handled by `nativeProps` now takes precedence +- // on the props handled by React, as we want to make sure that +- // all the props are applied to the component. +- // We use these finalProps as source of truth for the component. +- auto finalProps = mergeDynamicProps( +- (folly::dynamic)rawProps, // source +- *family.nativeProps_DEPRECATED, // patch +- NullValueStrategy::Override); +- +- // 3. Clone the props by using finalProps. +- props = componentDescriptor.cloneProps( +- propsParserContext, shadowNode.getProps(), RawProps(finalProps)); +- } else { +- props = componentDescriptor.cloneProps( +- propsParserContext, shadowNode.getProps(), std::move(rawProps)); ++ std::optional finalProps; ++ { ++ std::lock_guard lock(family.nativePropsMutex); ++ if (family.nativeProps_DEPRECATED != nullptr) { ++ // 1. update the nativeProps_DEPRECATED props. ++ // ++ // In this step, we want the most recent value for the props ++ // managed by setNativeProps. ++ // Values in `rawProps` patch (take precedence over) ++ // `nativeProps_DEPRECATED`. For example, if both ++ // `nativeProps_DEPRECATED` and `rawProps` contain key 'A'. ++ // Value from `rawProps` overrides what was previously in ++ // `nativeProps_DEPRECATED`. Notice that the `nativeProps_DEPRECATED` ++ // patch will not get more props from `rawProps`: if the key is not ++ // present in `nativeProps_DEPRECATED`, it will not be added. ++ // ++ // The result of this operation is the new `nativeProps_DEPRECATED`. ++ family.nativeProps_DEPRECATED = ++ std::make_unique(mergeDynamicProps( ++ *family.nativeProps_DEPRECATED, // source ++ (folly::dynamic)rawProps, // patch ++ NullValueStrategy::Ignore)); ++ ++ // 2. Compute the final set of props. ++ // ++ // This step takes the new props handled by `setNativeProps` and ++ // merges them in the `rawProps` managed by React. ++ // The new props handled by `nativeProps` now takes precedence ++ // on the props handled by React, as we want to make sure that ++ // all the props are applied to the component. ++ // We use these finalProps as source of truth for the component. ++ finalProps = mergeDynamicProps( ++ (folly::dynamic)rawProps, // source ++ *family.nativeProps_DEPRECATED, // patch ++ NullValueStrategy::Override); ++ } + } ++ ++ props = componentDescriptor.cloneProps( ++ propsParserContext, ++ shadowNode.getProps(), ++ finalProps ? RawProps(std::move(*finalProps)) : std::move(rawProps)); + } + + auto clonedShadowNode = componentDescriptor.cloneShadowNode( +@@ -426,19 +428,22 @@ + const std::shared_ptr& shadowNode, + RawProps rawProps) const { + auto& family = shadowNode->getFamily(); +- if (family.nativeProps_DEPRECATED) { +- // Values in `rawProps` patch (take precedence over) +- // `nativeProps_DEPRECATED`. For example, if both `nativeProps_DEPRECATED` +- // and `rawProps` contain key 'A'. Value from `rawProps` overrides what was +- // previously in `nativeProps_DEPRECATED`. +- family.nativeProps_DEPRECATED = +- std::make_unique(mergeDynamicProps( +- *family.nativeProps_DEPRECATED, +- (folly::dynamic)rawProps, +- NullValueStrategy::Override)); +- } else { +- family.nativeProps_DEPRECATED = +- std::make_unique((folly::dynamic)rawProps); ++ { ++ std::lock_guard lock(family.nativePropsMutex); ++ if (family.nativeProps_DEPRECATED) { ++ // Values in `rawProps` patch (take precedence over) ++ // `nativeProps_DEPRECATED`. For example, if both `nativeProps_DEPRECATED` ++ // and `rawProps` contain key 'A'. Value from `rawProps` overrides what was ++ // previously in `nativeProps_DEPRECATED`. ++ family.nativeProps_DEPRECATED = ++ std::make_unique(mergeDynamicProps( ++ *family.nativeProps_DEPRECATED, ++ (folly::dynamic)rawProps, ++ NullValueStrategy::Override)); ++ } else { ++ family.nativeProps_DEPRECATED = ++ std::make_unique((folly::dynamic)rawProps); ++ } + } + + shadowTreeRegistry_.visit( diff --git a/package.json b/package.json index b51946272f..9161dc747d 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "moment@npm:^2.24.0": "2.31.0", "moment@npm:^2.29.4": "2.31.0", "path-to-regexp@npm:8.3.0": "^8.4.2", - "react-native-macos": "patch:react-native-macos@npm%3A0.81.9#~/.yarn/patches/react-native-macos-npm-0.81.9-aa583a0648.patch", + "react-native-macos": "patch:react-native-macos@npm%3A0.81.9#~/.yarn/patches/react-native-macos-npm-0.81.9-aa583a0648.patch&~/.yarn/patches/react-native-macos-npm-0.81.9-native-props.patch", "react-native-windows": "0.81.35", "shell-quote": "1.11.0", "smol-toml@npm:^1.6.1": "1.9.0", diff --git a/packages/agentic/native-core/references/remaining-work.md b/packages/agentic/native-core/references/remaining-work.md index ad5a77fc60..6655c4bf1b 100644 --- a/packages/agentic/native-core/references/remaining-work.md +++ b/packages/agentic/native-core/references/remaining-work.md @@ -35,9 +35,12 @@ issue or pull request; compilation and skipped cases are not native qualificatio ## RNmacOS upstream replacement -- **Outcome:** consumers receive the macOS accessibility fixes without this repository's RNmacOS patch. +- **Outcome:** consumers receive the macOS accessibility and native-props synchronization fixes without this repository's RNmacOS patches. - **Current state:** the [repository-local patch](rnmacos-patch.md) is applied only to this repository's native hosts; publishing native-core or components does not install it in a consumer. - **Done when:** the fixes land upstream or in an equivalent consuming-renderer integration, and the same native cases pass against that replacement before the patch is removed. Checked-state actions, AX relationships, and VoiceOver speech remain separate, still-unqualified semantics. + The native-props synchronization already has an upstream implementation; remove + that backport only after the pinned RNmacOS fork includes it and the animated + window-resize regression passes against the replacement. diff --git a/packages/agentic/native-core/references/rnmacos-patch.md b/packages/agentic/native-core/references/rnmacos-patch.md index 15b8fd6485..246ea13e10 100644 --- a/packages/agentic/native-core/references/rnmacos-patch.md +++ b/packages/agentic/native-core/references/rnmacos-patch.md @@ -20,6 +20,50 @@ text on macOS. RNmacOS otherwise rejects them unconditionally because its iOS element provider is compiled out, which hides every Text label and `testID` from accessibility clients. +The root also applies +`.yarn/patches/react-native-macos-npm-0.81.9-native-props.patch`, a minimal +backport of MIT-licensed React Native code from +[upstream commit `923e7ddcaf4d` by OrfeasZ, #52646](https://github.com/facebook/react-native/commit/923e7ddcaf4d2de45ca7dedafbb84c6b87dbffc4). +The upstream copyright and license in the patched source files remain intact. +Fabric's window-resize layout can clone animated nodes on the main thread while +JavaScript replaces their `nativeProps_DEPRECATED` map. The backport guards +both writers and the cloning reader with one family-owned mutex, copying the +props before releasing the lock and parsing them afterward. This preserves +merge precedence without holding the mutex across shadow-tree commits. +Regenerate Pods and clean-build all native dependencies after changing this +patch: the family header's layout changes. + +The race was exposed while qualifying F16 defect 1's oversized-preview repair +for physical-click obstruction. Both complete Fabric lanes lost the app in +the unchanged PGB-006 NativeSemantics window-resize callback. A clean native +rebuild still failed, and an owned-process AddressSanitizer report recorded +`BUS` in `folly::dynamic::type()` while `ShadowNode::clone` copied the +unprotected native-props map during AppKit layout. This is a renderer +concurrency fix, not a click-through or driver retry workaround. PGB-006 runs +in the full Fabric physical lane as well as the accessible lane; the original +Checkbox, keyboard-clear, and Accordion reproductions passed without this +backport. Exact before/after qualification evidence is in the +[desktop-driver status ledger](../../desktop-driver/references/current-status.md). + +Recorded local evidence on November 12, 2026: + +- Before the backport, Fabric full physical run + `7bfe3fc7-bcbc-4275-ac5b-b457b66af7d7` and accessible run + `aebe42da-fcf5-4482-8eec-3e28401ea50c` failed PGB-006. Clean native + rebuild run `5314fc3d-da45-403e-b9bd-e187f0a9284c` still failed. + The owned-process report is + `artifacts/desktop/f16-macos-physical/fabric-progress-asan-report.86816`. +- After the backport, fresh Pods and a clean Fabric native build retained + AddressSanitizer and passed the same forced-resize callback **1/1**, run + `61d2dce4-5980-49b9-a727-412da47fca71`. Native Core's Apple module and + Office-style bridging-header probe passed **3/3**. The build, callback, + sanitizer linkage, and probe log is + `artifacts/desktop/f16-macos-physical/native-props-clean-build-green.log`. +- This native build evidence is for macOS Storybook. The macOS FluentTester + host and any other native application consuming the root resolution were + **not built** in this local check; the Apple probe is not an Office host + application build. + These fixes belong in RNmacOS, not in a MenuItem-specific native host or a JavaScript accessibility-value workaround. The patch is used by this repository's native hosts; publishing native-core or components does **not** install it in a diff --git a/yarn.lock b/yarn.lock index 6be5d02e4a..964a8c9d44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19597,9 +19597,9 @@ __metadata: languageName: node linkType: hard -"react-native-macos@patch:react-native-macos@npm%3A0.81.9#~/.yarn/patches/react-native-macos-npm-0.81.9-aa583a0648.patch": +"react-native-macos@patch:react-native-macos@npm%3A0.81.9#~/.yarn/patches/react-native-macos-npm-0.81.9-aa583a0648.patch&~/.yarn/patches/react-native-macos-npm-0.81.9-native-props.patch": version: 0.81.9 - resolution: "react-native-macos@patch:react-native-macos@npm%3A0.81.9#~/.yarn/patches/react-native-macos-npm-0.81.9-aa583a0648.patch::version=0.81.9&hash=fdc083" + resolution: "react-native-macos@patch:react-native-macos@npm%3A0.81.9#~/.yarn/patches/react-native-macos-npm-0.81.9-aa583a0648.patch&~/.yarn/patches/react-native-macos-npm-0.81.9-native-props.patch::version=0.81.9&hash=63578b" dependencies: "@jest/create-cache-key-function": "npm:^29.7.0" "@react-native-macos/virtualized-lists": "npm:0.81.9" @@ -19645,7 +19645,7 @@ __metadata: bin: react-native: cli.js react-native-macos: cli.js - checksum: 10c0/c4dd2eda84eea704dc205b31bb5ddbc6f58f26a23fa99f14d66ebf6b4637407a0ebb66096df4c34f8923910426a326e586184e2efa62e006257b984608d39f86 + checksum: 10c0/3d565e0d0a494b81519e5d86a8322aec279170317e7b5dc77ef1f3b8b786706cb342fc1626f5348bc3e3f67a501f46616b13c43f1f02842b21022f91597c8806 languageName: node linkType: hard From b0a27d46783d38954cf283f605fdb5cb0437d0d9 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Thu, 12 Nov 2026 17:32:05 +0000 Subject: [PATCH 2/3] Record standalone native-props backport qualification Document the observed failing reader, inferred concurrent writer, complete Fabric regression results, and immutable-install/fresh-native-build evidence for the independent lower branch. No E driver or runtime implementation is present in this layer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native-core/references/rnmacos-patch.md | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/agentic/native-core/references/rnmacos-patch.md b/packages/agentic/native-core/references/rnmacos-patch.md index 246ea13e10..6ef2c8c52a 100644 --- a/packages/agentic/native-core/references/rnmacos-patch.md +++ b/packages/agentic/native-core/references/rnmacos-patch.md @@ -20,13 +20,17 @@ text on macOS. RNmacOS otherwise rejects them unconditionally because its iOS element provider is compiled out, which hides every Text label and `testID` from accessibility clients. +## Native-props synchronization backport + The root also applies `.yarn/patches/react-native-macos-npm-0.81.9-native-props.patch`, a minimal backport of MIT-licensed React Native code from [upstream commit `923e7ddcaf4d` by OrfeasZ, #52646](https://github.com/facebook/react-native/commit/923e7ddcaf4d2de45ca7dedafbb84c6b87dbffc4). The upstream copyright and license in the patched source files remain intact. Fabric's window-resize layout can clone animated nodes on the main thread while -JavaScript replaces their `nativeProps_DEPRECATED` map. The backport guards +JavaScript replaces their `nativeProps_DEPRECATED` map. This concurrent-access +cause is inferred from the failing reader, the unguarded source, and the upstream +fix; no ThreadSanitizer run established the concurrent writer. The backport guards both writers and the cloning reader with one family-owned mutex, copying the props before releasing the lock and parsing them afterward. This preserves merge precedence without holding the mutex across shadow-tree commits. @@ -42,10 +46,13 @@ unprotected native-props map during AppKit layout. This is a renderer concurrency fix, not a click-through or driver retry workaround. PGB-006 runs in the full Fabric physical lane as well as the accessible lane; the original Checkbox, keyboard-clear, and Accordion reproductions passed without this -backport. Exact before/after qualification evidence is in the -[desktop-driver status ledger](../../desktop-driver/references/current-status.md). +backport. + +## Native-props regression ledger (2026-11-12 UTC) -Recorded local evidence on November 12, 2026: +The following before/after runs include E's separately owned driver and LiteUI +fixes. They isolate the renderer prerequisite but do not claim those fixes are +present in the standalone backport branch. - Before the backport, Fabric full physical run `7bfe3fc7-bcbc-4275-ac5b-b457b66af7d7` and accessible run @@ -59,11 +66,46 @@ Recorded local evidence on November 12, 2026: Office-style bridging-header probe passed **3/3**. The build, callback, sanitizer linkage, and probe log is `artifacts/desktop/f16-macos-physical/native-props-clean-build-green.log`. +- Both complete Fabric lanes then passed without retries or changed assertions: + physical **343 passed, 3 declared unsupported**, run + `3cb2f6af-69fd-44c1-8fb0-495607e37ca0`; accessible **260 passed, + 3 declared unsupported**, run `e8ef9d6a-e3a0-4164-b692-de319aaae545`. + Neither lane had failed, skipped, quarantined, incomplete, retried, or flaky + cases. The report is + `artifacts/desktop/f16-macos-physical/fabric-native-props-final-lanes-qualification.json`. - This native build evidence is for macOS Storybook. The macOS FluentTester host and any other native application consuming the root resolution were **not built** in this local check; the Apple probe is not an Office host application build. +### Standalone bottom-layer verification + +Branch `user/jasonvmo/rnmacos-native-props-backport` starts directly at +`origin/main` commit `505a2187b`, with the backport committed as `1eaa60a44`. +It does not contain E's driver, CI, or LiteUI implementation commits. +The following checks passed on that branch alone, in a fresh worktree: + +- `yarn install --immutable`: **passed**, without changing the manifest, + lockfile, or patches. +- `yarn build`: **passed**. +- From `apps/storybook`, `yarn storybook bundle --macos`, + `yarn storybook prep --macos`, and `yarn storybook build --macos`: + **passed**, with fresh Pods and DerivedData. The native build report is + `e9329920-eb03-4104-879e-b0c73af7820d`. AddressSanitizer remained linked; + the resulting native image SHA256 is + `0497580af4a37e99f2f092e3f9b716caa7d2936ecd5ff740e1d1ecd42251f35a`. +- `yarn workspace @fluentui-react-native/native-core test:apple-integration`: + **passed, 3/3** module/bridging-header checks. + +The shared native lock covered this batch. The machine-local Ruby environment +pinned the already-installed `json` gem to 2.18.0; no E product-source overlay +was applied. The captured command/results log is E's +`artifacts/desktop/f16-macos-physical/native-props-bottom-verify.log`. +This standalone check builds the Fabric Storybook host; it is not a claim +that the original input reproductions pass without E's driver/runtime fixes. + +## Scope and replacement + These fixes belong in RNmacOS, not in a MenuItem-specific native host or a JavaScript accessibility-value workaround. The patch is used by this repository's native hosts; publishing native-core or components does **not** install it in a From fb89e9d493205cfd51d1e2e45941584aaf622ec9 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Thu, 12 Nov 2026 18:35:28 +0000 Subject: [PATCH 3/3] docs(native-core): keep backport qualification durable Move session-only run details out of the published reference into ignored private PR evidence. Preserve upstream attribution, lock scope, renderer diagnosis, and the qualified native-host boundary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native-core/references/rnmacos-patch.md | 66 +++---------------- 1 file changed, 8 insertions(+), 58 deletions(-) diff --git a/packages/agentic/native-core/references/rnmacos-patch.md b/packages/agentic/native-core/references/rnmacos-patch.md index 6ef2c8c52a..ca5577ed3f 100644 --- a/packages/agentic/native-core/references/rnmacos-patch.md +++ b/packages/agentic/native-core/references/rnmacos-patch.md @@ -37,10 +37,9 @@ merge precedence without holding the mutex across shadow-tree commits. Regenerate Pods and clean-build all native dependencies after changing this patch: the family header's layout changes. -The race was exposed while qualifying F16 defect 1's oversized-preview repair -for physical-click obstruction. Both complete Fabric lanes lost the app in -the unchanged PGB-006 NativeSemantics window-resize callback. A clean native -rebuild still failed, and an owned-process AddressSanitizer report recorded +The race was exposed by the PGB-006 NativeSemantics window-resize callback +during Fabric Storybook qualification. A clean native rebuild still failed, +and an owned-process AddressSanitizer report recorded `BUS` in `folly::dynamic::type()` while `ShadowNode::clone` copied the unprotected native-props map during AppKit layout. This is a renderer concurrency fix, not a click-through or driver retry workaround. PGB-006 runs @@ -48,61 +47,12 @@ in the full Fabric physical lane as well as the accessible lane; the original Checkbox, keyboard-clear, and Accordion reproductions passed without this backport. -## Native-props regression ledger (2026-11-12 UTC) +### Qualification -The following before/after runs include E's separately owned driver and LiteUI -fixes. They isolate the renderer prerequisite but do not claim those fixes are -present in the standalone backport branch. - -- Before the backport, Fabric full physical run - `7bfe3fc7-bcbc-4275-ac5b-b457b66af7d7` and accessible run - `aebe42da-fcf5-4482-8eec-3e28401ea50c` failed PGB-006. Clean native - rebuild run `5314fc3d-da45-403e-b9bd-e187f0a9284c` still failed. - The owned-process report is - `artifacts/desktop/f16-macos-physical/fabric-progress-asan-report.86816`. -- After the backport, fresh Pods and a clean Fabric native build retained - AddressSanitizer and passed the same forced-resize callback **1/1**, run - `61d2dce4-5980-49b9-a727-412da47fca71`. Native Core's Apple module and - Office-style bridging-header probe passed **3/3**. The build, callback, - sanitizer linkage, and probe log is - `artifacts/desktop/f16-macos-physical/native-props-clean-build-green.log`. -- Both complete Fabric lanes then passed without retries or changed assertions: - physical **343 passed, 3 declared unsupported**, run - `3cb2f6af-69fd-44c1-8fb0-495607e37ca0`; accessible **260 passed, - 3 declared unsupported**, run `e8ef9d6a-e3a0-4164-b692-de319aaae545`. - Neither lane had failed, skipped, quarantined, incomplete, retried, or flaky - cases. The report is - `artifacts/desktop/f16-macos-physical/fabric-native-props-final-lanes-qualification.json`. -- This native build evidence is for macOS Storybook. The macOS FluentTester - host and any other native application consuming the root resolution were - **not built** in this local check; the Apple probe is not an Office host - application build. - -### Standalone bottom-layer verification - -Branch `user/jasonvmo/rnmacos-native-props-backport` starts directly at -`origin/main` commit `505a2187b`, with the backport committed as `1eaa60a44`. -It does not contain E's driver, CI, or LiteUI implementation commits. -The following checks passed on that branch alone, in a fresh worktree: - -- `yarn install --immutable`: **passed**, without changing the manifest, - lockfile, or patches. -- `yarn build`: **passed**. -- From `apps/storybook`, `yarn storybook bundle --macos`, - `yarn storybook prep --macos`, and `yarn storybook build --macos`: - **passed**, with fresh Pods and DerivedData. The native build report is - `e9329920-eb03-4104-879e-b0c73af7820d`. AddressSanitizer remained linked; - the resulting native image SHA256 is - `0497580af4a37e99f2f092e3f9b716caa7d2936ecd5ff740e1d1ecd42251f35a`. -- `yarn workspace @fluentui-react-native/native-core test:apple-integration`: - **passed, 3/3** module/bridging-header checks. - -The shared native lock covered this batch. The machine-local Ruby environment -pinned the already-installed `json` gem to 2.18.0; no E product-source overlay -was applied. The captured command/results log is E's -`artifacts/desktop/f16-macos-physical/native-props-bottom-verify.log`. -This standalone check builds the Fabric Storybook host; it is not a claim -that the original input reproductions pass without E's driver/runtime fixes. +A clean Pods and Fabric Storybook native build with AddressSanitizer passed, +as did the PGB-006 resize callback and Native Core's CocoaPods-module and +Office-style bridging-header probes. This qualifies the Storybook host only: +macOS FluentTester and other native application hosts were not built locally. ## Scope and replacement