@kudzujs/core 0.7.6 → 0.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/GOAL_A.md CHANGED
@@ -1,187 +1,116 @@
1
- # Goal A: Static Business Applications
1
+ # Goal A: Static Application Lifecycles And Opt-In Navigation
2
2
 
3
- Goal A makes Kudzu sufficient for a conventional business application, starting with a complete commerce journey and leaving a clean path to realtime dashboards. It must preserve Kudzu's static HTML, zero-JavaScript static routes, direct DOM updates, and lack of a browser component tree.
3
+ Goal A is a completed compiler-capability milestone for general React-to-static migration. It proves that ordinary React-shaped applications can retain shared layouts, route lifetimes, asynchronous workflows, and optional same-document navigation while every route remains a complete static document.
4
4
 
5
- This is the implementation contract. `MIGRATION_ROADMAP.md` remains the source of truth for compiler invariants and the fixture-first workflow.
5
+ The six-route commerce journey is one executable validation fixture. It is not Kudzu's product scope, a commerce API, or the priority model for future development. [`MIGRATION_ROADMAP.md`](./MIGRATION_ROADMAP.md) is the source of truth for product direction and future fixture-driven work.
6
6
 
7
- The benchmark runner, framework fixtures, generated artifacts, and raw arrays are retained as local validation material and are intentionally excluded from the repository and npm package. Published numbers below are a dated product record rather than a reproducible public benchmark bundle. The matched versions were Kudzu 0.5.10, React 19.2.8 with Vite, Next.js 16.2.11, Nuxt 4.5.0 with Vue 3.5.40, and SvelteKit 2.70.1 with Svelte 5.56.7.
7
+ ## Status
8
8
 
9
- ## Implementation Status
9
+ Goal A is complete for explicitly configured emitted-route groups with shared layouts. Implemented capabilities include:
10
10
 
11
- **Goal A is complete for one explicitly configured emitted-route group with one shared layout.** Complete standalone documents, exact and runtime-parameter navigation, native fallback, persistent layout state/effects, disposable route state/effects, optimistic workflows, desktop/mobile performance gates, and the dashboard expansion seam are covered. Multiple independent shared-layout groups and conditional/keyed DOM-owned effects within layout and route lifetimes were added post-Goal-A.
11
+ - complete standalone documents for exact and runtime-parameter routes;
12
+ - native navigation fallback and opt-in same-document navigation;
13
+ - persistent layout state and effects with disposable route state and effects;
14
+ - conditional and keyed DOM ownership within layout and route lifetimes;
15
+ - validated finite prefetch caching for eligible links;
16
+ - optimistic success, rejection, rollback, and stale-write suppression;
17
+ - multiple independent shared-layout groups with overlap diagnostics.
12
18
 
13
- - **Phase 1 complete**: a local six-route commerce fixture, locked React/Next/Nuxt/SvelteKit comparisons, and a reproducible artifact/build/Chrome runner validate the implementation.
14
- - **Phase 2 complete**: effects inside conditional ranges and supported keyed row components mount with their DOM owner, unsubscribe and clean up on removal, and remount without affecting effect-free output.
15
- - **Phase 3 complete**: page-exported layouts render complete documents with compiler-owned route boundaries, collision-free layout/route IDs, and state/effect ownership metadata. Effects remain document effects and client navigation is unchanged.
16
- - **Phase 4 route/layout effects implemented**: layout effects mount once per document session, route effects remount after awaited route cleanup, and primitive dependency subscriptions exist only while their lifetime is mounted. Conditional/keyed effects use per-lifetime owner registries; route registries are fresh on cached revisits. Direct primitive keyed-item properties rerun only changed rows; reorder does not rerun and key changes remount. Disposed effect setters and queued commits are inactive.
17
- - **Phase 4 document prefetch implemented**: visible, near-visible, hovered, or focused eligible group anchors prefetch and validate complete documents without importing target capabilities. The finite in-memory full-URL cache removes the measured product-cart HTML RTT while preserving retry and native fallback.
18
- - **Phase 5 complete**: matched async cart success/rejection flows prove immediate optimistic updates, duplicate prevention, accessible errors, rollback, route-local reset, and stale-write suppression without new framework APIs.
19
- - **Phase 6 expansion probe complete**: one layout-owned mock `EventTarget` stream and one route-owned imperative chart stub use existing effects and a relative TypeScript helper across repeated navigation, with exact listener and disposal assertions. This proves only the compatibility seam; Kudzu does not provide telemetry or chart support.
20
- - **Desktop and mobile gates complete**: both profiles use seven rotating fresh Chrome runs per target and record zero cold/warm CLS.
19
+ Future migration features do not extend Goal A as a product vertical. They return to the migration roadmap and begin with a failing conventional React fixture.
21
20
 
22
- The capability-local prefetch/cache increased the commerce navigation asset from 1,887 B to 2,306 B gzip (+419 B). Routes outside the configured group remain unchanged.
21
+ ## Capability Contract
23
22
 
