@kudzujs/core 0.16.12 → 0.16.14

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.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.
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.
61
61
 
62
62
  ### 0.10.0 Through 0.21.x: Application Capability Release Train
63
63
 
package/PERFORMANCE.md CHANGED
@@ -1,6 +1,33 @@
1
1
  # Performance Records
2
2
 
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.
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
+
5
+ ## 0.16.14 Fair AI Delivery Evidence
6
+
7
+ Measured 2026-09-01 on Linux x64 with Node 24.14.0. The deterministic protocol
8
+ fixture records two interleaved attempts per variant, including one success and
9
+ one retained failure each. Both variants therefore report a 50% fixture success
10
+ rate, 50 nanos median successful cost, and 100 nanos total cost per success when
11
+ failed attempts remain in the numerator. Successful artifacts are one 63 raw /
12
+ 66 gzip B HTML file with digest
13
+ `0d22f579d793d0034c967c7ffa08e0b2c377bc36c959c7b4bafab587fd5dda60`.
14
+ This validates evidence accounting only and is not a model-driven framework
15
+ comparison. Compiler passes, runtime concepts, representative deploy output, and
16
+ browser bytes are unchanged. Browser-disabled and required-Chrome suites pass
17
+ 297/297 tests, package smoke passes, and the runner adds no dependency.
18
+
19
+ ## 0.16.13 Route Artifact Explanations
20
+
21
+ Measured 2026-09-01 on Linux x64 with Node 24.14.0. Route explanation is a
22
+ build-time projection over existing route, source, compatibility, ownership,
23
+ capability, and artifact records. Representative deploy manifests and hashes
24
+ remain unchanged. The maintained Worker graph remains 907 raw / 477 gzip B and
25
+ the window graph remains 14,456 raw / 6,160 gzip B. Seven clean builds record a
26
+ 605 ms median on this host without a timing comparison. Browser-disabled and
27
+ required-Chrome suites pass 296/296 tests, package smoke passes, and focused CLI
28
+ coverage includes an effect-owned Worker route, configured base, exact missing
29
+ route diagnostic, deterministic output, artifact hashes, and zero-JavaScript
30
+ static exclusion.
4
31
 
5
32
  ## 0.16.12 Bounded Application Inspection
6
33
 
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.12 - Bounded application inspection.** `kudzu inspect --json` now projects reachable modules, routes, packages, capabilities, semantic owners, and first blockers from the existing build graph in deterministic bounded output without dumping raw IR. Read the [release notes](./RELEASES.md#01612---bounded-application-inspection), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.16.12), or follow the [architecture packet](./docs/next-architecture/README.md).
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).
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,66 @@
1
1
  # Kudzu Releases
2
2
 
3
+ ## 0.16.14 - Fair AI Delivery Evidence
4
+
5
+ Kudzu 0.16.14 adds a repository-owned protocol and runner for equal-condition,
6
+ fully retained Kudzu and React+Vite delivery attempts.
7
+
8
+ ### Changed in 0.16.14
9
+
10
+ - Adds `npm run benchmark:ai-delivery`, backed only by Node standard-library
11
+ process, hash, filesystem, timing, and compression APIs.
12
+ - Pins model revision, pricing, tool permissions, prompt, budgets, adapter,
13
+ acceptance command, starter trees, public context, and paired attempt order.
14
+ - Runs every attempt in an isolated starter copy, then independently reruns the
15
+ declared build and framework-neutral acceptance command.
16
+ - Preserves raw adapter/build/acceptance output, final authored source, browser
17
+ artifacts, hashes, token/cost/tool/file/build metrics, and source retention.
18
+ - Includes deliberate failures in the evidence and total cost-per-success
19
+ numerator rather than cherry-picking successful attempts.
20
+ - Adds no compiler pass, semantic primitive, runtime concept, application API,
21
+ dependency, or browser byte.
22
+ - Uses a deterministic fixture only to validate the protocol. It does not claim
23
+ that Kudzu outperforms React+Vite; measured tooling-cost validation remains the
24
+ next packet.
25
+ - Updates `create-kudzu@0.1.139` to generate projects on
26
+ `@kudzujs/core@^0.16.14`.
27
+
28
+ ### Upgrade
29
+
30
+ ```sh
31
+ npm install @kudzujs/core@^0.16.14
32
+ ```
33
+
34
+ ## 0.16.13 - Route Artifact Explanations
35
+
36
+ Kudzu 0.16.13 lets tools ask why one exact emitted route owns its browser bytes
37
+ without reading raw semantic records or reconstructing an artifact graph.
38
+
39
+ ### Changed in 0.16.13
40
+
41
+ - Adds `kudzu explain --route <route> --json`, which runs the authoritative build
42
+ and projects authored source, normalization provenance, semantic owners,
43
+ capability facts, selected artifacts, and byte reasons for one emitted route.
44
+ - Reports raw and gzip byte totals plus SHA-256 hashes for runtime, handler,
45
+ transitive chunk, stylesheet, and Worker artifacts already selected by the
46
+ existing route artifact report.
47
+ - Explains zero-JavaScript routes from an absent behavior runtime family and an
48
+ empty compiler-selected JavaScript closure.
49
+ - Uses exact configured-base route matching and returns the structured
50
+ `explain.route.not-found` diagnostic for missing routes.
51
+ - Sorts every bounded section before truncation and excludes HTML, generated
52
+ code, RouteIR, ModuleIR, captures, and state values.
53
+ - Adds no analyzer, semantic primitive, compiler pass, runtime concept, public
54
+ application API, or browser byte.
55
+ - Updates `create-kudzu@0.1.138` to generate projects on
56
+ `@kudzujs/core@^0.16.13`.
57
+
58
+ ### Upgrade
59
+
60
+ ```sh
61
+ npm install @kudzujs/core@^0.16.13
62
+ ```
63
+
3
64
  ## 0.16.12 - Bounded Application Inspection
