@kudzujs/core 0.13.3 → 0.14.1

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/PERFORMANCE.md CHANGED
@@ -2,10 +2,64 @@
2
2
 
3
3
  Reproducibility classes: `npm run benchmark`, `npm run benchmark:keyed`, `npm run benchmark:native`, `npm run benchmark:module-cache`, `npm run benchmark:project-navigation`, `npm run benchmark:project-state`, and `npm run benchmark:source-scale` are maintained in this repository; `npm run benchmark:commerce` is a maintained paired runner over the public external storefront; older excluded-workspace sections are historical provenance only and are not current framework rankings.
4
4
 
5
+ ## 0.14.1 Nested Object-State Collections
6
+
7
+ Measured 2026-08-26 on Linux x64 with Node 24.14.0 and Chrome
8
+ 142.0.7444.175.
9
+
10
+ The project route now roots its selected project table and nested issue rows in
11
+ one direct `projectData.projects` field. Required Chrome proves immutable
12
+ whole-object replacement, nested insert/update/reorder/remove/re-add, retained
13
+ identity, latest handlers, descendant state release, and fresh remount. `/help`
14
+ remains 0 B JavaScript.
15
+
16
+ The application emits 44 files totaling 164,305 raw / 52,185 aggregate gzip
17
+ bytes with deploy SHA-256
18
+ `0a3b7e10b3447a76a9c04ef34ad7c2bfa30400ea53c9d16fc85b1c7cbf2ea203`.
19
+ The two-route session remains 17 JavaScript files and totals 74,826 raw / 26,204
20
+ aggregate gzip bytes. The delta from `0.14.0` includes the authored nested issue
21
+ controls and handlers plus one build-time validation-line edit and one production
22
+ list-runtime line; no semantic primitive, IR kind, compiler pass, runtime concept,
23
+ or public API was added.
24
+
25
+ Table update samples are
26
+ `[0.8, 0.8, 0.7, 0.8, 0.9, 0.8, 0.8]` ms, with a 0.8 ms median and 0.7/0.9 ms
27
+ minimum/maximum. Navigation samples are
28
+ `[3.7, 4.1, 4.5, 3.9, 4.2, 3.9, 4.3]` ms, with a 4.1 ms median and 3.7/4.5 ms
29
+ minimum/maximum. The navigation ranges overlap the `0.14.0` release evidence;
30
+ no improvement or regression claim is made.
31
+
5
32
  `npm run benchmark:source-scale` generates its fixture outside the repository so 50,000 lines of synthetic source are not tracked. The default topology is 50 pages plus 450 route-owned imported modules. Generation is excluded from timing; fresh-process samples separately report source reads, reachable-graph discovery, source compilation, clean production build, compiler-result and deploy digests, output files/bytes, cache counters, and peak RSS. `ROUTES`, `MODULES_PER_ROUTE`, `FILLER_LINES`, `WARMUPS`, and `RUNS` may reduce or expand the fixture without changing the default acceptance floor. `TARGET_ROOT` measures another checkout; `BASELINE_ROOT` alternates that checkout with the current tree and requires identical deploy output.
6
33
 
7
34
  The maintained 2026-08-13 comparison used Node 24.14.0 and an Intel Core i5-9500 Linux x64 host, one warm-up, and seven alternating fresh-process samples against clean `v0.8.44`. A narrow fast path skips Kudzu semantic transformation for 450 plain `.ts` modules whose runtime edges are exclusively resolvable relative TypeScript imports or exports; all other modules retain the existing transformer. Compile median fell from 2,323.9 ms to 1,413.2 ms (39.2%) and clean-build median from 3,325.3 ms to 2,382.4 ms (28.4%); every paired sample improved. Compile peak-RSS median fell from 571.2 MiB to 552.6 MiB, while build peak RSS was 570.9 MiB versus 568.8 MiB. Compiler scratch fell from 7,328,390 to 1,971,061 bytes. Both targets emitted the same 50 static HTML files, 10,980 bytes, and deploy SHA-256 `e107d78a7f55bc8a1af0ea6e53efeffa19b3d44d21c892484d103fa346e7ba7b`. This is a source-scale compiler comparison, not a cross-framework result.