24
- In the focused effect-enabled navigation fixture, mount support adds 171 B gzip to the same-route navigation asset and 37 B gzip to the shared runtime. The active-context guard adds 18 B gzip to `kudzu-effect.js` (257 B total); cache-safe route entries are 1,059-1,116 B gzip. The effect-free commerce specialization remains byte-for-byte unchanged.
25
-
26
- The post-Goal-A runtime-pattern matcher increases the exact-only commerce navigation asset from 2,306 B to 2,461 B gzip. The mixed exact/runtime navigation fixture emits a 3,105 B gzip navigation asset and a 703 B gzip cache-safe parameter initializer.
27
-
28
- The post-Goal-A multiple-group fixture emits a 7,448 B raw / 3,099 B gzip (`gzip -9`) mixed runtime/effect group asset, including one native exclusion for an overlapping ungrouped exact route, and a separately specialized 5,681 B raw / 2,448 B gzip exact effect-free group asset. These measurements do not revise the historical Goal A benchmark.
29
-
30
- In a matched one-effect navigation build with the same conditional capability, moving the effect from the route body into the conditional owner changes the route effect entry from 2,181 B raw / 1,036 B gzip to 4,135 B raw / 1,807 B gzip (`+1,954 B` raw / `+771 B` gzip). Owner-hook unsubscription changes the shared runtime from 1,347 B raw / 718 B gzip to 1,459 B raw / 732 B gzip (`+112 B` raw / `+14 B` gzip). Top-level-only and effect-free navigation builds retain their smaller generators.
31
-
32
- In matched state-only and item-property keyed-row builds, targeted notification adds 821 B raw / 255 B gzip across the route effect entry, shared runtime, and list runtime. Builds without item-property dependencies retain their previous generated path.
33
-
34
- In the latest matched 1,000-row keyed-effect runtime microbenchmark, Kudzu measured 3.6 ms selected-row cleanup/update/setup, 2.4 ms unrelated-field update, and 8.8 ms reorder after all rows and effects were ready. React CSR measured 9.8, 5.9, and 16.8 ms; Vue measured 5.8, 2.4, and 10.5 ms; and Svelte measured 5.7, 4.1, and 58.1 ms. Targeted changed-root notification avoids an extra O(n) effect-record scan; list reconciliation remains O(n). Kudzu emits initial rows while these framework fixtures are CSR, so their JavaScript, output, and build observations are not architecture-equivalent claims.
35
-
36
- A 0.6.4 release-tree desktop rerun of the matched six-route commerce fixture measured Kudzu at 486.8 ms build, 35,355 deploy bytes, 7,334 B gzip product JavaScript, 332/156 ms cold/warm LCP, 122.6 ms startup task, 4.8 ms interaction, and 5.6 ms product-cart navigation. React measured 545.4 ms build, 61,464 B gzip product JavaScript, 332/264 ms LCP, 179.9 ms startup task, 10.2 ms interaction, and 9.9 ms navigation. Kudzu built 10.7% faster and its top-level-only fixture retained byte-identical deploy, product-graph, and navigation-asset sizes after navigation-owned effects were added. Raw arrays and the consolidated report are retained under the local demo benchmark workspace.
37
-
38
- The Phase 6 chart probe's complete initial module graph is 11,902 B raw / 5,331 B gzip. It adds no framework API or package and does not change the commerce benchmark fixture.
39
-
40
- The app-mode Kudzu fixture emits 34,879 deploy bytes. Its product route loads 15,800 raw / 7,215 gzip bytes of initial JavaScript, including the 2,306 B gzip navigation capability. Routes outside a configured application group retain the static zero-JavaScript and byte-for-byte gates.
41
-
42
- The latest matched run used seven rotating production builds and seven rotating fresh Chrome profiles per target at 4x CPU slowdown, 100 ms latency, and 200 KiB/s download. Raw local results retain the full arrays, artifact groups, environment, and limitations.
43
-
44
- | Target | Product JS gzip | Cold transfer | Cold LCP | Warm LCP | Cold task | Cold heap | Interaction | Product-cart |
45
- |---|---:|---:|---:|---:|---:|---:|---:|---:|
46
- | Kudzu | 7,215 B | 34,809 B | 324 ms | 140 ms | 103.3 ms | 648,844 B | 3.7 ms | 5.7 ms |
47
- | React + Vite | 61,464 B | 202,842 B | 324 ms | 232 ms | 160.0 ms | 1,062,520 B | 10.5 ms | 8.3 ms |
48
- | Next.js | 190,090 B | 546,581 B | 316 ms | 156 ms | 357.7 ms | 2,157,020 B | 11.4 ms | 26.9 ms |
49
- | Nuxt | 67,620 B | 195,953 B | 320 ms | 204 ms | 205.1 ms | 1,721,348 B | 3.9 ms | 33.0 ms |
50
- | SvelteKit | 32,473 B | 90,929 B | 340 ms | 172 ms | 125.8 ms | 999,496 B | 4.7 ms | 20.3 ms |
51
-
52
- The navigation capability initially measured 128.7 ms because it paid one HTML round trip. Validated near-viewport document prefetch reduced the final seven-run median to 5.7 ms while Kudzu still transferred 62% less than SvelteKit and 83% less than React on the cold product load. A progressive-HTML grid shift found by the benchmark was fixed in the matched CSS; 30 focused Kudzu profiles and the final desktop/mobile cross-framework runs then recorded zero cold and warm CLS.
53
-
54
- The original final table measured 460.8 ms for Kudzu and 429.5 ms for React, and a focused follow-up confirmed a 6-7% loss primarily from TypeScript ESM/compiler startup. A post-gate startup fix now enables Node's native module compile cache before lazily loading the compiler. The first empty-cache build measured 541.4 ms against the previous 547.6 ms path; after one warm-up, 31 interleaved artifact-clean builds measured Kudzu at 425.8 ms and React at 483.4 ms, making Kudzu 11.9% faster in that run. Cache-disabled and cached builds emit byte-for-byte identical output.
55
-
56
- The mobile profile uses a 390x844 viewport, 6x CPU slowdown, 150 ms latency, and 150 KiB/s download. Kudzu measured 420 ms cold LCP, 220 ms warm LCP, 5.6 ms interaction, 8.7 ms product-cart navigation, 4.1 ms optimistic rejection, and 158 ms rollback/error.
57
-
58
- ## Product Target
59
-
60
- A user can build and deploy this flow without React, a VDOM, hydration, or a request server:
23
+ A migrated application may use familiar function components, props, children, JSX, hooks, conditions, collections, and handlers while Kudzu emits:
61
24
 
62
25
  ```text
63
- home -> category -> product -> cart -> checkout -> account
26
+ complete static document
27
+ -> optional persistent layout range
28
+ -> replaceable route range
29
+ -> only the route-specific ESM capabilities used
64
30
  ```
65
31
 
66
- The reference fixture must cover:
32
+ The capability must preserve:
67
33
 
68
- - complete indexable HTML for public pages;
34
+ - complete indexable HTML for every route;
69
35
  - direct entry, reload, back, forward, query strings, and base paths;
70
- - product filters stored in the URL;
71
- - product variants and quantity as route state;
72
- - cart and session information shared by an application layout;
73
- - async loading, empty, error, retry, and cancellation behavior;
74
- - optimistic cart updates with rollback after a rejected request;
75
- - accessible focus, title, scroll, and announcement behavior after navigation;
36
+ - URL, route, and shared-layout state with explicit lifetimes;
37
+ - async loading, empty, error, retry, cancellation, and stale-result handling;
38
+ - optimistic updates, rejection, rollback, and accessible status output;
39
+ - focus, title, scroll, and announcement behavior after enhanced navigation;
76
40
  - ordinary document navigation when JavaScript is absent, late, or fails.
77
41
 
78
- The fixture is a generic executable requirement, not a reusable commerce package. Kudzu should add only compiler features that the reduced fixture proves necessary.
42
+ ## Invariants
79
43
 
