id: PX-PLAN-_BUERPCN
type: plan
title: Release Build and Verified Publication
spec: PX-SPEC-DZLVGRW4
status: approved
depends_on:
PX-PLAN-RMJ8BIOX
Outcome
A release build produces the same package boundary as the development build, is verified as immutable bytes, and only those bytes are published to Git for explicitly selected extensions.
Consumers install without source or toolchain.
Verified current state: //:publish is Git-only; release commits README, CHANGELOG, package.json, lockfile; version lives in root package.json; extension packages are private: true without versions.
Behaviors
flowchart TB
r1["1. Release build of ultra behaves identically to dev build"] --> r2["2. Snapshot digest gates publication"]
r2 --> r3["3. Git distribution carries built packages for selected extensions"]
r3 --> r4["4. Consumer install smoke from Git without checkout"]
build-ext --release emits into the same dist/<name> with minification and no sourcemaps; chunk boundaries, externals, manifest, and resources are asserted equal to a dev build by a structural diff test.
Reload of a release package after a dev package shows no behavior change in the contract suite.
//:release-snapshot copies dist/<selected> into an immutable snapshot directory keyed by content digest, runs verify-packages on the snapshot, and records digests in a release manifest file.
//:publish refuses when the current dist digest differs from the manifest.
Publication eligibility is a per-extension declaration (pi-ext.publish: true in the source package.json); private stays default.
The snapshot rewrites the generated package.json with the root version, the public name, private: false, and no scripts.
Git channel: a release/<version> tag or dist branch containing only built packages so pi install git:…/dist/<name> works.
Consumer smoke: temp directory, independently installed Pi, pi install from Git, load, run one tool per extension.
Touched: scripts/build/* (release mode), scripts/release/*, scripts/extensions.mjs (publish, release-prepare), mise.toml (release-snapshot, publish), extensions/<name>/package.json (publish declaration, public name), .ci/*.kdl later plan.
Constraints
Root package.json version remains the single version source; generated manifests copy it at build time.
Compatibility metadata (peerDependencies on Pi) is authored once in the extension source manifest.
Release verification uses the snapshot, never a rebuilt dist.
Verification
Structural diff between dev and release builds shows only sourcemap and minification differences.
Publish with a modified dist after snapshot is rejected with a digest mismatch.
Only extensions declared publishable appear in the release selection.
Git consumer smoke passes in a temp directory without repository source.
---
id: PX-PLAN-_BUERPCN
type: plan
title: Release Build and Verified Publication
spec: PX-SPEC-DZLVGRW4
status: approved
depends_on:
- PX-PLAN-RMJ8BIOX
---
## Outcome
A release build produces the same package boundary as the development build, is verified as immutable bytes, and only those bytes are published to Git for explicitly selected extensions.
Consumers install without source or toolchain.
Verified current state: `//:publish` is Git-only; release commits README, CHANGELOG, `package.json`, lockfile; version lives in root `package.json`; extension packages are `private: true` without versions.
## Behaviors
```mermaid
flowchart TB
r1["1. Release build of ultra behaves identically to dev build"] --> r2["2. Snapshot digest gates publication"]
r2 --> r3["3. Git distribution carries built packages for selected extensions"]
r3 --> r4["4. Consumer install smoke from Git without checkout"]
```
1. `build-ext --release` emits into the same `dist/<name>` with minification and no sourcemaps; chunk boundaries, externals, manifest, and resources are asserted equal to a dev build by a structural diff test.
Reload of a release package after a dev package shows no behavior change in the contract suite.
2. `//:release-snapshot` copies `dist/<selected>` into an immutable snapshot directory keyed by content digest, runs `verify-packages` on the snapshot, and records digests in a release manifest file.
`//:publish` refuses when the current `dist` digest differs from the manifest.
3. Publication eligibility is a per-extension declaration (`pi-ext.publish: true` in the source `package.json`); private stays default.
The snapshot rewrites the generated `package.json` with the root version, the public name, `private: false`, and no scripts.
Git channel: a `release/<version>` tag or `dist` branch containing only built packages so `pi install git:…/dist/<name>` works.
4. Consumer smoke: temp directory, independently installed Pi, `pi install` from Git, load, run one tool per extension.
## Module structure
```mermaid
flowchart LR
build["scripts/build driver --release"] --> dist["dist/name"]
dist --> snap["scripts/release/snapshot: digest + manifest"]
snap --> gate{"digest match?"}
gate -->|yes| git["Git dist tag"]
gate -->|no| reject["reject"]
select["per-extension publish declaration"] --> snap
```
Touched: `scripts/build/*` (release mode), `scripts/release/*`, `scripts/extensions.mjs` (`publish`, `release-prepare`), `mise.toml` (`release-snapshot`, `publish`), `extensions/<name>/package.json` (publish declaration, public name), `.ci/*.kdl` later plan.
## Constraints
- Root `package.json` version remains the single version source; generated manifests copy it at build time.
- Compatibility metadata (`peerDependencies` on Pi) is authored once in the extension source manifest.
- Release verification uses the snapshot, never a rebuilt `dist`.
## Verification
- [ ] Structural diff between dev and release builds shows only sourcemap and minification differences.
- [ ] Publish with a modified `dist` after snapshot is rejected with a digest mismatch.
- [ ] Only extensions declared publishable appear in the release selection.
- [ ] Git consumer smoke passes in a temp directory without repository source.