@kudzujs/core 0.16.14 → 0.16.16

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.
@@ -57,7 +57,7 @@ Syntax compatibility does not mean reproducing React wholesale. Kudzu accepts th
57
57
  - stronger JavaScript failure resilience;
58
58
  - no remaining material large-route build-scaling weakness.
59
59
 
60
- The completed 0.9 plan defines the cross-framework comparison and release gate. The active application packet is `0.20.5` in the capability release plan below. Benchmark-only feature omission, unmatched accessibility, weighted scores that hide losses, and unrecorded environment differences do not count as proof.
60
+ The completed 0.9 plan defines the cross-framework comparison and release gate. The active application packet is `0.21.2` in the capability release plan below. Benchmark-only feature omission, unmatched accessibility, weighted scores that hide losses, and unrecorded environment differences do not count as proof.
61
61
 
62
62
  ### 0.10.0 Through 0.21.x: Application Capability Release Train
63
63
 
package/PERFORMANCE.md CHANGED
@@ -2,6 +2,133 @@
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`, `npm run benchmark:source-scale`, and `npm run benchmark:ai-delivery` 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.21.1 Compiler And Route Scale
6
+
7
+ Measured 2026-09-01 on Linux x64 with Node 24.14.0, an Intel i5-9500, six
8
+ logical CPUs, and 31.2 GiB RAM. The 100- and 1,000-route scales use one warm-up
9
+ and three measured fresh-process samples. The 10,000-route scale records one
10
+ complete full-contract run with no warm-up after two diagnostic runs completed
11
+ the measured stages but exposed cleanup and recovery-timeout harness defects.
12
+ The generated topology contains nine imported modules plus one page per route
13
+ and 1,011 lines per route. Fixture generation is excluded. These are absolute
14
+ candidate measurements, not cross-framework claims.
15
+
16
+ | Routes | Modules / lines | Graph median | TypeScript parse median | Normalize median | Compile/transform median | Render median | Write median | Clean median / RSS | Incremental median / retained-session peak RSS |
17
+ |---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
18
+ | 100 | 1,000 / 101,100 | 1,184.4 ms | 1,796.7 ms | 37.9 ms | 2,428.1 ms | 456.5 ms | 70.4 ms | 7,444.3 ms / 672.3 MiB | 1,838.0 ms / 680.9 MiB |
19
+ | 1,000 | 10,000 / 1,011,000 | 12,152.6 ms | 18,717.6 ms | 302.9 ms | 23,681.5 ms | 4,919.4 ms | 521.7 ms | 77,515.9 ms / 3,182.3 MiB | 18,132.1 ms / 3,281.1 MiB |
20
+ | 10,000 | 100,000 / 10,110,000 | 103,200.9 ms | 232,840.3 ms | 2,350.3 ms | 244,578.3 ms | 44,885.7 ms | 6,690.1 ms | 1,117,753.0 ms / 5,461.0 MiB | 643,697.2 ms / 8,266.9 MiB |
21
+
22
+ The exact 100-route runs are source read `[30.5, 30.3, 24.7]`, graph
23
+ `[1273.8, 1138.8, 1184.4]`, parse `[1749.8, 1911.6, 1796.7]`, normalize
24
+ `[37.2, 37.9, 41.4]`, compile/transform `[2428.1, 2828.6, 2381.1]`, render
25
+ `[516.7, 416.9, 456.5]`, write `[95.3, 53.1, 70.4]`, clean build
26
+ `[7444.3, 7269.2, 8156.1]`, and incremental build
27
+ `[1631.9, 1907.7, 1838.0]` ms. Clean-build RSS is
28
+ `[672.3, 658.6, 675.1]` MiB and retained-session peak RSS is
29
+ `[707.1, 673.9, 680.9]` MiB.
30
+
31
+ The exact 1,000-route runs are source read `[296.7, 315.7, 271.2]`, graph
32
+ `[12152.6, 12308.1, 10011.3]`, parse `[19099.5, 18717.6, 16398.2]`,
33
+ normalize `[259.6, 302.9, 315.8]`, compile/transform
34
+ `[27200.6, 23681.5, 21608.7]`, render `[4919.4, 4454.6, 5238.7]`, write
35
+ `[748.6, 521.7, 487.8]`, clean build `[77515.9, 70196.9, 82980.2]`, and
36
+ incremental build `[22359.7, 18132.1, 17097.2]` ms. Clean-build RSS is
37
+ `[3181.5, 3182.3, 3188.5]` MiB and retained-session peak RSS is
38
+ `[3281.0, 3281.1, 3284.5]` MiB.
39
+
40
+ The complete 10,000-route run records source read `17077.4`, graph `103200.9`,
41
+ TypeScript parse `232840.3`, normalize `2350.3`, compile/transform `244578.3`,
42
+ render `44885.7`, write `6690.1`, clean build `1117753.0`, and incremental
43
+ build `643697.2` ms. Compile-only RSS is 5,561.4 MiB, clean-build RSS is
44
+ 5,461.0 MiB, and retained-session peak RSS is 8,266.9 MiB under
45
+ `--max-old-space-size=10240`.
46
+
47
+ Graph time excludes measured TypeScript parsing. Compile/transform excludes
48
+ measured TypeScript parse and Kudzu normalization, but includes the indivisible
49
+ esbuild parse/transform call for proven import-free modules. Render includes
50
+ provisional page materialization; write includes artifact finalization and
51
+ staged-output promotion. Clean build is an end-to-end wall clock and is not the
52
+ sum of the reported phase boundaries.
53
+
54
+ Every incremental sample recompiles exactly 10 modules, renders one page,
55
+ matches a clean build of the changed source byte-for-byte, rejects invalid
56
+ source in the retained session without changing output, and recovers in that
57
+ same session after source restoration.
58
+ At 100 routes, clean output is 100 files / 21,980 B with digest
59
+ `61525962c70c5e69a975a656781e598cf6665137d648be82f1c3d5e73f0b1b48`;
60
+ the source change produces digest
61
+ `4c7e0f098f3f3236b6e04fa96e8057341c3aa8bdb35a72fe701e78be06160154`.
62
+ At 1,000 routes, clean output is 1,000 files / 221,780 B with digest
63
+ `ccdd2630bcaf9fac4a481b64c69982c341e4798205bb9fbb4cac67d528246635`;
64
+ the source change produces digest
65
+ `024811a5f4598d5025abc57320695503b2d63d0fd6aa54bcf79efde848c2a94e`.
66
+ At 10,000 routes, clean output is 10,000 files / 2,237,780 B with digest
67
+ `7a48bc40ff33c4faaef8a01ab90fcfe611a4bada5364a6fedca42f80ad5070d3`;
68
+ the source change emits 2,237,788 B with digest
69
+ `09a42f84b4ce16c994a8bd55b92e5b645c716168f9290d241cfe27903ccfe98f`.
70
+ Both clean and retained-session failure probes reject invalid source without
71
+ changing the prior deploy and recover to the expected digest.
72
+
73
+ The first full 10,000-route attempt exhausted a 10,240 MiB V8 heap while the
74
+ unbounded canonical module cache retained roughly 90,000 parent-linked
75
+ TypeScript ASTs. Bounding complete canonical records to 1,024 retains stable
76
+ position-based symbols while allowing old ASTs to be collected. The identical
77
+ 100,000-module / 10,110,000-line topology then completed under the same heap cap.
78
+ This adds eight net production compiler lines, no semantic primitive, compiler
79
+ pass, runtime concept, public API, deploy file, or browser byte.
80
+
81
+ ## 0.21.0 Functional Parity Matrix
82
+
83
+ Measured 2026-09-01 on Linux x64 with Node 24.14.0 and required Chrome. The
84
+ 300-test suite passes the maintained content, authentication, forms, CRUD,
85
+ shared-data, large-list, overlay, editor, lazy-load, realtime, error,
86
+ accessibility, and navigation browser journeys. Greenfield `/help`, Apache
87
+ Answer and Memos `/public`, editor `/static`, and the direct 10,000-row route
88
+ remain the corresponding static exclusion controls.
89
+
90
+ The previously benchmark-only 10,000-item pagination decision now runs once as
91
+ ordinary browser acceptance. Enter advances the native control to rows 101-200,
92
+ focus remains on the control, returning to rows 1-100 releases the old row and
93
+ restores fresh input state, the DOM remains bounded to 100 rows, and no browser
94
+ exception occurs. Its deploy contains 19 files totaling 1,900,048 raw / 242,968
95
+ aggregate gzip B with digest
96
+ `1bbaf3479ac90f923deb469c73eb93c0dd7364e7fe906919b167f2f854deda70`.
97
+ The selected pagination route owns 30,143 raw / 11,193 gzip B JavaScript; the
98
+ complete direct 10,000-row HTML control owns 0 B JavaScript. This freezes
99
+ behavior rather than making a new timing claim.
100
+
101
+ No fixture source, compiler, IR, normalization pass, runtime concept, public API,
102
+ or browser artifact changed. One focused browser acceptance test and one
103
+ artifact-baseline entry were added. `npm run check`, required-Chrome 300/300,
104
+ package smoke, and the artifact inventory pass, so no release version is
105
+ consumed.
106
+
107
+ ## 0.20.5 Tooling Cost Validation
108
+
109
+ Measured 2026-09-01 on Linux x64 with Node 24.14.0, OpenCode 1.18.25, and
110
+ `openai/gpt-5.6-sol`. Five interleaved attempts per condition repaired the same
111
+ Apache Answer-derived static React Bootstrap breakpoint under one prompt,
112
+ budget, public context, starter, and acceptance digest. Baseline exposed plain
113
+ `build`; tool-assisted exposed structured `build`, `inspect`, and `explain`.
114
+ Both conditions passed 5/5 with the same 234 raw / 181 gzip B HTML artifact,
115
+ 98.94% byte-identical source retention, and zero browser JavaScript.
116
+
117
+ Baseline total-token samples were `[75485, 75459, 66141, 60644, 61570]`: a
118
+ 66,141 median, 60,644/75,485 range, and 67,860 failure-inclusive tokens per
119
+ success. Tool-assisted samples were `[75983, 87615, 108588, 75828, 75950]`: a
120
+ 75,983 median, 75,828/108,588 range, and 84,793 tokens per success. Structured
121
+ tools therefore cost 16,933 more tokens per success on this task. Monetary cost
122
+ was reported as zero by the subscription provider in every attempt.
123
+
124
+ Baseline versus tool-assisted medians and ranges were: file reads 2 (1/3)
125
+ versus 2 (1/3), tool calls 8 (5/9) versus 9 (8/12), builds 2 (2/2) versus 2
126
+ (2/3), correction cycles 1 (1/1) versus 1 (1/2), and completion time 45,811 ms
127
+ (43,194/46,390) versus 60,736 ms (52,313/76,963). There were no failed
128
+ attempts. This rejects an AI cost-reduction claim for the structured tool bundle
129
+ on this task; it does not remove the independently useful machine-readable
130
+ commands or claim results for other tasks.
131
+
5
132
  ## 0.16.14 Fair AI Delivery Evidence
6
133
 
7
134
  Measured 2026-09-01 on Linux x64 with Node 24.14.0. The deterministic protocol
package/README.md CHANGED
@@ -14,7 +14,7 @@ Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTM
14
14
 
15
15
  > Experimental `0.16.x`: the compiler API and supported TSX surface may change.
16
16
 
17
- **Latest release: 0.16.14 - Fair AI delivery evidence.** The repository-owned AI delivery runner now pins equal Kudzu and React+Vite conditions, preserves successful and failed attempts, and records attribution, cost, source retention, acceptance, and browser artifacts without claiming a framework winner. Read the [release notes](./RELEASES.md#01614---fair-ai-delivery-evidence), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.16.14), or follow the [architecture packet](./docs/next-architecture/README.md).
17
+ **Latest release: 0.16.16 - Bounded compiler module cache.** Kudzu now completes the full 10,000-route, 100,000-module source-scale contract under a 10 GiB V8 heap by bounding retained canonical TypeScript AST records. Read the [release notes](./RELEASES.md#01616---bounded-compiler-module-cache), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.16.16), 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,73 @@
1
1
  # Kudzu Releases
2
2
 
3
+ ## 0.16.16 - Bounded Compiler Module Cache
4
+
5
+ Kudzu 0.16.16 bounds canonical TypeScript AST retention so the complete
6
+ 10,000-route production-scale contract runs under a 10 GiB V8 heap.
7
+
8
+ ### Changed in 0.16.16
9
+
10
+ - Bounds complete canonical module records to a 1,024-entry LRU while preserving
11
+ stable position-based module symbols and reparsing evicted source on demand.
12
+ - Fixes the measured 10,000-route failure where roughly 90,000 retained
13
+ parent-linked TypeScript ASTs exhausted a 10,240 MiB heap.
14
+ - Completes the identical 100,000-module / 10,110,000-line topology with 5,461.0
15
+ MiB clean-build RSS and 8,266.9 MiB retained-session peak RSS.
16
+ - Verifies 10-module / one-page incremental scope, byte-identical changed-clean
17
+ output, deterministic digests, and clean and retained-session recovery.
18
+ - Adds scale-aware recovery timeout, diagnostic stage progress, and bounded
19
+ temporary-fixture cleanup retries to the maintained benchmark harness.
20
+ - Adds eight net production compiler lines, no semantic primitive, compiler
21
+ pass, runtime concept, application API, dependency, deploy artifact, or
22
+ browser byte.
23
+ - Updates `create-kudzu@0.1.141` to generate projects on
24
+ `@kudzujs/core@^0.16.16`.
25
+
26
+ ### Upgrade
27
+
28
+ ```sh
29
+ npm install @kudzujs/core@^0.16.16
30
+ ```
31
+
32
+ ## 0.16.15 - Production Evidence Gates
33
+
34
+ Kudzu 0.16.15 turns compiler scale, large-list parity, and AI attribution gaps
35
+ into maintained executable evidence instead of release-time assumptions.
36
+
37
+ ### Changed in 0.16.15
38
+
39
+ - Adds opt-in internal source-read, graph, TypeScript parse, normalization,
40
+ compile/transform, render, and write timing to the existing project session.
41
+ - Extends `npm run benchmark:source-scale` with retained-session incremental
42
+ timing and RSS, clean changed-source equivalence, output digests, and clean
43
+ and retained-session failure recovery.
44
+ - Records repeated 100-route / 1,000-module and 1,000-route / 10,000-module
45
+ measurements. Every incremental sample recompiles 10 modules and renders one
46
+ page while matching a clean changed-source build byte-for-byte.
47
+ - Keeps the full 10,000-route / 100,000-module run explicitly pending a
48
+ separately provisioned host; no projection or reduced fixture is called a
49
+ pass.
50
+ - Promotes the 10,000-item pagination decision to ordinary Chrome acceptance,
51
+ including Enter navigation, focus retention, bounded 100-row DOM, state
52
+ release, and a zero-JavaScript direct-list control.
53
+ - Marks missing AI attribution traces incomplete and withholds token and cost
54
+ per-success claims instead of treating missing data as zero.
55
+ - Records the equal-condition OpenCode tooling trial: both conditions passed
56
+ 5/5, while structured tools used 16,933 more tokens per success, so no AI cost
57
+ reduction is claimed.
58
+ - Adds no semantic primitive, compiler pass, runtime concept, application API,
59
+ dependency, deploy artifact, or browser byte.
60
+ - Passes `npm run check`, required-Chrome 300/300, package smoke, tarball
61
+ inspection, and both npm publish dry-runs on the exact versioned tree.
62
+ - Updates `create-kudzu@0.1.140` to generate projects on
63
+ `@kudzujs/core@^0.16.15`.
64
+
65
+ ### Upgrade
66
+
67
+ ```sh
68
+ npm install @kudzujs/core@^0.16.15
69
+ ```
70
+
3
71
  ## 0.16.14 - Fair AI Delivery Evidence
4
72
 
5
73
  Kudzu 0.16.14 adds a repository-owned protocol and runner for equal-condition,
@@ -15,7 +15,7 @@ The completed `0.9.0` milestone is recorded in [`0.9-semantic-compression.md`](.
15
15
 
16
16
  [`1.0-large-application-compatibility-audit.md`](./1.0-large-application-compatibility-audit.md) records the first post-0.9 probes against Memos, Apache Answer, and Actual Budget. The audit finds that reduced slices build but whole-application source retention and behavior parity do not yet pass.
17
17
 
18
- [`application-capability-release-plan.md`](./application-capability-release-plan.md) is the authoritative post-0.9 execution queue, currently at `0.20.5`. It assigns one application-capability section to each minor release and one independently accepted evidence packet to each patch release from `0.10.0` through the `1.0.0` gate. It supersedes the provisional 0.10/0.11/0.12 tool-first ordering in the completed 0.9 handoff without rewriting that historical record.
18
+ [`application-capability-release-plan.md`](./application-capability-release-plan.md) is the authoritative post-0.9 execution queue, currently at `0.21.2`. It assigns one application-capability section to each minor release and one independently accepted evidence packet to each patch release from `0.10.0` through the `1.0.0` gate. It supersedes the provisional 0.10/0.11/0.12 tool-first ordering in the completed 0.9 handoff without rewriting that historical record.
19
19
 
20
20
  ## Required Invariants
21
21
 
@@ -1931,6 +1931,19 @@ required-Chrome suites pass 297/297 tests, and package smoke passes.
1931
1931
  - **Done condition:** useful tools are retained and non-improving tools are
1932
1932
  removed or deferred.
1933
1933
 
1934
+ Measured on 2026-09-01 with five interleaved attempts per condition against one
1935
+ Apache Answer-derived static Bootstrap correction. Both conditions passed 5/5
1936
+ with identical accepted behavior, source retention, and browser artifacts, but
1937
+ plain-build baseline cost 67,860 tokens per success while structured
1938
+ build/inspect/explain cost 84,793. The structured bundle is therefore deferred
1939
+ as an AI default rather than credited with a cost reduction. Existing JSON,
1940
+ inspection, and explanation commands remain for their independently accepted
1941
+ machine-readable contracts; no speculative `fix` command, compiler pass,
1942
+ runtime concept, application API, dependency, or browser byte was added. Exact
1943
+ samples, medians, and ranges are recorded in `PERFORMANCE.md`, while the pinned
1944
+ protocol reproduces and retains raw attempt evidence under the ignored
1945
+ `test-results/ai-delivery/` path.
1946
+
1934
1947
  ## `0.21.x`: Production-Scale Proof
1935
1948
 
1936
1949
  ### `0.21.0`: Functional Parity Matrix
@@ -1942,6 +1955,28 @@ required-Chrome suites pass 297/297 tests, and package smoke passes.
1942
1955
  - **Done condition:** every claimed capability has a browser journey and static
1943
1956
  exclusion control.
1944
1957
 
1958
+ **Result:** closed through existing application semantics without a release.
1959
+ The required-Chrome 300-test matrix passes content, authentication, forms, CRUD,
1960
+ shared data, large lists, overlays, editor ownership, lazy loading, realtime,
1961
+ errors, accessibility, and navigation across the maintained greenfield, Apache
1962
+ Answer, Memos, and focused package fixtures. The one material matrix gap was the
1963
+ 10,000-item pagination decision: its release/remount behavior existed only in an
1964
+ optional benchmark. One ordinary browser acceptance now proves Enter-key page
1965
+ advance, focus retention, the 101-200 and restored 1-100 ranges, bounded 100-row
1966
+ DOM, fresh off-range input state, and no browser exceptions. Greenfield `/help`,
1967
+ Answer and Memos `/public`, package `/static` routes, and the complete direct
1968
+ 10,000-row route provide zero-JavaScript controls.
1969
+
1970
+ The artifact inventory now includes the large-list fixture: 19 files,
1971
+ 1,900,048 raw / 242,968 aggregate gzip bytes, deploy SHA-256
1972
+ `1bbaf3479ac90f923deb469c73eb93c0dd7364e7fe906919b167f2f854deda70`.
1973
+ Pagination owns 30,143 raw / 11,193 gzip bytes of existing JavaScript while the
1974
+ direct static route owns zero. Semantic primitives, IR kinds, compiler passes,
1975
+ production compiler/runtime LOC, normalization rules, adapters, runtime
1976
+ concepts, public APIs, and browser artifacts change by zero. `npm run check`,
1977
+ required-Chrome 300/300, package smoke, focused acceptance, and artifact
1978
+ inventory pass. No production feature changed, so no release is consumed.
1979
+
1945
1980
  ### `0.21.1`: Compiler And Route Scale
1946
1981
 
1947
1982
  - **Purpose:** measure clean/incremental compilation and artifact emission.
@@ -1952,6 +1987,44 @@ required-Chrome suites pass 297/297 tests, and package smoke passes.
1952
1987
  - **Done condition:** repeated measurements and all material regressions are
1953
1988
  explained or fixed.
1954
1989
 
1990
+ **Result:** opt-in internal telemetry records source reads, reachable
1991
+ graph discovery, TypeScript parse, normalize, compile/transform, render, and
1992
+ write boundaries without changing deploy output. Compile/transform excludes
1993
+ the measured TypeScript parse and Kudzu normalization but includes indivisible
1994
+ esbuild parse/transform for proven import-free modules. Render includes
1995
+ provisional page materialization, write includes finalization and staged-output
1996
+ promotion, and the end-to-end clean build is not their sum. The runner also proves that an
1997
+ incremental source edit matches a clean build of the changed source, compares
1998
+ paired incremental outputs when a baseline is supplied, names retained-session
1999
+ rather than incremental-only peak RSS, and fails the process when either clean
2000
+ or retained-session invalid-source recovery changes output. This adds no
2001
+ semantic primitive, compiler pass, runtime concept, public API, deploy artifact,
2002
+ or browser byte; production compiler/build instrumentation is 35 added and four
2003
+ removed lines.
2004
+
2005
+ One warm-up and three fresh-process samples pass at 100 routes / 1,000 modules /
2006
+ 101,100 lines and 1,000 routes / 10,000 modules / 1,011,000 lines. Clean-build
2007
+ medians are 7,444.3 and 77,515.9 ms with 672.3 and 3,182.3 MiB peak RSS;
2008
+ incremental medians are 1,838.0 and 18,132.1 ms, recompiling exactly 10 modules
2009
+ and rendering one page in every sample. Clean and changed digests differ,
2010
+ incremental output equals a clean changed-source build, and clean and retained
2011
+ failure probes preserve then recover the expected digest. Exact phase samples,
2012
+ bytes, and digests are recorded in `PERFORMANCE.md`.
2013
+
2014
+ The full 10,000-route / 100,000-module / 10,110,000-line topology initially
2015
+ exhausted a 10,240 MiB V8 heap because the canonical module cache retained about
2016
+ 90,000 complete TypeScript ASTs. A 1,024-record LRU bounds that existing cache
2017
+ without changing stable position-based symbols. The identical topology then
2018
+ completed under the same heap cap with 5,461.0 MiB clean-build RSS and 8,266.9
2019
+ MiB retained-session peak RSS. It emits 10,000 files / 2,237,780 B with clean
2020
+ digest `7a48bc40ff33c4faaef8a01ab90fcfe611a4bada5364a6fedca42f80ad5070d3`;
2021
+ incremental output matches a clean changed-source build, recompiles 10 modules,
2022
+ renders one page, and clean and retained recovery pass. One complete measured
2023
+ run is retained after two diagnostic runs completed measured stages but exposed
2024
+ cleanup and timeout defects; no projection or reduced topology is counted.
2025
+ The memory fix adds eight net production lines, no semantic primitive, pass,
2026
+ runtime concept, public API, deploy artifact, or browser byte.
2027
+
1955
2028
  ### `0.21.2`: Browser Performance And Memory
1956
2029
 
1957
2030
  - **Purpose:** protect interaction latency and long-running stability.
@@ -2122,3 +2195,6 @@ release transaction where possible or document and publish a forward-fix patch.
2122
2195
  | `0.20.2` | Released as `0.16.13` | Preserve exact emitted-route lookup, authored provenance, semantic ownership, capability/artifact byte reasons and hashes, bounded deterministic output, structured missing-route diagnostics, and zero-JavaScript explanation. | Patch release retained the `0.16.x` public version line |
2123
2196
  | `0.20.3` | Deferred by evidence gate | Resume only after recorded AI trials prove one repeated correction safe and useful with a stable diagnostic code and compiler-proven preconditions. | No recorded AI trials; no production change or release consumed |
2124
2197
  | `0.20.4` | Released as `0.16.14` | Preserve pinned equal conditions, isolated paired attempts, raw failures, independent acceptance, attribution, failure-inclusive costs, source retention, and browser artifact evidence. | Deterministic fixture validates the protocol only; no framework ranking claimed |
2198
+ | `0.20.5` | Closed by measured stop condition | Preserve the negative tooling-cost result and do not present structured tools as an AI cost reduction. | Tool-assisted attempts cost 16,933 more tokens per success; no release consumed |
2199
+ | `0.21.0` | Closed by existing semantics | Preserve the complete browser parity matrix, large-list keyboard/release acceptance, and static exclusion controls. | No production change; no release consumed |
2200
+ | `0.21.1` | Released as `0.16.16` | Preserve 100/1,000/10,000-route phase, RSS, output, digest, incremental-equivalence, recovery, and bounded canonical-AST retention evidence. | Full 10,000-route report has one complete measured run after two measured-stage diagnostics; no projection used |
@@ -1,6 +1,6 @@
1
1
  # Current Compiler Architecture
2
2
 
3
- This maps the current `0.16.14` architecture, built on the completed `0.9.0` semantic-compression release and `0.8.23` Goal A compiler foundation. The active application packet is `0.20.5`; file and function names are the stable references, while line numbers are intentionally omitted because later work may still move code.
3
+ This maps the current `0.16.16` architecture, built on the completed `0.9.0` semantic-compression release and `0.8.23` Goal A compiler foundation. The active application packet is `0.21.2`; file and function names are the stable references, while line numbers are intentionally omitted because later work may still move code.
4
4
 
5
5
  ## Responsibility Map
6
6
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Status
4
4
 
5
- Completed compiler-foundation record and longer-term plan after `0.8.35`. The [`0.9-semantic-compression.md`](./0.9-semantic-compression.md) execution queue is complete. The active queue for current work is [`application-capability-release-plan.md`](./application-capability-release-plan.md) at packet `0.20.5`. This document does not mark any remaining planned capability as supported and does not authorize a React runtime, VDOM, hydration, retained browser component tree, generic rerenderer, public store/query/resource API, SPA router, or islands.
5
+ Completed compiler-foundation record and longer-term plan after `0.8.35`. The [`0.9-semantic-compression.md`](./0.9-semantic-compression.md) execution queue is complete. The active queue for current work is [`application-capability-release-plan.md`](./application-capability-release-plan.md) at packet `0.21.2`. This document does not mark any remaining planned capability as supported and does not authorize a React runtime, VDOM, hydration, retained browser component tree, generic rerenderer, public store/query/resource API, SPA router, or islands.
6
6
 
7
- [`MIGRATION_ROADMAP.md`](../../MIGRATION_ROADMAP.md) remains the product authority for product invariants and fixture-driven feature selection. [`application-capability-release-plan.md`](./application-capability-release-plan.md) is authoritative for current work order and evidence at packet `0.20.5`; this plan retains the completed foundation, deferred program, and long-term production gates. If implementation evidence changes either boundary, update the relevant document before broadening a patch.
7
+ [`MIGRATION_ROADMAP.md`](../../MIGRATION_ROADMAP.md) remains the product authority for product invariants and fixture-driven feature selection. [`application-capability-release-plan.md`](./application-capability-release-plan.md) is authoritative for current work order and evidence at packet `0.21.2`; this plan retains the completed foundation, deferred program, and long-term production gates. If implementation evidence changes either boundary, update the relevant document before broadening a patch.
8
8
 
9
9
  ## Product Outcome
10
10
 
@@ -483,4 +483,4 @@ The first comparison is Kudzu versus React + Vite using the same agent, model, t
483
483
 
484
484
  ## Immediate Decision
485
485
 
486
- All listed foundation and `0.9` slices are complete. Current work continues at `0.20.5` tooling cost validation under the [`application-capability-release-plan.md`](./application-capability-release-plan.md); keep ResourceIR limited to qualifying independent fixtures, and do not add range ownership, virtualization, optimistic transactions, a public adapter/store API, or a router before evidence justifies them.
486
+ All listed foundation and `0.9` slices are complete. Current work continues at `0.21.2` browser performance and memory under the [`application-capability-release-plan.md`](./application-capability-release-plan.md); keep ResourceIR limited to qualifying independent fixtures, and do not add range ownership, virtualization, optimistic transactions, a public adapter/store API, or a router before evidence justifies them.
@@ -1,6 +1,6 @@
1
1
  # Planned Version Sequence
2
2
 
3
- This is an execution sequence, not release history. `0.8.16` through `0.8.62` are completed scopes represented by package/release records. The `0.10.0` through `1.0.0` minor/patch sequence is maintained in [`application-capability-release-plan.md`](./application-capability-release-plan.md), currently at `0.20.5`; that plan supersedes the provisional tool-first 0.10/0.11/0.12 ordering in the completed 0.9 handoff.
3
+ This is an execution sequence, not release history. `0.8.16` through `0.8.62` are completed scopes represented by package/release records. The `0.10.0` through `1.0.0` minor/patch sequence is maintained in [`application-capability-release-plan.md`](./application-capability-release-plan.md), currently at `0.21.2`; that plan supersedes the provisional tool-first 0.10/0.11/0.12 ordering in the completed 0.9 handoff.
4
4
 
5
5
  Keep each patch behavior-preserving and independently reviewable. If a boundary proves inseparable, revise this plan before combining releases; do not silently broaden a patch.
6
6
 
@@ -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.139` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.16.14`.
69
+ `create-kudzu@0.1.141` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.16.16`.
70
70
 