80
- ## Runtime Model
44
+ - Native `<a>` navigation is the default.
45
+ - Navigation enhancement is explicit per emitted route group.
46
+ - Every enhanced route also exists as a complete document.
47
+ - Static routes emit zero client JavaScript.
48
+ - Interactive routes emit only the capabilities they use.
49
+ - React, a VDOM, hydration, retained browser components, and browser component rerenders remain forbidden.
50
+ - External, download, modified-click, reload, malformed, unsupported, and ungrouped links keep native behavior.
51
+ - A failed or superseded transition cannot commit stale route state.
52
+ - No separate fragment protocol, router API, cache, or scheduler is added without a measured fixture requirement.
81
53
 
82
- Kudzu continues to emit a complete document for every route. Native `<a>` navigation remains the default. An explicitly configured application route group may enhance eligible same-origin links after the initial document has loaded.
54
+ ## Ownership Model
83
55
 
84
- ```text
85
- Static document
86
- -> optional persistent layout
87
- -> replaceable route range
88
- -> capability-specific route ESM
89
- ```
90
-
91
- The implementation must use the smallest measured mechanism. A separate fragment format, prefetcher, cache, or router API is not required unless the fixture and browser measurements show that parsing the existing document output is insufficient.
92
-
93
- Navigation enhancement must not become a general SPA runtime:
56
+ Goal A adds explicit ownership, not a state library or application runtime.
94
57
 
95
- - no VDOM, hydration, retained component tree, or component rerenderer;
96
- - no global router on routes outside an opted-in application group;
97
- - no interception of external, download, modified-click, reload, or explicitly native links;
98
- - no client-only route as the sole representation of indexable content;
99
- - no duplicated source component execution in the browser.
100
-
101
- ## Ownership And Cleanup
102
-
103
- Goal A needs explicit ownership, not a new state library:
104
-
105
- | Owner | Lifetime | Examples |
58
+ | Owner | Lifetime | General examples |
106
59
  |---|---|---|
107
- | Document | Full document | global listeners and document exit cleanup |
108
- | Layout | Enhanced navigation session | user summary, cart count, persistent connection |
109
- | Route | Current route range | filters, selected variant, request, subscription |
110
- | DOM range | Conditional or keyed item | listener, effect, imperative child resource |
111
-
112
- Removing an owner must dispose its effects, listeners, pending work, and descendant registrations exactly once. A failed or superseded navigation must not commit stale route state. Full document navigation remains the recovery path.
60
+ | Document | Full document | global listeners and document-exit cleanup |
61
+ | Layout | Enhanced navigation session | user summary, navigation state, shared resource |
62
+ | Route | Current route range | filters, requests, subscriptions, pending work |
63
+ | DOM range | Conditional or keyed item | listener, effect, ref, imperative child resource |
113
64
 
114
- High-frequency data is deliberately not a Goal A state feature. A later dashboard can keep WebSocket parsing, telemetry buffers, charts, maps, and editors in Workers or imperative browser modules while Kudzu owns their route or layout lifecycle.
65
+ Removing an owner disposes its effects, listeners, pending work, and descendant registrations exactly once. A non-persisted document exit cleans route ownership before layout ownership. A BFCache-persisted document retains live ownership for restoration.
115
66
 
116
- ## Delivery Order
67
+ ## Validation Fixture
117
68
 
118
- Each phase starts with one failing fixture and ends with correctness, browser, size, and build measurements.
69
+ The reduced commerce journey remains a useful integration fixture because it exercises the neutral capability contract in one flow:
119
70
 
120
- 1. **Benchmark harness**: freeze the commerce journey, network profiles, framework versions, generated artifacts, and measurement scripts before optimizing Kudzu.
121
- 2. **Owned effects**: complete cleanup for conditional ranges and keyed items using the existing mount and unmount hooks. **Complete.**
122
- 3. **Layout and route scopes**: retain only declared layout state and dispose route-owned behavior on every completed transition. **Compiler ownership complete; transition behavior belongs to Phase 4.**
123
- 4. **Opt-in navigation**: support eligible links, history, aborts, stale responses, focus, scroll, metadata, and native fallback. **Complete for emitted exact/runtime-parameter routes and layout/route effects, including conditional/keyed DOM ownership.**
124
- 5. **Business workflows**: close only fixture-proven gaps in forms, async requests, optimistic updates, and diagnostics. **Complete for the matched cart success/rejection flow.**
125
- 6. **Expansion probe**: prove that one persistent mock stream and one imperative chart stub can mount, update, navigate, and dispose without adding a component runtime. **Compatibility probe complete; real telemetry and chart engines remain outside Goal A.**
126
-
127
- Do not begin a later phase while the current phase has an unexplained correctness or performance regression.
71
+ ```text
72
+ home -> category -> product -> cart -> checkout -> account
73
+ ```
128
74
 
129
- ## Performance Comparison
75
+ Its product filters prove URL state, variants prove route state, cart/session data proves layout state, rejected updates prove rollback, and product-to-cart transitions prove enhanced navigation. These nouns belong to the fixture only; Kudzu must not add commerce-specific APIs or architecture.
130
76
 
131
- The matched comparison set is:
77
+ Other applications should validate the same capabilities with domain-appropriate fixtures such as documentation, content, administration, forms, and dashboards.
132
78
 
133
- - Kudzu from the previous completed phase;
134
- - React with an equivalent production static deployment;
135
- - Next.js static export;
136
- - Vue/Nuxt static generation;
137
- - Svelte/SvelteKit static generation;
138
- - hand-written HTML and DOM JavaScript where it provides a useful lower bound.
79
+ ## Performance Protocol
139
80
 
140
- Every implementation must render the same initial content and provide the same tested behavior. Results that omit initial HTML, navigation semantics, error handling, or accessibility are reported separately and cannot be presented as direct wins.
81
+ Matched comparisons may include React/Vite, static exports from established frameworks, and hand-written HTML/DOM code as a lower bound. Every target must provide the same initial content, behavior, errors, navigation semantics, and accessibility before results are compared directly.
141
82
 
142
- Use identical content, CSS, local images, API payloads, cache state, browser version, CPU profile, and network profile. Record at least:
83
+ Record at least:
143
84
 
144
- - deploy artifact bytes and initial raw/gzip JavaScript;
145
- - HTML, CSS, image, and route payload transfer bytes;
85
+ - deploy bytes and initial raw/gzip JavaScript;
86
+ - HTML, CSS, media, and route transfer bytes;
146
87
  - clean build median;
