address architecture review findings and add review document

Fixes from architecture review (4 critical, 10 warnings):

Critical:
- Fix selectNode/setNode docs to accurately describe prop-key
  navigation behavior including array support and prop-key writes
- Document RenderContext/Density exported types in host-config
- Resolve ADR dual status ambiguity with clarifying note in README
  (frontmatter status = editorial, body Status = decision)
- Effect types already addressed in prior commit

Warnings addressed:
- Add Fragment re-export note to jsx-runtime section in
  build-distribution
- Document childCtx/transformCtx helper functions in transforms.md
- Document render() accepting non-root UNode in host-config
- Add Value.Hash re-entrancy constraint to reconciler.md
- Add true-passthrough constraint and h('root') special case
  to element-factory constraints
- Add _idCounter bundling caveat note

Review document added at docs/reviews/architecture-review-2026-05-18.md
with full findings, source verification table, and recommendations.
This commit is contained in:
2026-05-18 15:36:38 +00:00
parent da82b52b27
commit 23659233ca
8 changed files with 322 additions and 7 deletions

View File

@@ -64,17 +64,32 @@ Each segment is processed sequentially against the current node:
| Segment | Resolution | Example |
|---------|-----------|---------|
| Numeric (e.g., `"0"`, `"3"`) | `children[index]` on the current `UElement` | Path `["0", "2"]` → root.children[0].children[2] |
| Non-numeric (e.g., `"title"`) | `props[segment]` on the current `UElement`, if the prop value is an object | Path `["props", "title"]` → root.props.title (if title is an object node) |
| Non-numeric (e.g., `"title"`, `"items"`) | `props[segment]` on the current `UElement` if the prop value is a non-null object (including arrays), navigation continues into that value; otherwise returns `undefined` | Path `["items"]` → root.props.items (if items is an object or array) |
A segment that parses as a valid non-negative integer is treated as a children index. Otherwise, it is treated as a prop key. This is a simplified version of RFC 6901 JSON Pointer — no special escaping, no `~` encoding, no `/` separators. Simplicity over generality.
A segment that parses as a valid non-negative integer is treated as a children index. Otherwise, it is treated as a prop key. If the prop value exists and is a non-null object (which includes arrays, since `typeof [] === "object"`), `selectNode` navigates into it. If the prop value is a primitive (string, number, boolean, null) or absent, `selectNode` returns `undefined`.
This is a simplified version of RFC 6901 JSON Pointer — no special escaping, no `~` encoding, no `/` separators. Simplicity over generality.
### Early termination
If the current node is not a `UElement` (i.e., it's a `UPrimitive` — a string, number, boolean, or null), `selectNode` returns `undefined` because primitives have no children or props. This prevents runtime errors from navigating into leaf values.
### Non-element props
### Non-element and array props
When a string segment resolves to a prop value that is not an object (e.g., `props.title` is a string), `selectNode` returns `undefined`. Only object-typed prop values can be navigation targets. This is because `UPrimitive` values (strings, numbers) are terminal — they have no children to navigate into. A prop that holds a `UNode` subtree is an object and can be navigated; a prop that holds a string is a leaf.
When a string segment resolves to a prop value that is a primitive (string, number, boolean, null), `selectNode` returns `undefined`. Only non-null object prop values — including arrays, since `typeof [] === "object"` — can be navigation targets. This means `props.items` where `items` is an array can be navigated into, but `props.title` where `title` is a string cannot.
`setNode` mirrors this behavior for writes: a non-numeric string segment sets `props[segment] = value`, performing a shallow merge of that key into the element's props. This allows targeted prop updates via path-based navigation.
### setNode prop-key writes
Non-numeric path segments in `setNode` set values into the `props` object:
```typescript
setNode(root, ["title"], someNode)
// Produces: { ...rootEl, props: { ...rootEl.props, title: someNode } }
```
This shallow-merges a key into `props`. The `value` must be a valid `PropValue` (or `UNode`) for the result to remain type-safe.
## setNode