71
71
  ## Release Boundary
72
72
 
@@ -60,7 +60,9 @@ export async function buildWithSession(project, { changedFiles, quiet = false, m
60
60
  await recoverOutput(outputDirectory, backupOutput)
61
61
  await rm(stagedOutput, { recursive: true, force: true })
62
62
  const { result, pageCount, behaviorCount, cache, inspectionData, explanation } = await buildInto(project, stagedOutput, { changedFiles, minify, quiet, retainCache, explanationRoute })
63
+ const promoteStarted = project.timings ? performance.now() : 0
63
64
  await promoteOutput(stagedOutput, outputDirectory, backupOutput)
65
+ addTiming(project.timings, "writeMs", promoteStarted)
64
66
  project.buildCache = retainCache ? cache : undefined
65
67
  if (!quiet) console.log(`Built ${pageCount} page(s), ${behaviorCount} interactive page(s) into dist/`)
66
68
  return explanationRoute ? explanation : inspection ? createInspectionReport(inspectionData) : result
@@ -110,6 +112,7 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
110
112
  await mkdir(workDirectory, { recursive: true })
111
113
  await mkdir(outputDirectory, { recursive: true })
112
114
 
115
+ const sourceReadStarted = project.timings ? performance.now() : 0
113
116
  const projectFiles = await walk(sourceDirectory)
114
117
  const allSourceFiles = projectFiles.filter(file => /\.(?:ts|tsx)$/.test(file) && !file.endsWith(".d.ts")).sort()
115
118
  const configuredStyleSources = new Set(configuredStyles.sources.map(style => style.source))
@@ -118,10 +121,13 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
118
121
  const sourceIndex = project.sourceIndex
119
122
  for (const file of sourceIndex.keys()) if (file.startsWith(`${sourceDirectory}${sep}`) && !allSourceFileSet.has(file)) sourceIndex.delete(file)
120
123
  for (const [file, source] of await Promise.all(allSourceFiles.map(async file => [file, await readFile(file, "utf8")]))) sourceIndex.set(file, source)
124
+ addTiming(project.timings, "sourceReadMs", sourceReadStarted)
121
125
  const pageFiles = allSourceFiles.filter(file => file.startsWith(`${pagesDirectory}${sep}`) && file.endsWith(".tsx"))
122
126
  if (!pageFiles.length) throw new Error("No pages found in src/pages/")
127
+ const graphStarted = project.timings ? performance.now() : 0
123
128
  const pageSources = new Map(pageFiles.map(file => [file, new Set(reachableSourceFiles([file], allSourceFileSet, sourceIndex))]))
124
129
  const sourceFiles = [...new Set([...pageSources.values()].flatMap(files => [...files]))].sort()
130
+ addTiming(project.timings, "graphMs", graphStarted)
125
131
  const compatibility = createCompatibilityReport(sourceFiles.map(file => ({ file: relative(root, file).replaceAll(sep, "/"), source: sourceIndex.get(file) })))
126
132
  await writePrettyJson(join(workDirectory, "kudzu-compatibility.json"), compatibility)
127
133
  const sourceFileSet = project.sourceFiles
@@ -193,6 +199,7 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
193
199
  const routePageFiles = new Map()
194
200
  let renderedPages = 0
195
201
 
202
+ const renderStarted = project.timings ? performance.now() : 0
196
203
  for (const pageFile of pageFiles) {
197
204
  const cached = !affectedPages.has(pageFile) ? previous?.pageRenders.get(pageFile) : undefined
198
205
  if (cached) {
@@ -328,7 +335,9 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
328
335
  rewrites: rewrites.slice(rewriteOffset)
329
336
  })
330
337
  }
338
+ addTiming(project.timings, "renderMs", renderStarted)
331
339
 
340
+ const writeStarted = project.timings ? performance.now() : 0
332
341
  for (const group of navigationGroups) for (const route of group.routes) if (!emittedApplicationRoutes.has(route)) throw new Error(`${group.label} route ${JSON.stringify(route)} is not an emitted route`)
333
342
  rejectNavigationOverlap(navigationGroups)
334
343
  for (const group of navigationGroups) {
@@ -541,6 +550,7 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
541
550
  if (typeof config.afterBuild !== "function") throw new Error("kudzu.config afterBuild must be a function")
542
551
  await config.afterBuild({ root, outDir: outputDirectory, sourceDir: sourceDirectory, base, routes: plans.map(plan => plan.route), plans, rewrites: sortedRewrites, artifacts })
543
552
  }
553
+ addTiming(project.timings, "writeMs", writeStarted)
544
554
 
545
555
  let explanation
546
556
  if (explanationRoute) {
@@ -563,6 +573,10 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
563
573
  }
564
574
  }