147
- - cold and warm LCP, CLS, and INP;
148
- - hydration or startup main-thread work;
149
- - cold and warm route transition time;
150
- - cart update and rollback latency;
151
- - browser heap after initial load and repeated navigation;
152
- - duplicate listeners, unfinished requests, and lifecycle leaks.
153
-
154
- Production builds receive one warm-up and at least seven interleaved runs. Keep raw results and record the median; use additional runs when ranges overlap or a result controls an architectural decision.
155
-
156
- ## Performance Gates
157
-
158
- Goal A is not complete unless:
159
-
160
- - static routes still emit zero JavaScript;
161
- - routes outside an application group remain byte-for-byte unaffected by navigation support;
162
- - an application route ships only the layout and route capabilities it uses;
163
- - no hydration task or browser component tree is introduced;
164
- - repeated navigation leaves no growing listener, request, state, DOM, or heap ownership;
165
- - Kudzu has no unexplained material regression against its previous phase;
166
- - material losses against the fastest matched framework are profiled and either fixed or documented as an explicit product tradeoff;
167
- - performance claims include fixture limitations and do not compare unequal initial content as equivalent.
88
+ - cold and warm LCP, CLS, INP, startup work, and heap;
89
+ - state update, optimistic rejection, rollback, and route transition latency;
90
+ - repeated-navigation listener, request, state, DOM, and heap ownership.
168
91
 
169
- For browser timings, treat a repeatable median change above 5% as material. Deterministic byte growth is reviewed regardless of percentage. Measurement noise is not a reason to optimize: repeat the interleaved run first.
92
+ Production builds receive one warm-up and at least seven interleaved runs. Browser comparisons use rotating fresh profiles and additional runs when ranges overlap. A repeatable browser median change above 5% is material; deterministic byte growth is always reviewed.
170
93
 
171
- When a gate fails, stop feature work, reduce the cause, fix the shared path, rerun `npm run check`, `npm test`, and the affected benchmark, then continue. Do not hide regressions with prefetching, omitted content, or a weaker competitor fixture.
94
+ ## Regression Gates
172
95
 
173
- ## Completion Definition
96
+ - Static routes still emit zero JavaScript.
97
+ - Routes outside configured groups remain unaffected by navigation support.
98
+ - No hydration task or retained component tree is introduced.
99
+ - Repeated navigation leaves no growing ownership.
100
+ - Material regressions against Kudzu's previous path are explained and fixed or recorded as explicit tradeoffs.
101
+ - Competitor comparisons disclose unequal rendering architecture and fixture limitations.
102
+ - `npm run check`, `npm test`, and applicable browser checks pass.
174
103
 
175
- Goal A is complete when the commerce fixture passes direct-load and enhanced-navigation browser tests, every lifecycle owner cleans up correctly, static fallback behavior remains intact, and the benchmark gates above pass on both desktop and mobile profiles.
104
+ ## Historical Validation Record
176
105
 
177
- The final validation record must retain the generated artifacts, framework versions, commands, raw measurements, medians, known losses, and deliberate limits.
106
+ The completed commerce and lifecycle measurements remain dated evidence, not current product requirements. The latest retained records include complete desktop/mobile navigation runs, zero cold/warm CLS, exact cleanup counters, capability byte deltas, and matched framework comparisons. Release notes and repository history retain version-specific numbers; new measurements must record their source revision, fixture, browser, hardware, raw arrays, and limitations.
178
107
 
179
108
  ## Non-Goals
180
109
 
181
110
  - A default SPA router.
182
- - Arbitrary React application or package compatibility.
183
- - Runtime component registration or client component rendering.
184
- - Request-time SSR, server actions, or a hidden server.
185
- - A charting, mapping, telemetry, virtual-grid, or visual-editor engine.
186
- - A custom widget marketplace or plugin security model.
187
- - Winning every synthetic metric at the cost of correctness, accessibility, or deploy output.
111
+ - A commerce framework or reusable commerce package.
112
+ - Arbitrary React package compatibility.
113
+ - Runtime component registration, hydration, or client component rendering.
114
+ - Request-time SSR, server actions, or a hidden application server.
115
+ - Charting, mapping, telemetry, virtual-grid, or editor engines.
116
+ - Winning synthetic metrics by omitting equivalent content, behavior, accessibility, or fallback.
package/GOAL_B.md CHANGED
@@ -1,44 +1,28 @@
1
- # Goal B: Static Realtime Dashboards
1
+ # Goal B: Relative TypeScript Worker Capability Proof
2
2
 
3
- Goal B makes Kudzu sufficient for a ThingsBoard-shaped realtime device dashboard without turning Kudzu into a stream runtime, widget framework, or server platform. It preserves complete static documents, zero-JavaScript routes that use no browser capabilities, direct DOM ownership, native navigation fallback, and the absence of React, a VDOM, hydration, or a retained browser component tree.
3
+ Goal B is a completed cross-application compiler-capability proof for one browser-only pattern used by realtime React-shaped applications: a route-owned relative TypeScript module Worker created and cleaned up from an inline `useEffect`.
4
4
 
5
- `MIGRATION_ROADMAP.md` remains the source of truth for compiler invariants and fixture-first development. This document is the implementation contract for realtime dashboard work.
5
+ The realtime dashboard is a stress and conformance fixture. It is not a Kudzu product vertical, dashboard API, stream runtime, widget framework, server platform, or claim of ThingsBoard compatibility. [`MIGRATION_ROADMAP.md`](./MIGRATION_ROADMAP.md) remains the source of truth for future fixture-driven migration work.
6
6
 
7
- ## Product Target
7
+ ## Status
8
8
 
9
- A user can statically deploy this flow:
9
+ The exact relative TypeScript Worker capability is implemented and verified. Kudzu recognizes one statically analyzable constructor form, emits its validated module graph separately, rewrites the URL for the configured base, ties creation and termination to effect ownership, and adds no Worker bytes to routes that do not use it.
10
10
 
11
- ```text
12
- dashboard -> devices -> device detail -> alarms -> settings
13
- ```
11
+ Further Worker, transport, effect, or React compatibility work must begin with a reduced conventional React migration fixture that fails.
14
12
 
15
- The first vertical slice is deliberately smaller:
13
+ ## Capability Target
16
14
 
17
- ```text
18
- plain route <-> realtime device dashboard
19
- ```
20
-
21
- The dashboard receives a logical 1,000 telemetry samples per second, keeps a bounded history in a module Worker, downsamples it, and updates one imperative chart without routing samples through `useState()`.
22
-
23
- ## Runtime Model
15
+ The focused proof uses one Worker-enabled route, one plain companion route, and one unrelated static route:
24
16
 