4
65
 
5
66
  Kudzu 0.16.12 lets tools select the first migration blocker from a compact
package/bin/kudzu.mjs CHANGED
@@ -6,27 +6,34 @@ import { fileURLToPath } from "node:url"
6
6
 
7
7
  const command = process.argv[2] ?? "dev"
8
8
 
9
- if ((command === "build" || command === "inspect") && !process.env.KUDZU_BUILD_CHILD) {
9
+ if ((command === "build" || command === "inspect" || command === "explain") && !process.env.KUDZU_BUILD_CHILD) {
10
10
  const child = spawnSync(process.execPath, ["--expose-gc", "--max-semi-space-size=8", fileURLToPath(import.meta.url), ...process.argv.slice(2)], {
11
11
  stdio: "inherit",
12
12
  env: { ...process.env, KUDZU_BUILD_CHILD: "1" }
13
13
  })
14
14
  if (child.error) throw child.error
15
15
  process.exitCode = child.status ?? 1
16
- } else if (command === "build" || command === "dev" || command === "inspect") {
16
+ } else if (command === "build" || command === "dev" || command === "inspect" || command === "explain") {
17
17
  module.enableCompileCache?.()
18
- const { build, dev, inspect } = await import("../framework/build.mjs")
19
- const json = command === "build" && process.argv.includes("--json")
18
+ const { build, dev, explain, inspect } = await import("../framework/build.mjs")
19
+ const json = (command === "build" || command === "explain") && process.argv.includes("--json")
20
20
  try {
21
- if (command === "inspect") {
21
+ if (command === "inspect" || command === "explain") {
22
+ const args = process.argv.slice(3)
23
+ const routeIndex = args.indexOf("--route")
24
+ const route = routeIndex === -1 ? undefined : args[routeIndex + 1]
25
+ const validExplain = command !== "explain" || args.length === 3 && args.filter(arg => arg === "--json").length === 1 && args.filter(arg => arg === "--route").length === 1 && route && !route.startsWith("--") && args.every((arg, index) => arg === "--json" || arg === "--route" || index === routeIndex + 1)
22
26
  if (!process.argv.includes("--json")) {
23
- console.error("Use: kudzu inspect --json")
27
+ console.error(command === "inspect" ? "Use: kudzu inspect --json" : "Use: kudzu explain --route <route> --json")
28
+ process.exitCode = 1
29
+ } else if (!validExplain) {
30
+ console.error("Use: kudzu explain --route <route> --json")
24
31
  process.exitCode = 1
25
32
  } else {
26
33
  const log = console.log
27
34
  console.log = console.error
28
35
  try {
29
- process.stdout.write(`${JSON.stringify(await inspect())}\n`)
36
+ process.stdout.write(`${JSON.stringify(await (command === "inspect" ? inspect() : explain({ route })))}\n`)
30
37
  } finally {
31
38
  console.log = log
32
39
  }
@@ -40,6 +47,6 @@ if ((command === "build" || command === "inspect") && !process.env.KUDZU_BUILD_C
40
47
  process.exitCode = 1
41
48
  }
42
49
  } else {
43
- console.error(`Unknown command: ${command}\nUse: kudzu <build|dev|inspect>`)
50
+ console.error(`Unknown command: ${command}\nUse: kudzu <build|dev|inspect|explain>`)
44
51
  process.exitCode = 1
45
52
  }
@@ -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.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.
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.
19
19
 
20
20
  ## Required Invariants
21
21
 
@@ -1856,6 +1856,23 @@ ships as `@kudzujs/core@0.16.12` with `create-kudzu@0.1.137`.
1856
1856
  - **Done condition:** existing route records and artifact reports answer the
1857
1857
  query with bounded output.
1858
1858
 
1859
+ Completed by `@kudzujs/core@0.16.13` and `create-kudzu@0.1.138`. The
1860
+ `worker-effects` fixture proves exact configured-base lookup for an effect-owned
1861
+ Worker route, authored source closure, `Dashboard` ownership, capability family,
1862
+ runtime/handler/Worker byte reasons, raw/gzip totals, hashes, deterministic
1863
+ output, structured missing-route diagnostics, and a static sibling with an empty
1864
+ JavaScript closure. The implementation is one 137-line bounded projection over
1865
+ existing source results, compatibility sites, route records, and the sole route
1866
+ artifact report plus the existing build/CLI seam. It adds no analyzer, semantic
1867
+ primitive, compiler pass, normalization entry, runtime concept, or browser
1868
+ module. Representative deploy manifests and hashes remain unchanged. Worker and
1869
+ window graphs remain 907 raw / 477 gzip and 14,456 raw / 6,160 gzip bytes; seven
1870
+ clean builds record a 605 ms median without a timing comparison. Browser-disabled
1871
+ and required-Chrome suites pass 296/296 tests, and package smoke and artifact
1872
+ accounting pass. Fixed 100-record section limits expose totals and omitted counts;
1873
+ the command requires one exact emitted route and intentionally excludes raw IR,
1874
+ HTML, generated code, captures, and state values.
1875
+
1859
1876
  ### `0.20.3`: Deterministic Normalize And Fix
1860
1877
 
1861
1878
  - **Purpose:** automate only edits proven safe and useful by recorded AI trials.
@@ -1864,6 +1881,21 @@ ships as `@kudzujs/core@0.16.12` with `create-kudzu@0.1.137`.
1864
1881
  - **Stop condition:** canonical compiler source replaces ordinary authored TSX.
1865
1882
  - **Done condition:** each fix has one diagnostic code and explicit preconditions.
1866
1883
 
1884
+ Deferred by the evidence gate without production changes or a release. A complete
1885
+ repository inventory found no recorded model prompt, model/tool version, raw
1886
+ attempt, correction cycle, token/cost trace, or repeated source edit proving any
1887
+ automatic fix useful. Existing diagnostics offer migration guidance but do not
1888
+ identify a uniquely safe edit; replacing a non-null ref initializer would change
1889
+ authored behavior. The existing lazy-state-literal normalization could support a
1890
+ narrow exact-range rewrite while preserving comments and output bytes, but no AI
1891
+ trial records it as a correction or cost reduction. Adding check/preview/write
1892
+ infrastructure now would therefore be speculative and violate the packet purpose.
1893
+ Resume this packet only after `0.20.4` records a repeated correction with one
1894
+ stable diagnostic code, a unique semantics-preserving replacement, and
1895
+ compiler-proven preconditions. No fixture, analyzer, fix command, formatter,
1896
+ compiler pass, runtime concept, browser module, package version, or release was
1897
+ added.
1898
+
1867
1899
  ### `0.20.4`: AI Delivery Protocol And Runner
1868
1900
 
1869
1901
  - **Purpose:** track fair Kudzu and React+Vite delivery attempts.
@@ -1874,6 +1906,20 @@ ships as `@kudzujs/core@0.16.12` with `create-kudzu@0.1.137`.
1874
1906
  comparator.
1875
1907
  - **Done condition:** every attempt is reproducible or fully attributable.
1876
1908
 
1909
+ Completed by `@kudzujs/core@0.16.14` and `create-kudzu@0.1.139`. The
1910
+ repository-owned Node standard-library runner pins the model revision, pricing,
1911
+ tools, prompt, budgets, adapter, acceptance command, starter digests, optional
1912
+ public context, and paired schedule before creating isolated workspaces. It
1913
+ retains raw adapter/build/acceptance streams, final source, browser artifacts,
1914
+ hashes, attribution, token/cost/tool/file/build metrics, source retention, and
1915
+ both successful and failed attempts. The deterministic two-attempt-per-variant
1916
+ fixture proves equal ordering, one retained failure per variant, independent
1917
+ final builds, framework-neutral acceptance, and failure-inclusive cost per
1918
+ success. It is protocol evidence only and makes no Kudzu versus React+Vite
1919
+ delivery claim. No dependency, compiler pass, semantic primitive, runtime
1920
+ concept, application API, or browser byte was added. Browser-disabled and
1921
+ required-Chrome suites pass 297/297 tests, and package smoke passes.
1922
+
1877
1923
  ### `0.20.5`: Tooling Cost Validation
1878
1924
 
1879
1925
  - **Purpose:** prove that diagnostics/inspect/explain/fix lower total cost per
@@ -2073,3 +2119,6 @@ release transaction where possible or document and publish a forward-fix patch.
2073
2119
  | `0.19.5` | Deferred by stop condition | Resume only from a complete pinned Actual Budget workspace with an executable dependency graph and honest retention denominator. | Sparse acquisition omits required workspace and core packages; no compatibility claim |
2074
2120
  | `0.20.0` | Released as `0.16.11` | Preserve stable diagnostic schema/codes, authored ranges, human errors, compatibility reuse, and zero browser/output delta. | Patch release retained the `0.16.x` public version line |
2075
2121
  | `0.20.1` | Released as `0.16.12` | Preserve bounded deterministic reachable inventory, first-blocker retention, existing-record reuse, and zero browser/output delta. | Patch release retained the `0.16.x` public version line |
2122
+ | `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
+ | `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
+ | `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 |
@@ -1,12 +1,12 @@
1
1
  # Current Compiler Architecture
2
2
 
3
- This maps the current `0.16.12` 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.2`; 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.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.
4
4
 
5
5
  ## Responsibility Map
6
6
 
7
7
  | Responsibility | Current owner | Current contract |
8
8
  |---|---|---|
9
- | CLI entry | [`bin/kudzu.mjs`](../../bin/kudzu.mjs) | Dispatches build and development commands. |
9
+ | CLI entry | [`bin/kudzu.mjs`](../../bin/kudzu.mjs) | Dispatches build, development, inspection, and exact-route explanation commands. |
10
10
  | Project session | [`framework/compiler/project-session.mjs`](../../framework/compiler/project-session.mjs), `createProjectSession()` | Owns one absolute root, standard project paths, source records, bound graph operations, and Worker compiler. Production builds use one session; development retains it across rebuilds. Omitted roots resolve from call-time CWD. |
11
11
  | Parsed module cache and symbols | [`framework/compiler/project-session.mjs`](../../framework/compiler/project-session.mjs) | Parses each unchanged source module once per ProjectSession and records source-local declaration/import/re-export sites. Stable ModuleSymbol records resolve direct, aliased, barrel, and `export *` exports with cycle and ambiguity checks; repeated resolutions are cached against their source dependencies, and normalization consumers locate the resolved SiteId in a fresh clone with independent parent links. |
12
12
  | Build orchestration | [`framework/build.mjs`](../../framework/build.mjs), `build()`, `buildWithSession()` | Coordinates config, discovery, source compilation, RouteBuildRecord collection, CapabilityIR projection, generator invocation, artifact emission, and `afterBuild`. A retained session caches source results and pre-family route renders by page graph; successful builds alone replace that cache. |
@@ -22,6 +22,7 @@ This maps the current `0.16.12` architecture, built on the completed `0.9.0` sem
22
22
  | Component ownership analysis | [`framework/compiler/analysis/component-analysis.mjs`](../../framework/compiler/analysis/component-analysis.mjs) | Produces ComponentAnalysis v2 with ordered JSON-safe owner and specialization slots for state, setters, props, refs, IDs, direct SignalIR links, direct static property/consumer links, structural OwnerRefs, source-local SiteIds, and source provenance. Three direct callback/ref component boundaries specialize into the same parent signal and intrinsic ownership; Context action-private setters may remain compiler-only and receive collision-free consumer-local aliases; AST identity remains private to its source-local session. |
23
23
  | Per-source descriptor registration | [`framework/compiler/descriptor-session.mjs`](../../framework/compiler/descriptor-session.mjs), `createSemanticArtifact()`, `createDescriptorSession()` | Keeps AST descriptors private during analysis, then finalizes ModuleIR v2 with deterministic SymbolRef, SharedStateIR, SharedActionIR, SignalIR, HandlerIR, BindingIR, DerivedIR, EffectIR, KeyedBlockIR, and ImportIR slots. One fail-closed boundary validates every source-local and component ownership edge before build-module generation. |
24
24
  | Route artifact graph | [`framework/compiler/route-build-record.mjs`](../../framework/compiler/route-build-record.mjs), `createRouteBuildRecord()`, `planRouteArtifacts()`; [`framework/compiler/route-artifact-report.mjs`](../../framework/compiler/route-artifact-report.mjs), `createRouteArtifactReport()` | Validates each rendered route's RouteIR, capabilities, entry paths, styles, and exact handler/effect references. Handler and Worker esbuild metafiles project transitive output edges back through those records into deterministic per-route capability signatures and runtime requirements plus emitted handler, Worker, stylesheet, and shared-chunk closure. |
25
+ | Tool projections | [`framework/compiler/inspection-report.mjs`](../../framework/compiler/inspection-report.mjs), `createInspectionReport()`; [`framework/compiler/explanation-report.mjs`](../../framework/compiler/explanation-report.mjs), `createExplanationReport()` | Projects bounded deterministic reachable-application inventory and one exact route's authored provenance, ownership, capability, artifact byte reasons, hashes, and zero-JavaScript explanation from existing build records. Raw semantic IR, generated code, HTML, captures, and state values remain private. |
25
26
  | Route contract validation | [`framework/compiler/route-ir.mjs`](../../framework/compiler/route-ir.mjs), `assertRouteIR()` | Fails before artifact selection for invalid state/parameter identity, commands, native/effect captures and dependencies, reactive descriptors, conditions, keyed-list identity/ownership, marker fields, or JSON safety. Immutable in-memory contracts validate once by identity. |
26
27
  | Command IR and codegen | [`framework/compiler/optimize/command-specialization.mjs`](../../framework/compiler/optimize/command-specialization.mjs), [`framework/compiler/ir/module-ir.mjs`](../../framework/compiler/ir/module-ir.mjs), [`framework/compiler/codegen/command-codegen.mjs`](../../framework/compiler/codegen/command-codegen.mjs) | Direct commands use the existing fast path; proven immutable state aliases and one-call local helpers specialize to the same JSON-safe command ModuleIR. Recursion, escape, mutation, and dynamic helper dispatch fail explicitly, while unrelated handlers retain native ESM. Codegen emits the existing `__kBehavior` AST and command ABI. |
27
28
  | Source compilation | [`framework/compiler/source-compiler.mjs`](../../framework/compiler/source-compiler.mjs), `compileSource()` | Runs TypeScript with the Kudzu transformer, rejects surviving React/Router references, and returns a JSON-safe project-relative build module, component analysis, ModuleIR, optional handler module, and imported assets without filesystem writes. |
@@ -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.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.
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.
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.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.
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.
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.2` `kudzu explain --route` 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.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.
@@ -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.2`; 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.20.5`; 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.137` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.16.12`.
69
+ `create-kudzu@0.1.139` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.16.14`.
70
70
 
71
71
  ## Release Boundary
72
72
 
@@ -5,7 +5,8 @@ import { pathToFileURL } from "node:url"
5
5
  import { build as bundle, transform } from "esbuild"
6
6
  import { createEffectCodegen } from "./compiler/effect-codegen.mjs"
7
7
  import { createCompatibilityReport } from "./compiler/compatibility-registry.mjs"
8
- import { diagnosticEnvelope, normalizeDiagnosticError } from "./compiler/diagnostics.mjs"
8
+ import { createDiagnosticError, diagnosticEnvelope, normalizeDiagnosticError } from "./compiler/diagnostics.mjs"
9
+ import { createExplanationReport } from "./compiler/explanation-report.mjs"
9
10
  import { createInspectionReport } from "./compiler/inspection-report.mjs"
10
11
  import { generateListRuntime } from "./compiler/list-runtime-codegen.mjs"
11
12
  import { assetPath, browserPath, relativeModulePath, withBase } from "./compiler/path-helpers.mjs"
@@ -44,7 +45,12 @@ export async function inspect({ minify = true, root: projectRoot = process.cwd()
44
45
  return buildWithSession(project, { quiet: true, minify, retainCache: false, inspection: true })
45
46
  }
46
47
 
47
- export async function buildWithSession(project, { changedFiles, quiet = false, minify = true, retainCache = true, inspection = false } = {}) {
48
+ export async function explain({ route, minify = true, root: projectRoot = process.cwd() } = {}) {
49
+ const project = createProjectSession(projectRoot)
50
+ return buildWithSession(project, { quiet: true, minify, retainCache: false, explanationRoute: route })
51
+ }
52
+
53
+ export async function buildWithSession(project, { changedFiles, quiet = false, minify = true, retainCache = true, inspection = false, explanationRoute } = {}) {
48
54
  const { root, outputDirectory } = project
49
55
  const stagedOutput = join(root, ".kudzu-dist-staging")
50
56
  const backupOutput = join(root, ".kudzu-dist-backup")
@@ -53,11 +59,11 @@ export async function buildWithSession(project, { changedFiles, quiet = false, m
53
59
  try {
54
60
  await recoverOutput(outputDirectory, backupOutput)
55
61
  await rm(stagedOutput, { recursive: true, force: true })
56
- const { result, pageCount, behaviorCount, cache, inspectionData } = await buildInto(project, stagedOutput, { changedFiles, minify, quiet, retainCache })
62
+ const { result, pageCount, behaviorCount, cache, inspectionData, explanation } = await buildInto(project, stagedOutput, { changedFiles, minify, quiet, retainCache, explanationRoute })
57
63
  await promoteOutput(stagedOutput, outputDirectory, backupOutput)
58
64
  project.buildCache = retainCache ? cache : undefined
59
65
  if (!quiet) console.log(`Built ${pageCount} page(s), ${behaviorCount} interactive page(s) into dist/`)
60
- return inspection ? createInspectionReport(inspectionData) : result
66
+ return explanationRoute ? explanation : inspection ? createInspectionReport(inspectionData) : result
61
67
  } catch (error) {
62
68
  const normalized = normalizeDiagnosticError(error, root)
63
69
  const envelope = inspection && diagnosticEnvelope(normalized)
@@ -76,7 +82,7 @@ export async function buildWithSession(project, { changedFiles, quiet = false, m
76
82
  }
77
83
  }
78
84
 
79
- async function buildInto(project, outputDirectory, { changedFiles, minify, quiet, retainCache }) {
85
+ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet, retainCache, explanationRoute }) {
80
86
  const { root, sourceDirectory, pagesDirectory, workDirectory } = project
81
87
  const previous = retainCache ? project.buildCache : undefined
82
88
  project.buildGeneration = (project.buildGeneration ?? 0) + 1
@@ -184,6 +190,7 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
184
190
  const bindingPlaceholder = placeholders.binding
185
191
  const listPlaceholder = placeholders.list
186
192
  const pageRenders = new Map()
193
+ const routePageFiles = new Map()
187
194
  let renderedPages = 0
188
195
 
189
196
  for (const pageFile of pageFiles) {
@@ -304,6 +311,7 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
304
311
  runtimeSchema
305
312
  })
306
313
  routeRecords.push(record)
314
+ routePageFiles.set(record, pageFile)
307
315
  if (navigationGroup) navigationGroup.buildRecords.push(record)
308
316
  routeDrafts.push({ record, runtimeSchema, navigationGroup, applicationRoute, effectPath, nativePath, paramPath })
309
317
  if (!retainCache && config.afterBuild === undefined) {
@@ -534,10 +542,21 @@ async function buildInto(project, outputDirectory, { changedFiles, minify, quiet
534
542
  await config.afterBuild({ root, outDir: outputDirectory, sourceDir: sourceDirectory, base, routes: plans.map(plan => plan.route), plans, rewrites: sortedRewrites, artifacts })
535
543
  }
536
544
 
545
+ let explanation
546
+ if (explanationRoute) {
547
+ const artifact = artifacts.routes.find(entry => entry.route === explanationRoute)
548
+ const record = routeRecords.find(entry => entry.route === explanationRoute)
549
+ if (!artifact || !record) throw createDiagnosticError({ code: "explain.route.not-found", stage: "explain", message: `No emitted route exactly matches ${JSON.stringify(explanationRoute)}.`, suggestion: "Use an exact emitted route listed by kudzu inspect --json." })
550
+ const pageFile = routePageFiles.get(record)
551
+ const sourceFiles = [...pageSources.get(pageFile)].map(file => relative(root, file).replaceAll(sep, "/"))
552
+ explanation = await createExplanationReport({ route: explanationRoute, record, artifact, entrySource: relative(root, pageFile).replaceAll(sep, "/"), sourceFiles, sourceResults, compatibility, outputDirectory, base })
553
+ }
554
+
537
555
  const incremental = { compiledModules, renderedPages }
538
556
  return {
539
557
  result: { sourceResults, incremental },
540
558
  inspectionData: { sourceFiles: sourceFiles.map(file => relative(root, file).replaceAll(sep, "/")), sourceResults, compatibility, artifacts },
559
+ explanation,
541
560
  pageCount: routeRecords.length,
542
561
  behaviorCount,
543
562
  cache: { pageRenders, pageSources, placeholders, sourceResults: sourceResultsByFile }
@@ -0,0 +1,137 @@
1
+ import { createHash } from "node:crypto"
2
+ import { readFile } from "node:fs/promises"
3
+ import { join } from "node:path"
4
+ import { gzipSync } from "node:zlib"
5
+
6
+ const limits = Object.freeze({ sources: 100, normalization: 100, owners: 100, effects: 100, artifacts: 100 })
7
+
8
+ export async function createExplanationReport({ route, record, artifact, entrySource, sourceFiles, sourceResults, compatibility, outputDirectory, base }) {
9
+ const sources = [...sourceFiles].sort(compareText)
10
+ const sourceSet = new Set(sources)
11
+ const results = sourceResults.filter(result => sourceSet.has(result.file))
12
+ const normalization = compatibility.sites.filter(site => sourceSet.has(site.file)).map(site => ({ ...site, provenance: "reachable-source" }))
13
+ const owners = results.flatMap(result => [
14
+ ...result.componentAnalysis.owners.map(owner => ownerFact(result.file, "component", owner)),
15
+ ...result.componentAnalysis.specializations.map(owner => ownerFact(result.file, "specialization", owner)),
16
+ ]).sort((left, right) => compareText(left.module, right.module) || compareText(left.kind, right.kind) || left.slot - right.slot)
17
+ const effects = effectFacts(record, results, sources)
18
+ const artifacts = await artifactFacts(artifact, outputDirectory, base)
19
+ const eager = artifacts.filter(entry => !entry.reasons.includes("lazy-handler-chunk") && !entry.external)
20
+ const lazy = artifacts.filter(entry => entry.reasons.includes("lazy-handler-chunk") && !entry.external)
21
+ const javascript = artifacts.filter(entry => entry.path.endsWith(".js") && !entry.external)
22
+ const zeroJavaScript = artifact.runtime.family === null && javascript.length === 0
23
+ const sections = { sources, normalization, owners, effects, artifacts }
24
+ return {
25
+ version: 1,
26
+ status: "ready",
27
+ route,
28
+ entrySource,
29
+ runtimeRoute: Boolean(record.runtimeSchema),
30
+ capability: { signature: artifact.capability.signature, family: artifact.runtime.family, facts: enabledFacts(artifact.capability.manifest) },
31
+ ...Object.fromEntries(Object.entries(sections).map(([name, entries]) => [name, entries.slice(0, limits[name])])),
32
+ bytes: {
33
+ eagerRawBytes: sum(eager, "rawBytes"),
34
+ eagerGzipBytes: sum(eager, "gzipBytes"),
35
+ lazyRawBytes: sum(lazy, "rawBytes"),
36
+ lazyGzipBytes: sum(lazy, "gzipBytes"),
37
+ javascriptRawBytes: sum(javascript, "rawBytes"),
38
+ javascriptGzipBytes: sum(javascript, "gzipBytes"),
39
+ },
40
+ zeroJavaScript: {
41
+ value: zeroJavaScript,
42
+ scope: "compiler-selected-capability-artifacts",
43
+ reasons: zeroJavaScript
44
+ ? ["no behavior runtime family", "no runtime or handler entry", "no Worker graph"]
45
+ : ["route selects one or more browser capability artifacts"],
46
+ },
47
+ limits,
48
+ summary: Object.fromEntries(Object.entries(sections).map(([name, entries]) => [name, entries.length])),
49
+ omitted: Object.fromEntries(Object.entries(sections).map(([name, entries]) => [name, Math.max(0, entries.length - limits[name])])),
50
+ }
51
+ }
52
+
53
+ function effectFacts(record, results, sources) {
54
+ const facts = []
55
+ for (const reference of record.artifacts.effects) {
56
+ const result = results.find(entry => entry.handlerModule && reference.module.endsWith(`/assets/${entry.handlerModule.path}`))
57
+ if (!result) continue
58
+ const handler = result.moduleIR.handlers.find(entry => entry.exportName === reference.handler)
59
+ const effect = result.moduleIR.effects.find(entry => entry.setup?.handler === handler?.slot)
60
+ if (!handler || !effect) continue
61
+ const owner = effect.ownership?.owner
62
+ const descriptor = owner?.kind === "component" ? result.componentAnalysis.owners[owner.slot] : owner?.kind === "specialization" ? result.componentAnalysis.specializations[owner.slot] : undefined
63
+ facts.push({
64
+ module: result.file,
65
+ handler: reference.handler,
66
+ ...(handler.source ? { source: handler.source } : {}),
67
+ owner: descriptor?.name ?? descriptor?.component?.name ?? owner?.kind ?? "module",
68
+ cleanup: Boolean(effect.cleanup),
69
+ dependencies: effect.dependencies?.length ?? 0,
70
+ workers: effect.workers.map(worker => {
71
+ const matches = sources.filter(file => file === worker.root || file.endsWith(`/${worker.root}`))
72
+ return matches.length === 1 ? matches[0] : worker.root
73
+ }).sort(compareText),
74
+ })
75
+ }
76
+ return facts.sort((left, right) => compareText(left.module, right.module) || compareText(left.handler, right.handler))
77
+ }
78
+
79
+ async function artifactFacts(route, outputDirectory, base) {
80
+ const edges = [
81
+ ...route.runtime.entries.map(path => [path, "runtime-entry"]),
82
+ ...route.runtime.requirements.map(path => [path, "runtime-requirement"]),
83
+ ...route.handlers.entries.map(path => [path, "handler-entry"]),
84
+ ...route.handlers.chunks.map(path => [path, "handler-chunk"]),
85
+ ...route.handlers.lazyChunks.map(path => [path, "lazy-handler-chunk"]),
86
+ ...route.workers.flatMap(worker => [[worker.entry, `worker:${worker.source}`], ...worker.chunks.map(path => [path, `worker-chunk:${worker.source}`])]),
87
+ ...route.styles.map(path => [path, "style"]),
88
+ ]
89
+ const selected = new Map()
90
+ for (const [url, reason] of edges) {
91
+ const reasons = selected.get(url) ?? new Set()
92
+ reasons.add(reason)
93
+ selected.set(url, reasons)
94
+ }
95
+ return Promise.all([...selected].sort(([left], [right]) => compareText(left, right)).map(async ([url, reasons]) => {
96
+ if (/^https?:\/\//.test(url)) return { path: url, reasons: [...reasons].sort(compareText), external: true }
97
+ const pathname = new URL(url, "https://kudzu.invalid").pathname
98
+ const deployed = base && pathname.startsWith(`${base}/`) ? pathname.slice(base.length + 1) : pathname.slice(1)
99
+ const contents = await readFile(join(outputDirectory, deployed))
100
+ return {
101
+ path: deployed,
102
+ reasons: [...reasons].sort(compareText),
103
+ rawBytes: contents.byteLength,
104
+ gzipBytes: gzipSync(contents).byteLength,
105
+ sha256: createHash("sha256").update(contents).digest("hex"),
106
+ }
107
+ }))
108
+ }
109
+
110
+ function ownerFact(module, kind, owner) {
111
+ return {
112
+ module,
113
+ kind,
114
+ slot: owner.slot,
115
+ name: owner.name ?? owner.component?.name ?? "anonymous",
116
+ states: owner.states?.length ?? 0,
117
+ refs: owner.refs?.length ?? 0,
118
+ ids: owner.ids?.length ?? 0,
119
+ provenance: "reachable-source",
120
+ }
121
+ }
122
+
123
+ function enabledFacts(value, prefix = "") {
124
+ const facts = []
125
+ for (const [key, entry] of Object.entries(value ?? {}).sort(([left], [right]) => compareText(left, right))) {
126
+ if (key === "version") continue
127
+ const path = prefix ? `${prefix}.${key}` : key
128
+ if (entry === true) facts.push(path)
129
+ else if (typeof entry === "number" && entry > 0) facts.push(`${path}=${entry}`)
130
+ else if (Array.isArray(entry)) for (const item of entry) facts.push(`${path}=${item}`)
131
+ else if (entry && typeof entry === "object") facts.push(...enabledFacts(entry, path))
132
+ }
133
+ return facts
134
+ }
135
+
136
+ const sum = (entries, field) => entries.reduce((total, entry) => total + entry[field], 0)
137
+ const compareText = (left, right) => left < right ? -1 : left > right ? 1 : 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kudzujs/core",
3
- "version": "0.16.12",
3
+ "version": "0.16.14",
4
4
  "description": "HTML-first TSX framework with synchronous state semantics and no virtual DOM",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -65,6 +65,7 @@
65
65
  "benchmark:project-list-decision": "node test/project-list-decision-performance.mjs",
66
66
  "benchmark:project-state": "node test/project-state-performance.mjs",
67
67
  "benchmark:source-scale": "node test/source-scale-performance.mjs",
68
+ "benchmark:ai-delivery": "node test/ai-delivery-runner.mjs",
68
69
  "prepublishOnly": "npm run check && npm test",
69
70
  "deploy": "wrangler deploy",
70
71
  "preview": "wrangler dev"