565
575
 
576
+ function addTiming(timings, name, started) {
577
+ if (timings) timings[name] = (timings[name] ?? 0) + performance.now() - started
578
+ }
579
+
566
580
  function affectedPageFiles({ changedFiles, pageFiles, pageSources, previous, sourceDirectory }) {
567
581
  if (!previous || changedFiles === undefined) return new Set(pageFiles)
568
582
  if (changedFiles.some(file => typeof file !== "string")) return new Set(pageFiles)
@@ -5,13 +5,15 @@ import { assetPath } from "./path-helpers.mjs"
5
5
  import { createSourceGraph } from "./source-graph.mjs"
6
6
  import { createWorkerCompiler } from "./worker-compiler.mjs"
7
7
 
8
- export function createProjectSession(projectRoot = process.cwd(), { counters, sourceIndex = new Map() } = {}) {
8
+ export function createProjectSession(projectRoot = process.cwd(), { counters, sourceIndex = new Map(), timings } = {}) {
9
9
  const root = resolve(projectRoot)
10
10
  const sourceDirectory = join(root, "src")
11
11
  const graph = createSourceGraph(root)
12
- const modules = createModuleCache(root, sourceIndex, graph, counters)
12
+ if (timings && !ts.performance.isEnabled()) ts.performance.enable()
13
+ const modules = createModuleCache(root, sourceIndex, graph, counters, timings)
13
14
  return {
14
15
  counters,
16
+ timings,
15
17
  root,
16
18
  sourceDirectory,
17
19
  pagesDirectory: join(sourceDirectory, "pages"),
@@ -25,7 +27,8 @@ export function createProjectSession(projectRoot = process.cwd(), { counters, so
25
27
  }
26
28
  }
27
29
 
28
- function createModuleCache(root, sourceIndex, graph, counters) {
30
+ function createModuleCache(root, sourceIndex, graph, counters, timings) {
31
+ const recordLimit = 1024
29
32
  const records = new Map()
30
33
  let resolvedExports = new WeakMap()
31
34
  const moduleName = file => relative(root, file).replaceAll(sep, "/")
@@ -44,13 +47,21 @@ function createModuleCache(root, sourceIndex, graph, counters) {
44
47
  const read = (file, source = sourceIndex.get(file)) => {
45
48
  if (typeof source !== "string") throw new Error(`Source text is unavailable for ${file}`)
46
49
  const cached = records.get(file)
47
- if (cached?.source === source) return cached
50
+ if (cached?.source === source) {
51
+ records.delete(file)
52
+ records.set(file, cached)
53
+ return cached
54
+ }
55
+ const parseBefore = timings ? ts.performance.getDuration("Parse") : 0
48
56
  const sourceFile = graph.parseSourceFile(file, source)
57
+ if (timings) timings.parseMs = (timings.parseMs ?? 0) + ts.performance.getDuration("Parse") - parseBefore
49
58
  increment("parsedModules")
50
59
  const summary = summarizeModule(file, sourceFile, moduleSymbol, siteId)
51
60
  increment("exportSummaries")
52
61
  const record = { source, sourceFile, ...summary }
62
+ records.delete(file)
53
63
  records.set(file, record)
64
+ if (records.size > recordLimit) records.delete(records.keys().next().value)
54
65
  resolvedExports = new WeakMap()
55
66
  return record
56
67
  }
@@ -28,7 +28,7 @@ import { ownedLazyPackageImport } from "./source-graph.mjs"
28
28
  import { createZustandPass } from "./zustand-pass.mjs"
29
29
 
30
30
  export function createSourceCompiler(project) {
31
- const { root, sourceDirectory, pagesDirectory, workDirectory, workerCompiler, modules, counters } = project
31
+ const { root, sourceDirectory, pagesDirectory, workDirectory, workerCompiler, modules, counters, timings } = project
32
32
  const buildDirectory = project.buildDirectory ?? workDirectory
33
33
  const { ordinaryRuntimeDependencies, resolveSourceImport, runtimeModuleReference } = project.graph
34
34
  const parseSourceFile = (file, source) => modules.read(file, source).sourceFile
@@ -42,6 +42,13 @@ async function compileSourceAsync(file, sourceFiles, sourceIndex, staticFiles, c
42
42
  }
43
43
 
44
44
  function compileSource(file, sourceFiles, sourceIndex, staticFiles, cssModules, base, importFreeOutput) {
45
+ const parseBefore = timings?.parseMs ?? 0
46
+ const typeScriptParseBefore = timings ? ts.performance.getDuration("Parse") : 0
47
+ const finishTiming = () => {
48
+ if (!timings) return
49
+ const recordedParse = (timings.parseMs ?? 0) - parseBefore
50
+ timings.parseMs = (timings.parseMs ?? 0) + Math.max(0, ts.performance.getDuration("Parse") - typeScriptParseBefore - recordedParse)
51
+ }
45
52
  const importedAssets = new Set()
46
53
  const source = sourceIndex.get(file)
47
54
  const semantic = createSemanticArtifact(relative(root, file).replaceAll(sep, "/"))
@@ -74,6 +81,7 @@ function compileSource(file, sourceFiles, sourceIndex, staticFiles, cssModules,
74
81
  const moduleHandlers = moduleIR.handlers.filter(handler => handler.kind === "module-export")
75
82
  if (!moduleHandlers.length && !moduleIR.bindings.length) {
76
83
  normalizeModulePaths(moduleIR)
84
+ finishTiming()
77
85
  return sourceResult
78
86
  }
79
87
  const moduleSource = printHandlerModule({ moduleIR, handlerPath })
@@ -85,6 +93,7 @@ function compileSource(file, sourceFiles, sourceIndex, staticFiles, cssModules,
85
93
  if (moduleErrors.length) throw new Error(moduleErrors.map(error => ts.flattenDiagnosticMessageText(error.messageText, "\n")).join("\n"))
86
94
  normalizeModulePaths(moduleIR)
87
95
  sourceResult.handlerModule = { path: handlerPath, code: moduleResult.outputText, hasNativeHandlers: moduleHandlers.some(handler => handler.role === "native"), hasEffects: moduleHandlers.some(handler => handler.role === "effect"), clientImports: moduleIR.clientModules, hasPackageImports: moduleIR.imports.some(entry => entry.package) }
96
+ finishTiming()
88
97
  return sourceResult
89
98
  }
90
99
 
@@ -358,7 +367,9 @@ function createKudzuTransformer({ semantic, handlerUrl, file, sourceFiles, sourc
358
367
  const importedStaticCollections = importedSerializableCollections(sourceFile, file, sourceFiles, sourceIndex, true)
359
368
  const importedCollections = new Set(importedStaticCollections.keys())
360
369
  const importedFallbackCollections = importedSerializableCollections(sourceFile, file, sourceFiles, sourceIndex)
370
+ const normalizeStarted = timings ? performance.now() : 0
361
371
  const normalized = normalizeCompilerSource(sourceFile, { base, context, file, importedCollections, importedFallbackCollections, importedStaticCollections, sourceFiles, sourceIndex })
372
+ if (timings) timings.normalizeMs = (timings.normalizeMs ?? 0) + performance.now() - normalizeStarted
362
373
  sourceFile = normalized.sourceFile
363
374
  const { customHookTimerStates } = normalized
364
375
  const bindingIndex = createBindingIndex(sourceFile)
@@ -417,7 +428,9 @@ function createKudzuTransformer({ semantic, handlerUrl, file, sourceFiles, sourc
417
428
  const importedSource = target => {
418
429
  let result = importedSourceCache.get(target)
419
430
  if (!result) {
431
+ const normalizeStarted = timings ? performance.now() : 0
420
432
  result = normalizeCompilerSource(modules.clone(target, context.factory, context), { base, context, file: target, sourceFiles, sourceIndex })
433
+ if (timings) timings.normalizeMs = (timings.normalizeMs ?? 0) + performance.now() - normalizeStarted
421
434
  importedSourceCache.set(target, result)
422
435
  }
423
436
  return result.sourceFile
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kudzujs/core",
3
- "version": "0.16.14",
3
+ "version": "0.16.16",
4
4
  "description": "HTML-first TSX framework with synchronous state semantics and no virtual DOM",
5
5
  "type": "module",
6
6
  "license": "MIT",