25
17
  ```text
26
- Complete static dashboard shell
27
- -> route-specific effect ESM
28
- -> route-owned module Worker
29
- -> bounded telemetry buffer and downsampling
30
- -> batched imperative chart updates
18
+ plain route <-> Worker-enabled route
31
19
  ```
32
20
 
33
- Kudzu state is for low-frequency UI state such as selected device, time range, filters, tabs, connection status, alarm status, and widget configuration. High-frequency samples belong in a Worker or imperative browser module.
34
-
35
- The Worker is a capability, not a framework runtime. Routes that do not create one must not load its graph. Static routes must remain JavaScript-free.
21
+ The stress fixture generates a logical 1,000 samples per second, keeps bounded history in a module Worker, downsamples it, and updates one imperative chart. Telemetry and chart details validate Worker isolation, throughput, and ownership; they are not Kudzu product features or advice to rewrite ordinary declarative UI imperatively.
36
22
 
37
- ## Milestone 1: Relative TypeScript Workers
23
+ ## Supported Form
38
24
 
39
- Status: implemented and verified. The compiler recognizes only the exact inline-effect form below, emits its validated graph separately, rewrites the constructor to the base-aware same-origin asset, and leaves routes without this capability on their existing output paths.
40
-
41
- Support this exact shape inside a compiled inline `useEffect` callback:
25
+ The Worker must be constructed directly inside a compiled inline effect:
42
26
 
43
27
  ```tsx
44
28
  useEffect(() => {
@@ -47,13 +31,13 @@ useEffect(() => {
47
31
  { type: "module" },
48
32
  )
49
33
 
50
- const onMessage = (event: MessageEvent<ChartFrame>) => chart.render(event.data)
34
+ const onMessage = (event: MessageEvent<Frame>) => resource.render(event.data)
51
35
  worker.addEventListener("message", onMessage)
52
36
 
53
37
  return () => {
54
38
  worker.removeEventListener("message", onMessage)
55
39
  worker.terminate()
56
- chart.dispose()
40
+ resource.dispose()
57
41
  }
58
42
  }, [])
59
43
  ```
@@ -63,87 +47,67 @@ Compiler requirements:
63
47
  - accept only an unshadowed `Worker` with `new URL(relativeLiteral, import.meta.url)` and literal `{ type: "module" }`;
64
48
  - resolve one `.worker.ts` entry under project source and bundle its relative TypeScript graph separately from window code;
65
49
  - emit deterministic content-hashed ESM under `assets/workers` and rewrite the constructor to the base-aware emitted URL;
66
- - reject package imports, JSX, TypeScript import-equals declarations, dynamic imports, `require()`, paths outside source, malformed options, and unsupported Worker forms with source locations;
50
+ - reject package imports, JSX, import-equals declarations, dynamic imports, `require()`, paths outside source, malformed options, and unsupported Worker forms with source locations;
67
51
  - reject ordinary runtime imports or re-exports of `.worker.ts`; type-only imports may erase normally;
68
- - do not mark Worker files as navigation capability scripts or import them into the window;
69
- - create the Worker only when the owning effect mounts;
70
- - preserve byte-for-byte generated shared/list/effect paths for builds without relative TypeScript Workers where practical;
71
- - reject generated/public asset collisions instead of silently overwriting output.
52
+ - never mark Worker files as document capability scripts or import them into the window;
53
+ - create the Worker only when its owning effect mounts;
54
+ - preserve zero-cost exclusion for builds without relative TypeScript Workers;
55
+ - reject generated/public asset collisions.
72
56
 
73
- Worker construction inside imported helpers or imported keyed-row effects, `SharedWorker`, classic workers, inline Blob workers, and arbitrary dynamic Worker URLs are outside Milestone 1. Imported keyed rows must move Worker ownership to a directly compiled page or local component effect so lexical global analysis remains tied to the original source tree.
57
+ Worker construction in imported helpers or imported keyed-row effects, `SharedWorker`, classic workers, Blob workers, arbitrary dynamic URLs, and package runtime graphs remain outside this completed capability.
74
58
 
75
59
  ## Ownership
76
60
 
77
- | Owner | Lifetime | Dashboard responsibility |
61
+ | Owner | Lifetime | Capability responsibility |
78
62
  |---|---|---|
79
- | Document | Full document | authentication expiry and global diagnostics |
80
- | Layout | Enhanced navigation session | tenant session or shared transport |
81
- | Route | Current dashboard/device | Worker, telemetry subscription, request cancellation |
82
- | DOM range | Current widget | chart, gauge, map, table, animation frame |
83
- | Worker | Explicit owner cleanup | parsing, bounded buffering, aggregation, downsampling |
63
+ | Document | Full document | global diagnostics and document-exit cleanup |
64
+ | Layout | Enhanced navigation session | explicitly shared browser resource |
65
+ | Route | Current route range | Worker, subscription, request cancellation |
66
+ | DOM range | Connected conditional/keyed range | imperative resource and animation work |
67
+ | Worker | Explicit owner cleanup | parsing, bounded buffering, aggregation |
84
68
 
85
- Leaving a route must remove message listeners, stop chart work, terminate its Worker, and invalidate stale UI writes before another route mounts. BFCache-preserved documents must retain their live ownership until a real document exit.
69
+ On an enhanced same-document transition, route cleanup removes listeners, stops imperative work, terminates its Worker, and invalidates stale UI writes before the next route mounts. Non-persisted document exit performs cleanup; a BFCache-persisted document retains live ownership for restoration.
86
70
 
87
71
  ## Fixture Contract
88
72
 
89
- The first fixture must provide:
73
+ The capability fixture proves:
90
74
 
91
- - one complete realtime dashboard document and one complete plain document in an opt-in navigation group;
75
+ - one complete Worker-enabled document and one complete plain document in an opt-in navigation group;
92
76
  - one unrelated static route with zero JavaScript;
93
77
  - a relative TypeScript Worker importing at least one relative helper;
94
- - a fixed-capacity ring buffer with deterministic eviction;
95
- - logical 1,000 samples/second input in batches rather than a 1 ms browser timer;
96
- - bounded downsampled frames delivered at no more than display cadence;
97
- - one imperative canvas or DOM chart updated without sample-level Kudzu setters;
98
- - direct load, dashboard-to-plain navigation, back/forward, and repeated cached revisits;
99
- - exact counters for Worker starts, terminations, messages, renders, listeners, and stale post-cleanup work;
78
+ - bounded deterministic buffering and batched sample generation;
79
+ - bounded frames delivered no faster than display cadence;
80
+ - one imperative resource updated without sample-level Kudzu setters;
81
+ - direct load, enhanced navigation, back/forward, and repeated cached revisits;
82
+ - exact starts, terminations, messages, renders, listeners, disposal, and stale-write counters;
100
83
  - native document fallback when JavaScript or Worker creation fails.
