# Building KitJS

This document is for KitJS maintainers. People who load KitJS from a CDN do
not need Node.js, npm, or a build step.

The runtime source and generated artifacts in this checkout identify the
stable `1.0.0` line. A local version string is not publication evidence:
`RELEASE_READINESS.md` records exact tagged and public retrieval evidence
separately. `1.0.0-rc.2` and earlier releases remain immutable historical
evidence.

The artifact builder uses only Node.js standard-library modules. Playwright and
its browser binaries are development-only test tools; they do not enter either
published classic script.

## Source and profiles

`src/` contains readable classic-script fragments. `src/profiles.json` defines
the only supported output profiles and their exact concatenation order:

```text
kit      -> dist/kit.js
hydrate  -> dist/hydrate.kit.js
```

Kit provides scoped reactive HTML, events, structures, and direct client
components. Hydrate contains the same browser runtime plus Morph and Drive for
compatibility-checked navigation. The profiles are alternatives; a page must
load only one.

Every included JavaScript fragment must:

- begin with `;`;
- end with one LF;
- use LF rather than CRLF;
- be UTF-8 without a byte-order mark.

The builder concatenates exact bytes. It does not transpile, rewrite, minify,
add a banner, or resolve dependencies.

## Generate distributions

From this package directory:

```sh
npm run build
```

The equivalent direct command is:

```sh
node ./scripts/build.mjs
```

The build validates that `package.json`, `src/profiles.json`, and `src/core.js`
name the same release. It writes both scripts and `dist/integrity.json` through
temporary files, removes obsolete distribution names, verifies source parity,
and prints each artifact's byte length and SHA-256.

The integrity manifest has a fixed schema and profile order. It records the
package/version, filename, byte length, SHA-256, and browser SRI for each
profile, with no timestamp, absolute path, or machine-specific value.

Verify checked-in output without rewriting it:

```sh
node ./scripts/build.mjs --check
```

The package publishes one readable canonical file per profile. There is no
second `.min.js` implementation. A static deployment may copy and rename an
already verified file to a content-addressed URL, but it must not change its
bytes.

The deterministic `1.0.0` artifacts are:

| Profile | Bytes | SHA-256 | SRI |
|---|---:|---|---|
| Kit | 206,607 | `2d7b750cae101b8decbac50dc334d0a7b1f4e3a1b5fe038d74e84101c5d52192` | `sha256-LXt1DK4QG43susUNwzTQp7H046G1/gONdOhBAcXVIZI=` |
| Hydrate | 314,424 | `01b23e3e45ce5604b1643362323402c5e86b70049642e5be9891eb4a67d2e7b9` | `sha256-AbI+PkXOVgSxZDNiMjQCxehrcASWQuW+mJHrSmfS57k=` |

The checked `dist/integrity.json` reproduces these values. After publication,
the release workflow must additionally prove that the tag, npm `gitHead`,
registry tarball, and exact CDN files reproduce these bytes, while npm `latest`
and the default unversioned CDN entry points identify the same stable release.
jsDelivr may minify its pathless default response, so that response is compared
with the immutable pathless `@1.0.0` response rather than the readable file.

## Test

Install the exact development tools and browser binaries:

```sh
npm ci
npx playwright install chromium firefox webkit
```

For a required release-evidence run, set `KITJS_REQUIRE_BROWSER=1` and
`KITJS_REQUIRE_BROWSER_MATRIX=1`. If the deep Chromium corpus should use a
specific installed Chrome, set `KITJS_BROWSER` to that executable. Then run:

```sh
npm test
```

The complete gate verifies:

- source reproduces `dist/kit.js` and `dist/hydrate.kit.js` byte for byte;
- the expected release sizes, SHA-256 values, SRI values, and deterministic
  integrity manifest have not drifted;
- expressions, state, models, events, structures, components, lifecycle,
  cleanup, Morph, and Drive pass the deep Chromium corpus;
- the direct-element and template forms of `data-kit-if`, plus template-only
  `data-kit-for` and `data-kit-key`, retain their documented behavior;
- Drive response/document budgets, GET forms, native fallback, script-topology
  diagnostics, history, focus, and fragment behavior pass browser regressions;
- the exact Kit and Hydrate files pass the shared critical matrix in Chromium,
  Firefox, and WebKit without silently skipping a required browser;
- release-verifier tests cover exact versions, bounded retries, tar traversal,
  registry metadata, tarball bytes, and CDN byte comparison;
- the benchmark smoke run completes every required shape without treating a
  workstation timing as a release threshold;
- package metadata exposes classic-script entries with no runtime dependency
  or install hook; and
- `npm pack --dry-run` contains only the documented public files.

Playwright `1.62.1` is exact-pinned test tooling. A local run, hosted CI, a tag
run, and public retrieval are separate evidence. WebKit results do not imply
support for every Safari version.

Useful narrower gates are:

```sh
npm run test:dist
npm run test:browser
npm run test:release
npm run test:package
npm run bench:smoke
```

The Kitwork server consumer has a separate release lifecycle. During a
coordinated server upgrade, maintainers with the sibling engine checkout may
run `KITJS_VERIFY_ENGINE_CONSUMER=1 npm run test:dist` to require byte parity.
That opt-in integration check is not part of the standalone npm/CDN package
release.

## Changing runtime source

1. Edit the appropriate readable fragment in `src/`.
2. If profile membership or order changes, update `src/profiles.json`.
3. When shipped behavior changes, advance the version in `package.json`,
   `src/profiles.json`, and `src/core.js` together.
4. Run `npm run build`.
5. Intentionally update pinned artifact sizes and hashes in the distribution
   parity test.
6. Run `npm test` and inspect
   `npm pack --dry-run --json --ignore-scripts`.

Never edit `dist/` by hand. Never add a generated public file that cannot be
reproduced solely from this package checkout.

## Release checklist

1. Confirm the intended version is exact SemVer and all three version sources
   agree.
2. Run `node ./scripts/build.mjs --check`, `npm run build`, and `npm test` on a
   supported Node.js release, then confirm the build left no diff.
3. Inspect `npm pack --dry-run --json --ignore-scripts`.
4. Confirm the tarball contains the documented files, both distribution
   scripts, and `dist/integrity.json`, with no unexpected entry.
5. Confirm the trusted publisher is authorized for `@kitwork/kitjs` and uses
   the required authentication policy.
6. Confirm the Git tag is exactly `v${package.version}`. Prereleases publish to
   npm `next`; a plain stable release publishes directly to npm `latest`.
   Trusted publishing supports `npm publish`, so the stable tag must select its
   final channel in that single authenticated publication.
7. After publication, run the bounded verifier from the exact tagged checkout:

   ```sh
   node ./scripts/verify-public-release.mjs 1.0.0 --git-sha <40-hex-tag-commit> --latest
   ```

   It compares npm metadata and `gitHead`, registry tarball SHA-512/SHA-1,
   packaged metadata, `dist/integrity.json`, and exact Kit/Hydrate bytes from
   npm, jsDelivr, and unpkg. With `--latest`, it also requires npm `latest` and
   the default unversioned jsDelivr/unpkg entry points to identify the stable
   release. The readable mutable `/dist/kit.js` URLs must match the artifact;
   jsDelivr's possibly minified pathless response must match its immutable
   pathless `@1.0.0` counterpart. Signatures, provenance, and browser evidence
   remain separately recorded checks.
8. Record the immutable and mutable-channel evidence. Recommend exact-version
   URLs with SRI for production even though the unversioned URL follows
   `latest` for users who explicitly want automatic upgrades.

See `RELEASE_READINESS.md` for the immutable publication evidence and the
current stable-exit criteria.