8
35
 
36
+ ## 0.14.0 Project Table CRUD And Identity
37
+
38
+ Measured 2026-08-26 on Linux x64 with Node 24.14.0 and Chrome
39
+ 142.0.7444.175. Required Chrome proves native table insert, update, delete,
40
+ reorder, sort, filter, selection, keyboard focus, row-local edit state, and
41
+ retained keyed DOM identity.
42
+
43
+ The application emits 44 files totaling 159,258 raw / 51,627 aggregate gzip
44
+ bytes with deploy SHA-256
45
+ `ebb3358e7a03612459e723ae765c39d105498db9d293415b924f1066cddf4793`.
46
+ The two-route session remains 17 JavaScript files and totals 73,304 raw / 25,930
47
+ aggregate gzip bytes, 2,273 raw / 626 gzip bytes above `0.13.3`. `/help`
48
+ remains 0 B JavaScript. The added bytes are route-specific authored table
49
+ handlers, bindings, selectors, and keyed row state; there is no data-grid
50
+ runtime.
51
+
52
+ Table update samples are `[0.7, 0.8, 1.0, 0.7, 1.1, 0.7, 0.8]` ms, with a 0.8
53
+ ms median and 0.7/1.1 ms minimum/maximum. Navigation samples are
54
+ `[3.9, 3.9, 5.5, 4.2, 6.1, 3.5, 3.4]` ms, with a 3.9 ms median and 3.4/6.1 ms
55
+ minimum/maximum. Table update is a new measurement, so no same-content latency
56
+ delta is claimed.
57
+
58
+ Core semantic LOC remains 5,682 with zero new semantic primitives, IR kinds,
59
+ compiler passes, production compiler/runtime lines, normalization rules,
60
+ adapters, runtime concepts, public APIs, or data-grid runtimes. Infinite loading,
61
+ windowing, and the 10,000-row strategy remain later measured decisions.
62
+
9
63
  ## 0.13.3 File Upload Boundary
10
64
 
11
65
  Measured 2026-08-25 on Linux x64 with Node 24.14.0 and Chrome
package/README.md CHANGED
@@ -12,9 +12,9 @@ Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTM
12
12
 
13
13
  *Watch: React-shaped TSX to static HTML and route-specific ESM in 22 seconds.*
14
14
 
15
- > Experimental `0.13.x`: the compiler API and supported TSX surface may change.
15
+ > Experimental `0.14.x`: the compiler API and supported TSX surface may change.
16
16
 