101
84
 
102
- ## Acceptance Criteria
103
-
104
- - the Worker graph is absent from static and plain route HTML and is fetched only after the dashboard effect mounts;
105
- - two unchanged production builds emit identical Worker names and bytes;
106
- - changing Worker source changes its content hash;
107
- - base-prefixed deployment produces a valid same-origin Worker URL;
108
- - 30 dashboard/plain cycles create and terminate exactly 30 route Workers with no growing listener or chart ownership;
109
- - messages arriving after cleanup cannot update removed route DOM;
110
- - the ring buffer remains at its configured capacity under sustained input;
111
- - chart rendering is batched and sample ingestion does not call `useState()`;
112
- - routes without Worker capabilities remain byte-for-byte unaffected;
113
- - output raw/gzip cost, clean build time, sample throughput, render cadence, and lifecycle counters are recorded;
114
- - `npm run check`, `npm test`, package dry-run, and browser checks pass.
115
-
116
- Verified measurements for the focused `/dash` fixture: the minified Worker graph is `assets/workers/telemetry.worker-BVG2SA55.js`, 907 B raw and 477 B gzip. The dashboard window graph is 11,388 B raw and 5,148 B gzip across its shared runtime, effect runtime, navigation, route effect entry, and handler module; the Worker is not part of that graph. Seven clean minified builds measured 455.1, 459.9, 460.7, 463.5, 467.6, 472.6, and 475.2 ms, with a 463.5 ms median.
117
-
118
- The real-Worker browser check uses real wall time and requires sustained generation beyond 1,130 samples at 700-1,300 logical samples/second, an exact 128-sample ring bound, batches of 10, exactly 24 displayed points, multiple renders, and a render ceiling below 25 Hz. Delayed Worker ticks catch up in batches to the logical 1,000 samples/second clock; frames emit no more often than every 50 ms. The imperative chart performs a minimal canvas path draw. The navigation ownership check completed 30 dashboard/plain cycles with exactly 30 starts and 30 terminations, exactly 60 listener additions and removals across message and error listeners, zero retained listeners after every cleanup, disposed every old chart canvas, fresh ownership on back/forward and cached revisits, and no render from a removed message listener invoked after cleanup. Dashboard, plain, and static HTML contain no Worker asset URL; plain does not load the route effect graph, and static contains no script, capability marker, or state payload. A no-Worker equivalent emitted byte-identical shared runtime, effect runtime, navigation, and route effect entry files with no `assets/workers` directory. An unreachable imported-row effect referencing `unused.worker.ts` emitted no Worker asset. Two unchanged builds emitted identical Worker names and bytes, and a controlled downsample-source change changed the emitted hash.
85
+ ## Acceptance And Performance Gates
119
86
 
120
- ## Delivery Order
87
+ - The Worker graph is absent from static and plain route HTML and fetched only after its effect mounts.
88
+ - Two unchanged builds emit identical Worker names and bytes; source changes alter the content hash.
89
+ - Base-prefixed output constructs a valid same-origin Worker URL.
90
+ - Repeated route cycles create and terminate exactly one route Worker each with no growing ownership.
91
+ - Messages after cleanup cannot update removed route DOM.
92
+ - Worker memory remains bounded by declared capacity.
93
+ - High-frequency ingestion does not create one main-thread task or Kudzu state commit per sample.
94
+ - Imperative rendering is batched to its declared cadence.
95
+ - Builds without this capability remain unaffected.
96
+ - Raw/gzip output, build time, throughput, cadence, and lifecycle counters are recorded.
97
+ - `npm run check`, `npm test`, package dry-run, and applicable browser checks pass.
121
98
 
122
- 1. **Worker compiler capability**: exact syntax, graph bundling, hashing, base rewriting, diagnostics, and zero-cost exclusion.
123
- 2. **Capability conformance fixture**: mock telemetry Worker, bounded buffer, downsampling, imperative DOM ownership, and route cleanup.
99
+ ## Historical Validation Record
124
100
 
125
- Further work belongs to the React migration roadmap and starts from a reduced compatibility fixture that fails. Kudzu does not implement device, alarm, transport, or widget product features.
101
+ The focused fixture emitted a 907 B raw / 477 B gzip Worker graph and an 11,388 B raw / 5,148 B gzip window graph. Seven clean minified builds measured a 463.5 ms median. Thirty route cycles produced exactly 30 starts and terminations, balanced message/error listener registration, bounded 128-sample history, no retained chart ownership, no stale post-cleanup render, deterministic unchanged builds, and a changed hash after a controlled Worker source edit.
126
102
 
127
- ## Performance Gates
128
-
129
- - sustained 1,000 samples/second does not create one main-thread task or Kudzu state commit per sample;
130
- - Worker memory is bounded by declared buffer capacity;
131
- - chart updates are batched to at most one per display frame;
132
- - dashboard departure stops observable messages and renders before the next route mounts;
133
- - repeated navigation leaves no growing Worker, timer, listener, chart, state, DOM, or heap ownership;
134
- - Worker support adds no bytes to routes and builds that do not use it;
135
- - material losses are profiled and fixed or documented as explicit tradeoffs using matched initial content and behavior.
103
+ These numbers are dated conformance evidence. They do not define a dashboard product target.
136
104
 
137
105
  ## Non-Goals
138
106
 
139
- - implementing ThingsBoard's server, protocol, rule engine, database, or complete UI;
140
- - storing telemetry samples in Kudzu component state;
141
- - adding a general observable, scheduler, stream, state, or widget runtime;
142
- - retaining a browser component tree;
143
- - request-time SSR, Server Actions, or a hidden application server;
144
- - a plugin marketplace or arbitrary third-party React widgets;
145
- - claiming Worker isolation as a security sandbox.
146
-
147
- ## Completion Definition
148
-
149
- Goal B Milestone 1 is complete when the focused realtime fixture proves deterministic relative TypeScript Worker emission, bounded high-frequency processing, imperative chart updates, exact route ownership and cleanup across repeated navigation, native/static fallback, zero-cost exclusion, source diagnostics, and recorded production measurements.
107
+ - Device, alarm, tenant, transport, chart, map, or widget product features.
108
+ - A general stream, observable, scheduler, state, or plugin runtime.
109
+ - Storing high-frequency samples in Kudzu component state.
110
+ - Retaining a browser component tree.
111
+ - Request-time SSR, server actions, or a hidden server.
112
+ - Arbitrary third-party React widgets.
113
+ - Treating Worker isolation as a security sandbox.
package/README.md CHANGED
@@ -10,11 +10,11 @@ Kudzu is designed so ordinary common React-shaped TSX can migrate with minimal s
10
10
 
11
11
  > Experimental `0.7.x`: the compiler API and supported TSX surface may change.
12
12
 
13
- **0.7.6:** Zustand-shaped shared stores. Reduced `create(set => ...)` stores compile to persistent application-layout state and direct handler updates without shipping React or Zustand. See [release notes](./RELEASES.md#076---zustand-shaped-shared-stores).
13
+ **0.7.9:** Keyed-row prop defaults. Same-file and relative keyed row components retain destructured primitive literal defaults, with missing props substituted at compile time and no new browser runtime. See [release notes](./RELEASES.md#079---keyed-row-prop-defaults).
14
14
 
15
15
  Documentation: [kudzujs.cloud/docs](https://kudzujs.cloud/docs)
16
16
 
17
- Development target: [Goal A static business applications](./GOAL_A.md)
17
+ Development direction: [React migration roadmap](./MIGRATION_ROADMAP.md)
18
18
 
19
19
  ## Install
20
20
 
@@ -74,7 +74,7 @@ export default function Header() {
74
74
  }
75
75
  ```
76
76
 
77
- Kudzu rewrites supported React imports to its compile-time APIs before evaluating the module; neither the React package nor a compatibility runtime enters the deploy output. Named or aliased `useState`, `useReducer`, `useEffect`, `useRef`, `createContext`, and `useContext` imports compile to their canonical forms. Default and namespace imports may call those APIs as direct members such as `React.useState`, and default, namespace, or named `Fragment` also works. `memo(Component)` is erased to a same-file component. Inline `useCallback(function, literalDependencies)` is erased to its function, while inline synchronous `useMemo` callbacks may return one expression over primitive literals/direct local state or an analyzable `filter`, `map`, `flatMap`, and `Array.from` collection pipeline. Scalar expressions inline into existing bindings; collection pipelines lower to existing keyed-list selectors and preserve row identity. Both hooks require inert literal dependency arrays and complete captured-state dependencies; memo locals cannot be duplicated or captured by nested functions. React classes and side-effect or dynamic React imports remain unsupported. A static route using these forms still emits zero JavaScript.
77
+ Kudzu rewrites supported React imports to its compile-time APIs before evaluating the module; neither the React package nor a compatibility runtime enters the deploy output. Named or aliased `useState`, `useReducer`, `useEffect`, `useRef`, `createContext`, and `useContext` imports compile to their canonical forms. Default and namespace imports may call those APIs as direct members such as `React.useState`, and default, namespace, or named `Fragment` also works. `memo(Component)` is erased to a same-file component. Inline `useCallback(function, literalDependencies)` is erased to its function, while inline synchronous `useMemo` callbacks may return one expression over primitive literals/direct local state or an analyzable `filter`, `map`, `flatMap`, and `Array.from` collection pipeline. Collection pipelines may start from local array state or a named relative import whose source is an exported JSON-safe `const` array; imported static collections may be filtered by direct local state listed in the dependency array. Scalar expressions inline into existing bindings; collection pipelines lower to existing keyed-list selectors and preserve row identity. Both hooks require inert literal dependency arrays and complete captured-state dependencies; memo locals cannot be duplicated or captured by nested functions. React classes and side-effect or dynamic React imports remain unsupported. A static route using these forms still emits zero JavaScript.
78
78
 
79
79
  Direct default or named `clsx` imports compile away for string/number literals, literal arrays, literal object conditions, and conditional expressions. Kudzu lowers those calls to ordinary class expressions, so reactive classes reuse existing bindings without shipping `clsx`; spreads, computed object keys, arbitrary calls, and indirect references remain unsupported.
80
80
 
@@ -418,7 +418,9 @@ return <ItemList items={items} />
418
418
 
419
419
  The original row component remains reusable across multiple lists and ordinary JSX. State-backed list wrappers and row components are specialized to intrinsic JSX at build time; no component function or component runtime is shipped to the browser. Kudzu emits initial items as static HTML, then adds, removes, updates, styles, conditional branches, and moves keyed elements directly. The map may appear directly in JSX, in one top-level immutable `const` rendered once as a JSX child, or in one synchronous wrapper receiving the state identifier as a direct prop. Existing keys move without remounting, preserving uncontrolled descendant state. Direct `item.<field>` reads use compact markers; derived item expressions compile to external ESM evaluators. Nested item-local `&&` and ternary conditions patch bounded branches and mount or unmount their handlers. Item-local handlers and effects receive the latest JSON-safe item for their key. Effects mount after a row is connected and clean up when it is removed. A direct primitive item dependency such as `[item.name]`, optionally mixed with row or page state, reruns only rows whose selected values changed; unrelated fields and reorder do not rerun it, while removal cleans it up. The item remains stored once in shared list state; runtime descriptors carry a placeholder that the list runtime fills when mounting or updating the keyed root.
420
420
 
421
- Rendered collections may use one-use top-level aliases and analyzable pipelines over local array state. Inline arrow callbacks accept `(item)` or `(item, index)`; `filter()` supports pure synchronous expressions, `flatMap()` projects one direct array property, `Array.from()` accepts an optional pure mapper, and the final `map()` may use `key={item.field}` or positional `key={index}`. Field keys preserve the matching DOM node through filtering and reorder. Positional keys deliberately preserve the DOM node at each position while its item changes, matching React key semantics.
421
+ Rendered collections may use one-use top-level aliases and analyzable pipelines over local array state or named relative imports of exported JSON-safe `const` arrays. Inline arrow callbacks accept `(item)` or `(item, index)`; `filter()` supports pure synchronous expressions and direct local-state reads, `flatMap()` projects one direct array property, `Array.from()` accepts an optional pure mapper, and the final `map()` may use `key={item.field}` or positional `key={index}`. Field keys preserve the matching DOM node through filtering and reorder. Positional keys deliberately preserve the DOM node at each position while its item changes, matching React key semantics.
422
+
423
+ Compiler-owned static `filter` collections with structural keyed rows validate source items and key tokens once. Removed rows become detached prototypes; restoration clones fresh nodes and inserts only new runs, so retained keys keep identity while restored keys remount. In a 31-fresh-profile, 4x CPU-throttled Chrome benchmark over 1,000 alternating products, Kudzu measured 37.8 ms to visible rows, 8.4 ms to filter to 500, and 3.6 ms to restore 1,000. React measured 86.3/12.9/6.2 ms, Vue 54.1/8.4/4.3 ms, and Svelte 61.4/11.7/8.3 ms. This is a focused static-filter result, not a claim that rendering 100,000 or 1,000,000 DOM rows is appropriate; paginate or window large datasets so only the visible result set enters the document.
422
424
 
423
425
  A keyed row may contain multiple keyed maps over direct array properties of its item at any nesting depth. This supports recursively nested data populated after mount while preserving keyed DOM identity across updates and reorder:
424
426
 
@@ -463,7 +465,7 @@ Initial child rows remain complete HTML. Kudzu stores one child row prototype, i
463
465
 
464
466
  In the matched 100-parent/1,000-child fixture, Kudzu measured 1.3/0.4/5.0/0.7 ms for child update and condition change, child reverse, parent reverse, and parent removal. Hand-written Astro/native measured 0.5/0.4/3.9/0.2 ms, Svelte 2.7/1.2/6.7/1.3 ms, Vue 4.9/2.5/6.1/2.2 ms, and React 11.8/5.0/8.2/4.4 ms. Kudzu and Astro emit initial rows while the CSR targets do not, so artifact sizes are not architecture-equivalent.
465
467
 
466
- Each item must be an ordinary plain object with a unique string or finite-number key; nested data may contain only JSON-safe arrays, ordinary plain objects, and primitive values. Null-prototype objects are rejected to preserve JSON round-trip parity. Collections must remain anchored to local array state; inline callbacks accept one or two identifier parameters, and row roots must be intrinsic JSX or supported same-file/relative components with `key={item.<field>}` or `key={index}`. State-backed list wrappers use one destructured props parameter, an intrinsic return root, no effects, and a direct local-state prop. Whole-item, computed, nested, derived, `__proto__`, `prototype`, and `constructor` effect dependencies are rejected. A collection alias may only be rendered once and cannot be read by other JavaScript. Collection callbacks and derived expressions must be pure and synchronous: supported reads, operators, templates, approved read-only methods, deterministic `Math`, and primitive conversion compile; imported callbacks, browser globals, promises, mutation, arbitrary calls, and prototype-sensitive properties fail. Lazy or dynamic keyed-row state initializers, non-`null` refs, callback refs, package/namespace/star row imports, same-file exported rows, reusable aliases, prop spreads/defaults/rest, children, fragments, and `dangerouslySetInnerHTML` remain unsupported. Keyed rows must be placed inside an explicit `<tbody>`, `<thead>`, or `<tfoot>`.
468
+ Each item must be an ordinary plain object with a unique string or finite-number key; nested data may contain only JSON-safe arrays, ordinary plain objects, and primitive values. Null-prototype objects are rejected to preserve JSON round-trip parity. Collections must remain anchored to local array state or a supported static named import; inline callbacks accept one or two identifier parameters, and row roots must be intrinsic JSX or supported same-file/relative components with `key={item.<field>}` or `key={index}`. Specialized keyed row components accept missing destructured string, finite-number, boolean, or `null` props with literal defaults. State-backed list wrappers use one destructured props parameter, an intrinsic return root, no effects, and a direct local-state prop. Whole-item, computed, nested, derived, `__proto__`, `prototype`, and `constructor` effect dependencies are rejected. A collection alias may only be rendered once and cannot be read by other JavaScript. Collection callbacks and derived expressions must be pure and synchronous: supported reads, operators, templates, approved read-only methods, deterministic `Math`, and primitive conversion compile; imported callbacks, browser globals, promises, mutation, arbitrary calls, and prototype-sensitive properties fail. Lazy or dynamic keyed-row state initializers, non-`null` refs, callback refs, package/namespace/star row imports, same-file exported rows, reusable aliases, prop spreads/rest, non-primitive defaults, children, fragments, and `dangerouslySetInnerHTML` remain unsupported. Keyed rows must be placed inside an explicit `<tbody>`, `<thead>`, or `<tfoot>`.
467
469
 
468
470
  The focused wrapper fixture emits 1,393 B raw / 500 B gzip HTML and 10,719 B raw / 4,665 B gzip JavaScript across its route capabilities. After one warm-up, seven clean builds measured 314.1, 325.3, 322.3, 327.2, 336.1, 322.4, and 315.0 ms, with a 322.4 ms median.
469
471
 
@@ -672,18 +674,21 @@ Supported:
672
674
  - Layout- and route-lifetime effect mounts in navigation groups
673
675
  - Conditional/keyed DOM-owned effects in navigation groups
674
676
 
675
- Not implemented yet:
677
+ Selected current migration limits:
678
+
679
+ - Common prop spreads/rest, wrapper `children` forwarding, `forwardRef`, and `useId` still need fixture-driven component specialization.
680
+ - Hookful non-keyed imported components and pure lazy state/reducer initializers remain narrower than ordinary React.
681
+ - Reusable collection aliases, computed child collections, imported pure transforms, and common immutable pagination/sorting forms need failing fixtures before expansion.
682
+ - Effect dependencies remain limited to directly analyzable primitive signals and supported keyed-item properties.
683
+ - Conditional/keyed ranges inside SVG and router-shaped package source remain separate compatibility work.
684
+ - Arbitrary, mutating, asynchronous, or package collection callbacks remain deliberate static-analysis boundaries.
685
+ - Server actions, request-time SSR, a React runtime/ecosystem layer, React islands, and a default SPA router are non-goals.
676
686
 
677
- - Reusable keyed-list aliases
678
- - Arbitrary, imported, mutating, or asynchronous collection callbacks
679
- - Lazy/dynamic keyed-row state initializers and callback refs
680
- - Server actions and request-time SSR
681
- - React package/runtime/ecosystem compatibility or React islands
682
- - HMR and framework DevTools
687
+ See the [active fixture queue](./MIGRATION_ROADMAP.md#active-fixture-queue) for development order. Unsupported syntax is not automatically backlog work; a real React migration fixture must fail first.
683
688
 
684
689
  ## Benchmarks
685
690
 
686
- ### Goal A Commerce Journey
691
+ ### Goal A Validation Fixture: Commerce Journey
687
692
 
688
693
  The matched fixture covers home, category, product, cart, checkout, and account routes with complete initial HTML, shared application layout state, product options, optimistic cart success and rejection, accessible errors, rollback, and product-to-cart navigation. Kudzu, React + Vite, Next.js, Nuxt, and SvelteKit render the same tested content and interactions.
689
694