17
- **Latest release: 0.13.3 - File upload boundary.** Native file validation, multipart upload, cancellation, failure and retry, route cleanup, and keyed attachment mutation compose without an upload runtime. Read the [release notes](./RELEASES.md#0133---file-upload-boundary), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.13.3), or follow the [architecture packet](./docs/next-architecture/README.md).
17
+ **Latest release: 0.14.1 - Nested and object-state collections.** Direct immutable array fields of ordinary object state now compose root and nested keyed ownership with retained identity, latest handlers, and exact row-state release. Read the [release notes](./RELEASES.md#0141---nested-and-object-state-collections), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.14.1), or follow the [architecture packet](./docs/next-architecture/README.md).
18
18
 
19
19
  - [Documentation](https://kudzujs.cloud/docs)
20
20
  - [Installation guide](https://kudzujs.cloud/docs#install)
package/RELEASES.md CHANGED
@@ -1,5 +1,101 @@
1
1
  # Kudzu Releases
2
2
 
3
+ ## 0.14.1 - Nested And Object-State Collections
4
+
5
+ Kudzu 0.14.1 lets one direct immutable array field of ordinary object state own
6
+ a root keyed collection and its nested direct-property lists.
7
+
8
+ ### Changed in 0.14.1
9
+
10
+ - Allowed compiler-proven object-state collection roots without authored field
11
+ state.
12
+ - Initialized binding-backed roots before nested row ownership mounts.
13
+ - Preserved project and issue DOM identity through immutable replacement and
14
+ nested update, reorder, and removal.
15
+ - Preserved latest-item handlers and released descendant row state exactly.
16
+ - Recreated removed and re-added nested rows with fresh local state.
17
+ - Updated `create-kudzu@0.1.123` to generate projects on
18
+ `@kudzujs/core@^0.14.1`.
19
+
20
+ ### Output Evidence
21
+
22
+ - The application emits 44 files totaling 164,305 raw / 52,185 aggregate gzip
23
+ bytes with deploy digest
24
+ `0a3b7e10b3447a76a9c04ef34ad7c2bfa30400ea53c9d16fc85b1c7cbf2ea203`.
25
+ - The maintained two-route session remains 17 JavaScript files and totals
26
+ 74,826 raw / 26,204 aggregate gzip bytes; `/help` remains 0 B JavaScript.
27
+ - No semantic primitive, IR kind, compiler pass, runtime concept, or public API
28
+ was added. One build-time validation line changed and one list-runtime line
29
+ was added.
30
+
31
+ ### Validation
32
+
33
+ - Required Chrome proves immutable whole-object replacement, nested issue
34
+ insert, update, reorder, removal, re-addition, retained identity, latest
35
+ handlers, descendant state release, and fresh remount.
36
+ - The complete suite passes 274 tests, package smoke, and serialized required-
37
+ Chrome execution.
38
+ - Seven fresh Chrome profiles record a 0.8 ms table-update median with a
39
+ 0.7-0.9 ms range and a 4.1 ms navigation median with a 3.7-4.5 ms range.
40
+
41
+ ### Limits
42
+
43
+ Collection roots require one direct static array field and immutable whole-
44
+ object replacement. Dynamic or computed paths, mutation, and non-array fields
45
+ remain unsupported.
46
+
47
+ ### Upgrade
48
+
49
+ ```sh
50
+ npm install @kudzujs/core@^0.14.1
51
+ ```
52
+
53
+ ## 0.14.0 - Project Table CRUD And Identity
54
+
55
+ Kudzu 0.14.0 composes a complete native project table from ordinary state,
56
+ collection selectors, and keyed ownership without a data-grid runtime.
57
+
58
+ ### Changed in 0.14.0
59
+
60
+ - Replaced the project article list with valid native table structure.
61
+ - Added project insertion, inline name editing, save, and deletion.
62
+ - Added reorder, immutable name sorting, active filtering, and row selection.
63
+ - Preserved keyed row and draft-input identity through reorder and sort.
64
+ - Recreated removed rows with fresh local state after filter restoration.
65
+ - Kept editor controls mounted with native `hidden` and verified keyboard focus.
66
+ - Updated `create-kudzu@0.1.122` to generate projects on
67
+ `@kudzujs/core@^0.14.0`.
68
+
69
+ ### Output Evidence
70
+
71
+ - The application emits 44 files totaling 159,258 raw / 51,627 aggregate gzip
72
+ bytes with deploy digest
73
+ `ebb3358e7a03612459e723ae765c39d105498db9d293415b924f1066cddf4793`.
74
+ - The maintained two-route session remains 17 JavaScript files and totals
75
+ 73,304 raw / 25,930 aggregate gzip bytes; `/help` remains 0 B JavaScript.
76
+ - No semantic primitive, IR kind, compiler pass, production compiler/runtime
77
+ line, runtime concept, public API, or data-grid runtime was added.
78
+
79
+ ### Validation
80
+
81
+ - Required Chrome proves insert, update, delete, reorder, sort, filter,
82
+ selection, keyboard access, row-local edit state, and retained DOM identity.
83
+ - The complete suite passes 273 tests.
84
+ - Seven fresh Chrome profiles record a 0.8 ms table-update median with a
85
+ 0.7-1.1 ms range and a 3.9 ms navigation median with a 3.4-6.1 ms range.
86
+
87
+ ### Limits
88
+
89
+ This is an ordinary bounded table, not virtualization. Infinite loading,
90
+ windowing, dynamic row measurement, and 10,000-row strategy selection remain
91
+ separate evidence packets.
92
+
93
+ ### Upgrade
94
+
95
+ ```sh
96
+ npm install @kudzujs/core@^0.14.0
97
+ ```
98
+
3
99
  ## 0.13.3 - File Upload Boundary
4
100
 
5
101
  Kudzu 0.13.3 composes a bounded file-upload lifecycle from native controls,
@@ -877,6 +877,35 @@ regression or improvement is claimed.
877
877
  - **Stop condition:** a data-grid runtime is introduced for ordinary tables.
878
878
  - **Done condition:** complete CRUD behavior passes with measured update latency.
879
879
 
880
+ Evidence complete. The first failing fixture was the
881
+ `0.14.0` project-application contract against the previous article list. It now
882
+ uses a native table, ordinary array/object state, the existing pure collection
883
+ selector, three existing keyed row-state slots, and native button/input keyboard
884
+ behavior for insert, update, delete, reverse, sort, filter, selection, and edit.
885
+ The browser journey proves retained row and draft-input identity through reorder
886
+ and sort, fresh identity/state after filter removal and restoration, and focused
887
+ keyboard reachability. Native `hidden` keeps the editor mounted rather than
888
+ introducing a conditional callback-scope adapter or data-grid runtime.
889
+
890
+ This slice adds zero semantic primitives, zero compiler passes, zero core LOC,
891
+ and zero runtime concepts. It changes one real fixture, its contract, the
892
+ machine-readable capability record, and the existing project benchmark. The
893
+ application remains 44 files and changes from the `0.13.3` baseline by +9,235
894
+ raw / +1,387 aggregate gzip bytes to 159,258 / 51,627 bytes, with deploy SHA-256
895
+ `ebb3358e7a03612459e723ae765c39d105498db9d293415b924f1066cddf4793`.
896
+ The maintained two-route session remains 17 JavaScript files and grows by 2,273
897
+ raw / 626 aggregate gzip bytes to 73,304 / 25,930 bytes; `/help` remains 0 B
898
+ JavaScript.
899
+
900
+ Seven fresh Linux x64 Chrome 142 profiles record table Save-click-to-committed-
901
+ DOM samples of `[0.7, 0.8, 1.0, 0.7, 1.1, 0.7, 0.8]` ms, a 0.8 ms median and
902
+ 0.7/1.1 ms range. This is the first equivalent table-update measurement, so no
903
+ same-content latency delta is claimed. The same runs record list-to-detail
904
+ samples of `[3.9, 3.9, 5.5, 4.2, 6.1, 3.5, 3.4]` ms, a 3.9 ms median and
905
+ 3.4/6.1 ms range. No compiler/runtime production logic changed; `0.14.0`
906
+ publishes the accepted application-capability packet and `create-kudzu@0.1.122`
907
+ generates projects on `@kudzujs/core@^0.14.0`.
908
+
880
909
  ### `0.14.1`: Nested And Object-State Collections
881
910
 
882
911
  - **Purpose:** prove project/group/issue/checklist nesting from ordinary object
@@ -889,6 +918,37 @@ regression or improvement is claimed.
889
918
  - **Done condition:** direct immutable paths cover the application journey and
890
919
  nearby dynamic forms fail clearly.
891
920
 
921
+ Release evidence complete. The first failure replaced the project route's
922
+ separate array state with one direct `projectData.projects` field and failed at
923
+ build time because nested lists required their source ownership signal itself to
924
+ contain an array. The compiler already emitted a binding-backed root
925
+ `KeyedBlockIR`, its selector states, and the nested issue child block. Build-time
926
+ list validation now allows an object-valued signal only for a compiler-proven
927
+ `ownerField`; root lists still require arrays and nested non-array fields still
928
+ fail. Browser mounting initializes binding-backed roots with children from their
929
+ serialized state before the evaluator module loads, preserving the existing
930
+ parent prototype and ownership path.
931
+
932
+ Required Chrome proves immutable whole-object replacement, nested issue insert,
933
+ update, reorder, removal, re-addition, retained project/issue identity, latest
934
+ issue handlers, descendant state release, and fresh remount. Existing dynamic
935
+ object-property, alias, mutation, mutating-sort, and non-array diagnostics retain
936
+ the negative boundary, while `/help` remains complete HTML with 0 B JavaScript.
937
+ The slice adds zero semantic primitives, IR kinds, compiler passes,
938
+ normalization rules, adapters, runtime concepts, or public APIs. It changes one
939
+ build-time validation line and adds one production list-runtime line.
940
+
941
+ The release emits 44 files totaling 164,305 raw / 52,185 aggregate gzip bytes
942
+ with deploy SHA-256
943
+ `0a3b7e10b3447a76a9c04ef34ad7c2bfa30400ea53c9d16fc85b1c7cbf2ea203`.
944
+ The two-route session remains 17 JavaScript files totaling 74,826 raw / 26,204
945
+ aggregate gzip bytes. Seven fresh Chrome 142 profiles record table
946
+ update samples of `[0.8, 0.8, 0.7, 0.8, 0.9, 0.8, 0.8]` ms, a 0.8 ms median and
947
+ 0.7/0.9 ms range, plus navigation samples of
948
+ `[3.7, 4.1, 4.5, 3.9, 4.2, 3.9, 4.3]` ms, a 4.1 ms median and 3.7/4.5 ms range.
949
+ `0.14.1` publishes this accepted packet, and `create-kudzu@0.1.123` generates
950
+ projects on `@kudzujs/core@^0.14.1`.
951
+
892
952
  ### `0.14.2`: Infinite Loading Composition
893
953
 
894
954
  - **Purpose:** prove sentinel-driven incremental loading before virtualization.
@@ -1365,5 +1425,7 @@ release transaction where possible or document and publish a forward-fix patch.
1365
1425
  | `0.13.1` | Released | Preserve application-owned nested metadata, keyed row identity, release, and reset evidence. | None |
1366
1426
  | `0.13.2` | Released | Preserve multistep validation, versioned persistence, stale-save rejection, conflict retention, and reset evidence. | None |
1367
1427
  | `0.13.3` | Released | Preserve the published upload validation, cancellation, retry, route cleanup, and attachment mutation evidence. | None |
1368
- | `0.14.0` | Active | Add the first failing project-table CRUD and retained-identity fixture. | None |
1369
- | `0.14.1` onward | Blocked | Complete or explicitly close `0.14.0` first. | Ordered patch boundary |
1428
+ | `0.14.0` | Released | Preserve native table CRUD, retained identity, keyboard access, and measured update evidence. | None |
1429
+ | `0.14.1` | Released | Preserve immutable object-state replacement, nested keyed identity, latest handlers, and exact row release. | None |
1430
+ | `0.14.2` | Active | Add the first failing infinite-loading composition fixture. | None |
1431
+ | `0.14.3` onward | Blocked | Complete or explicitly close `0.14.2` first. | Ordered patch boundary |
@@ -66,7 +66,7 @@ Keep each patch behavior-preserving and independently reviewable. If a boundary
66
66
 
67
67
  ## Generator Versions
68
68
 
69
- `create-kudzu@0.1.121` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.13.3`.
69
+ `create-kudzu@0.1.123` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.14.1`.
70
70
 
71
71
  ## Release Boundary
72
72
 
@@ -100,6 +100,6 @@ A direct setter or inline/simple `const` setter callback may cross one same-file
100
100
 
101
101
  `kudzu.config` may opt one emitted shared-layout group into same-document navigation with legacy `navigation: { routes: ["/product", "/items/[id]"] }`, or multiple groups with `navigation: { groups: [{ routes: [...] }, { routes: [...] }] }`. The forms are mutually exclusive. Identities are globally unique emitted exact paths or `runtimeParams` patterns; each group uses one page-exported layout function identity. Runtime records securely match concrete pathnames under `base`, and their cache-safe parameter initializer runs before route DOM/effects mount on every transition. Each group receives a deterministic route-hashed asset specialized to only its records, pattern decoder, and effect/parameter lifecycle needs. Cross-group and ungrouped anchors remain native and are not prefetched; overlapping path domains across groups fail the build. Route effect entries export cache-safe layout and route mount functions: layout effects, including conditional/keyed DOM-owned effects, persist for the group session; route effects receive a fresh owner registry after each route insertion; and non-persisted page disposal cleans route before layout. Direct primitive state, runtime parameter, and keyed-item property dependencies and cleanup are supported. Fragment payloads and coordinated View Transitions are not implemented.
102
102
 
103
- A direct object-state prop may expose one-segment static fields when its same-file or relative-imported child directly maps an array field. Scalar bindings and that selected array effect dependency reuse the parent signal, existing `Object.is` comparison, and binding-backed keyed ownership without field state or a browser component. Dynamic paths, aliases, mutation, child state/ref/ID hooks, and opaque call-site values remain unsupported.
103
+ A direct object-state prop may expose one-segment static fields when its same-file or relative-imported child directly maps an array field. Scalar bindings and that selected array effect dependency reuse the parent signal, existing `Object.is` comparison, and binding-backed keyed ownership without field state or a browser component. A direct static array field of local object state may also root a keyed selector pipeline with nested direct-property lists; immutable whole-object replacement reuses the same binding-backed root and nested ownership. Dynamic paths, aliases, mutation, child state/ref/ID hooks, opaque call-site values, and non-array collection fields remain unsupported.
104
104
 
105
105
  Cross-framework performance tables are historical snapshots from excluded workspaces and are not current rankings. `npm run benchmark` tracks the Worker build/graph fixture; `RUNS=21 npm run benchmark:keyed` tracks large keyed restoration; `BASELINE_ROOT=... npm run benchmark:native` tracks native dispatch and exact artifact changes. Current methodology, raw arrays, external-fixture limits, and artifact deltas live in `PERFORMANCE.md` and the web docs.
@@ -316,7 +316,7 @@ export function list(items, keyField, render, ownerField, selector = [], indexed
316
316
  const source = items?.[bindingMarker] ? bindingDescriptor(items) : undefined
317
317
  if (source) items = createInternalState(items.value)
318
318
  if (Array.isArray(items)) items = createInternalState(items)
319
- if (!items?.[signalMarker] || !Array.isArray(items.value)) throw new Error("A keyed list must use local array state or a supported imported static array")
319
+ if (!items?.[signalMarker] || (!ownerField && !Array.isArray(items.value))) throw new Error("A keyed list must use local array state or a supported imported static array")
320
320
  const selectorStateMap = new Map(selectorStates)
321
321
  for (const [name, state] of selectorStateMap) if (!state?.[signalMarker]) throw new Error(`Rendered collection selector state ${JSON.stringify(name)} must be framework state`)
322
322
  let values = items.value
@@ -96,6 +96,7 @@ function mountLists(root) {
96
96
  ownedLists.set(list.owner, lists)
97
97
  listRegistrations.set(start, { list, owner: list.owner })
98
98
  } else if (descriptor.source) {
99
+ if (descriptor.children) updateList(list)
99
100
  const load = {}
100
101
  listLoads.set(start, load)
101
102
  loadListEvaluator(descriptor.source).then(evaluator => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kudzujs/core",
3
- "version": "0.13.3",
3
+ "version": "0.14.1",
4
4
  "description": "HTML-first TSX framework with synchronous state semantics and no virtual DOM",
5
5
  "type": "module",
6
6
  "license": "MIT",