Skip to content

feat(release): prove RC1 launcher parity - #203

Merged
HsiangNianian merged 6 commits into
mainfrom
feat/rc1-parity-audit
Aug 4, 2026
Merged

feat(release): prove RC1 launcher parity#203
HsiangNianian merged 6 commits into
mainfrom
feat/rc1-parity-audit

Conversation

@HsiangNianian

@HsiangNianian HsiangNianian commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

  • add a machine-checked 42-row PCL/HMCL/Prism parity evidence matrix and bilingual RC1 guide
  • smoke-test isolated Linux, macOS, and Windows installs before artifact upload
  • enter the rc channel and harden Semifold manifest synchronization

Validation

  • cargo test: 308 passed, 1 ignored
  • cargo check and cargo clippy
  • UI unit tests and production build
  • Playwright: 176 passed
  • docs lint, types:check, and production build
  • release workflow tests: 5 passed
  • parity audit tests: 3 passed
  • prek run --all-files

Closes #178

Summary by Sourcery

Add an RC1 parity audit and documentation, tighten release manifest synchronization, and validate isolated desktop installers in CI before artifact upload.

New Features:

  • Introduce a machine-checked RC1 launcher parity audit matrix with bilingual release documentation.
  • Add isolated installer smoke tests for Linux, macOS, and Windows desktop artifacts in the release workflow.

Enhancements:

  • Extend the Tauri version bump script to synchronize Cargo.lock and normalize package manifests across workspaces.
  • Update release configuration to use rc pre-release tags and wire the parity audit into the prek CI workflow.

Tests:

  • Add automated tests to enforce release workflow smoke-test ordering, validate manifest synchronization, and verify parity audit coverage and CI integration.

Copilot AI review requested due to automatic review settings August 4, 2026 05:57
@sourcery-ai

sourcery-ai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This PR formalizes the 0.2.0-rc.1 release as a machine-checked launcher parity contract, strengthens release/versioning automation, and adds cross-platform installer smoke tests plus bilingual RC1 documentation.

Sequence diagram for bump-tauri manifest synchronization

sequenceDiagram
    actor ReleaseWorkflow
    participant bump_tauri_ts
    participant tauri_conf_json
    participant cargo_lock
    participant ui_package_json
    participant docs_package_json

    ReleaseWorkflow->>bump_tauri_ts: pnpm bump-tauri
    bump_tauri_ts->>bump_tauri_ts: read DROPOUT_REPO_ROOT or repoRoot
    bump_tauri_ts->>tauri_conf_json: fs.readFileSync
    bump_tauri_ts->>bump_tauri_ts: getCurrentVersion
    bump_tauri_ts->>bump_tauri_ts: getBumpVersion
    alt currentVersion != bumpVersion
        bump_tauri_ts->>bump_tauri_ts: replaceVersion
        bump_tauri_ts->>tauri_conf_json: writeIfChanged
    else currentVersion == bumpVersion
        bump_tauri_ts->>bump_tauri_ts: log up-to-date
    end

    bump_tauri_ts->>cargo_lock: fs.readFileSync
    bump_tauri_ts->>bump_tauri_ts: replaceLockedVersion
    bump_tauri_ts->>cargo_lock: writeIfChanged

    bump_tauri_ts->>ui_package_json: fs.readFileSync
    bump_tauri_ts->>bump_tauri_ts: normalize trailing newline
    bump_tauri_ts->>ui_package_json: writeIfChanged

    bump_tauri_ts->>docs_package_json: fs.readFileSync
    bump_tauri_ts->>bump_tauri_ts: normalize trailing newline
    bump_tauri_ts->>docs_package_json: writeIfChanged
Loading

File-Level Changes

Change Details Files
Add a machine-checked RC1 launcher parity audit and wire it into CI.
  • Introduce scripts/parity-audit.test.mjs to validate the rc1-parity JSON schema, required rows, evidence links, and bilingual docs coverage.
  • Ensure every evidence path exists and optional content matches expected markers, failing if anything is missing or stale.
  • Assert that the prek workflow runs the new parity audit test via pnpm test:parity and add the npm script wiring.
scripts/parity-audit.test.mjs
.github/workflows/prek.yml
package.json
docs/release/rc1-parity.json
Harden the Tauri version bump script to synchronize all release manifests.
  • Allow overriding the repo root via DROPOUT_REPO_ROOT for testability, instead of assuming a fixed relative path.
  • Update bump-tauri.ts to also update the dropout package version inside Cargo.lock using a validated pattern.
  • Normalize UI/docs package.json files to always end with a trailing newline, writing changes only when content differs.
scripts/bump-tauri.ts
scripts/release-workflow.test.mjs
Cargo.lock
packages/ui/package.json
packages/docs/package.json
src-tauri/tauri.conf.json
src-tauri/Cargo.toml
Add cross-platform isolated-install smoke tests for all desktop artifacts and enforce ordering before artifact upload.
  • Introduce smoke-install shell/PowerShell scripts for Linux (AppImage + .deb), macOS (.dmg), and Windows (NSIS) that install into a temp directory and perform basic structural/binary checks.
  • Integrate these smoke tests into the build-tauri job in semifold-ci.yaml, guarded by runner.os and the matrix target.
  • Extend the release workflow tests to assert that each smoke step exists, references the correct script, and runs before any Upload Artifact step.
scripts/smoke-install-linux.sh
scripts/smoke-install-macos.sh
scripts/smoke-install-windows.ps1
.github/workflows/semifold-ci.yaml
scripts/release-workflow.test.mjs
Switch packages to the rc pre-release channel and bump versions for the RC1 cut.
  • Update .changes/config.toml to use pre-release.tag = "rc" for UI, docs, and Rust packages.
  • Bump @dropout/ui, @dropout/docs, and src-tauri (dropout) versions from beta.2 to rc.0.
  • Add a changeset describing the RC1 parity audit feature and associated package bumps.
.changes/config.toml
packages/ui/package.json
packages/docs/package.json
src-tauri/Cargo.toml
.changes/rc1-parity-audit.md
Add bilingual RC1 release documentation describing the parity contract and verification steps.
  • Create an English RC1 release note that explains the 42-row parity matrix, how to reproduce the evidence gate, and how to verify installer provenance.
  • Add a corresponding Chinese RC1 release note with equivalent content and links, ensuring both locales describe install, migration, and known limits.
  • Wire these docs into the existing release docs metadata so they appear in the release manual navigation.
packages/docs/content/en/manual/releases/rc-1.mdx
packages/docs/content/zh/manual/releases/rc-1.mdx
packages/docs/content/en/manual/releases/meta.json
packages/docs/content/zh/manual/releases/meta.json

Assessment against linked issues

Issue Objective Addressed Explanation
#178 Create a structured RC1 parity audit matrix (covering UI/UX, functionality, migration, distribution, and documentation) with all required rows and direct, in-repo evidence for each requirement.
#178 Enforce the parity audit and release requirements via automated tests and CI, including running the parity contract and smoke-testing each packaged desktop artifact in an isolated install before upload.
#178 Provide bilingual (English and Chinese) RC1 release documentation that explains the parity evidence, how to reproduce the audit gate, and how to install and verify the release candidate.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Workspace change through: 00fa737

1 changesets found

Planned changes to release
Package Bump Level Current Version Next Version
@dropout/ui patch 0.1.0-rc.0 0.1.0-rc.1
dropout patch 0.2.0-rc.0 0.2.0-rc.1
@dropout/docs patch 0.1.0-rc.0 0.1.0-rc.1

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The replaceLockedVersion helper in bump-tauri.ts relies on a brittle regex that assumes a very specific Cargo.lock layout; consider parsing the TOML or at least tightening the pattern to tolerate formatting changes (extra fields, reordered keys, or comments) without breaking the bump step.
  • The new smoke-install scripts and workflow test assume all installer artifacts (AppImage, deb, dmg, NSIS) exist for every matrix target; if you add or remove targets or change bundle layout later, you may want a single shared helper or explicit guard to keep these checks aligned with the build outputs.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `replaceLockedVersion` helper in `bump-tauri.ts` relies on a brittle regex that assumes a very specific `Cargo.lock` layout; consider parsing the TOML or at least tightening the pattern to tolerate formatting changes (extra fields, reordered keys, or comments) without breaking the bump step.
- The new smoke-install scripts and workflow test assume all installer artifacts (AppImage, deb, dmg, NSIS) exist for every matrix target; if you add or remove targets or change bundle layout later, you may want a single shared helper or explicit guard to keep these checks aligned with the build outputs.

## Individual Comments

### Comment 1
<location path="scripts/smoke-install-macos.sh" line_range="36-45" />
<code_context>
+
+cp -R "$source_app" "$install_root/"
+installed_app="$install_root/$(basename "$source_app")"
+info_plist="$installed_app/Contents/Info.plist"
+plutil -lint "$info_plist" >/dev/null
+executable_name=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$info_plist")
+installed_binary="$installed_app/Contents/MacOS/$executable_name"
+
+test -x "$installed_binary"
+file "$installed_binary" | grep -q 'Mach-O'
+otool -L "$installed_binary" >/dev/null
+
+echo "Verified isolated macOS install for $target"
</code_context>
<issue_to_address>
**suggestion:** Handle missing or malformed Info.plist more defensively

Right now, failures from `plutil`/`PlistBuddy` will be indirect if `Info.plist` is missing or `CFBundleExecutable` isn’t set. Consider checking that the plist exists and that `CFBundleExecutable` is present before calling `PlistBuddy`, and emit a clear error like `"application bundle is missing CFBundleExecutable"` so CI output directly identifies the packaging issue.

```suggestion
cp -R "$source_app" "$install_root/"
installed_app="$install_root/$(basename "$source_app")"
info_plist="$installed_app/Contents/Info.plist"

if [ ! -f "$info_plist" ]; then
  echo "application bundle is missing Info.plist" >&2
  exit 1
fi

if ! plutil -lint "$info_plist" >/dev/null; then
  echo "application bundle has an invalid Info.plist" >&2
  exit 1
fi

executable_name=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$info_plist") || executable_name=
if [ -z "$executable_name" ]; then
  echo "application bundle is missing CFBundleExecutable" >&2
  exit 1
fi

installed_binary="$installed_app/Contents/MacOS/$executable_name"

if [ ! -x "$installed_binary" ]; then
  echo "application bundle CFBundleExecutable '$executable_name' is not present or not executable" >&2
  exit 1
fi

file "$installed_binary" | grep -q 'Mach-O'
otool -L "$installed_binary" >/dev/null
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread scripts/smoke-install-macos.sh Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR strengthens the RC1 release process by adding a machine-checked parity evidence matrix (plus bilingual RC1 release guides), extending CI to smoke-test packaged desktop artifacts prior to upload, and tightening prerelease/release-manifest synchronization (including moving the prerelease tag to rc).

Changes:

  • Add a required 42-row RC1 parity evidence contract (docs/release/rc1-parity.json) with a Node test enforcing row coverage, evidence existence, and bilingual documentation evidence.
  • Add isolated-install smoke scripts (Linux/macOS/Windows) and wire them into the release workflow before artifact upload; add CI coverage for the parity audit test.
  • Update release tooling/config to enter the rc prerelease channel and synchronize generated release manifests (including Cargo.lock and package manifest normalization).

Reviewed changes

Copilot reviewed 20 out of 22 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src-tauri/tauri.conf.json Bumps Tauri app version to an rc prerelease.
src-tauri/Cargo.toml Bumps Rust crate version to an rc prerelease.
Cargo.lock Updates locked workspace package version.
scripts/smoke-install-windows.ps1 Adds Windows isolated NSIS install smoke validation.
scripts/smoke-install-macos.sh Adds macOS DMG mount/copy/install smoke validation.
scripts/smoke-install-linux.sh Adds Linux AppImage + Debian extraction smoke validation.
scripts/release-workflow.test.mjs Extends release workflow contract tests (manifest sync + smoke ordering).
scripts/parity-audit.test.mjs Adds parity audit contract tests (rows, evidence, bilingual docs, CI wiring).
scripts/bump-tauri.ts Extends bump script to sync Cargo.lock + normalize package manifests; supports fixture root via env var.
packages/ui/package.json Bumps UI package version to an rc prerelease.
packages/docs/package.json Bumps docs package version to an rc prerelease.
packages/docs/content/zh/manual/releases/rc-1.mdx Adds Chinese RC1 parity evidence guide.
packages/docs/content/zh/manual/releases/meta.json Adds RC1 release page to Chinese releases nav.
packages/docs/content/en/manual/releases/rc-1.mdx Adds English RC1 parity evidence guide.
packages/docs/content/en/manual/releases/meta.json Adds RC1 release page to English releases nav.
package.json Adds pnpm test:parity script entry.
docs/release/rc1-parity.json Adds the machine-checked RC1 parity evidence matrix.
.gitignore Adjusts ignore rules (attempts to unignore docs/release/...).
.github/workflows/semifold-ci.yaml Adds isolated-install smoke steps before artifact upload.
.github/workflows/prek.yml Runs the parity audit contract test in CI.
.changes/rc1-parity-audit.md Adds changeset entry describing RC1 parity audit + CI hardening.
.changes/config.toml Switches prerelease tag from beta to rc for relevant packages.
Suppressed comments (1)

scripts/smoke-install-linux.sh:37

  • This validates the AppImage and Debian package contents, but does not validate the RPM at all. Add at least a basic RPM structure check (ideally list/extract its payload in an isolated dir) to align with the “smoke every packaged desktop artifact” requirement.
dpkg-deb --extract "$deb" "$deb_root"
find "$deb_root/usr/bin" -maxdepth 1 -type f -perm -u+x -print -quit | grep -q .
find "$deb_root/usr/share/applications" -type f -name '*.desktop' -print -quit | grep -q .

Comment thread scripts/smoke-install-linux.sh
Comment thread scripts/smoke-install-macos.sh
Comment thread scripts/smoke-install-windows.ps1
Comment thread scripts/smoke-install-windows.ps1 Outdated
Comment thread src-tauri/tauri.conf.json
Comment thread src-tauri/Cargo.toml
Comment thread packages/ui/package.json
Comment thread packages/docs/package.json
Copilot AI review requested due to automatic review settings August 4, 2026 06:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 22 changed files in this pull request and generated no new comments.

Suppressed comments (5)

src-tauri/tauri.conf.json:4

  • PR metadata and added RC1 parity audit/docs consistently refer to 0.2.0-rc.1, but this bumps the Tauri app version to 0.2.0-rc.0. This mismatch makes it unclear which release candidate these artifacts/documentation apply to and can break release automation expecting a single source of truth.
  "version": "0.2.0-rc.0",

src-tauri/Cargo.toml:3

  • PR metadata and the new parity audit/docs target 0.2.0-rc.1, but the Rust package version is set to 0.2.0-rc.0. Version skew across release artifacts makes Semifold/Changesets outputs and documentation hard to reconcile; align this to the intended RC version.
version = "0.2.0-rc.0"

packages/ui/package.json:4

  • PR metadata and the RC1 release docs/audit target 0.2.0-rc.1, but the UI package is versioned as 0.1.0-rc.0. If RC1 is meant to be rc.1 across the workspace, this should match to avoid publishing mixed prerelease tags.
  "version": "0.1.0-rc.0",

packages/docs/package.json:5

  • PR metadata and the RC1 release docs/audit target 0.2.0-rc.1, but the docs package is versioned as 0.1.0-rc.0. Align the workspace prerelease numbering so release notes and deployed docs map to the same RC.
  "version": "0.1.0-rc.0",

scripts/smoke-install-linux.sh:12

  • The release workflow uploads an additional Linux .rpm artifact (semifold-ci.yaml includes bundle/appimage/.rpm), but the Linux isolated-install smoke script only checks for AppImage and .deb. That means a missing/broken RPM could still be uploaded while smoke checks pass.
appimage=$(find "$bundle_root/appimage" -maxdepth 1 -type f -name '*.AppImage' -print -quit)
deb=$(find "$bundle_root/deb" -maxdepth 1 -type f -name '*.deb' -print -quit)
rpm=$(find "$bundle_root/rpm" -maxdepth 1 -type f -name '*.rpm' -print -quit)

if [ -z "$appimage" ] || [ -z "$deb" ] || [ -z "$rpm" ]; then

Copilot AI review requested due to automatic review settings August 4, 2026 06:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 22 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

scripts/smoke-install-windows.ps1:16

  • This assumes $env:RUNNER_TEMP is always set. In GitHub Actions it is, but running the script locally (or in other CI) can fail because Join-Path cannot accept a null base path. Use a temp-path fallback.
$smokeRoot = Join-Path $env:RUNNER_TEMP ("dropout-install-smoke-" + [guid]::NewGuid())
$installRoot = Join-Path $smokeRoot "installed"

scripts/parity-audit.test.mjs:92

  • The audit file controls evidence.path, and resolve(repoRoot, evidence.path) will happily accept absolute paths or .. traversal. That lets a modified audit point the test at arbitrary filesystem paths (e.g. /etc/passwd) and attempt to read them. Restrict evidence to paths that remain within repoRoot before checking existence/content.
      const evidencePath = resolve(repoRoot, evidence.path);
      assert.equal(
        existsSync(evidencePath),
        true,
        `${row.id} points to missing evidence ${evidence.path}`,

Comment thread scripts/smoke-install-macos.sh Outdated
Copilot AI review requested due to automatic review settings August 4, 2026 06:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 22 changed files in this pull request and generated no new comments.

Suppressed comments (4)

scripts/release-workflow.test.mjs:56

  • This test creates a temp fixture directory but never deletes it. Over time (and especially when re-running locally), this can accumulate temp dirs; register a cleanup hook so the fixtureRoot is removed even if assertions fail.
test("post-version hook synchronizes every generated release manifest", () => {
  const fixtureRoot = mkdtempSync(join(tmpdir(), "dropout-release-manifests-"));

scripts/parity-audit.test.mjs:92

  • Resolved evidence paths are only checked for existence; they should also be required to remain within repoRoot so the audit cannot be satisfied by pointing to files outside the checkout.
      const evidencePath = resolve(repoRoot, evidence.path);
      assert.equal(
        existsSync(evidencePath),
        true,
        `${row.id} points to missing evidence ${evidence.path}`,
      );

scripts/parity-audit.test.mjs:3

  • The parity audit contract resolves evidence paths relative to repoRoot but doesn't enforce that the resolved path stays within the repository. That leaves a loophole where evidence can point outside the repo (e.g. ../../some-file-on-runner) and still satisfy existsSync/match checks.

This issue also appears on line 87 of the same file.

import { resolve } from "node:path";

scripts/release-workflow.test.mjs:3

  • The test creates temporary fixture directories via mkdtempSync but does not import any cleanup helper (e.g. rmSync). This makes it easy to accidentally leak temp directories on CI runners as these tests evolve; add rmSync so the fixture root can be removed after the test completes.

This issue also appears on line 55 of the same file.

import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";

@HsiangNianian
HsiangNianian merged commit 01a1cb7 into main Aug 4, 2026
25 of 26 checks passed
@HsiangNianian
HsiangNianian deleted the feat/rc1-parity-audit branch August 4, 2026 06:29
HsiangNianian added a commit that referenced this pull request Aug 4, 2026
# Releases

## @dropout/docs

## v0.1.0-rc.1

### New Features

-
[`e0cc80d`](e0cc80d):
Add a machine-checked 42-row launcher parity audit, bilingual RC1
evidence guides, isolated installer smoke tests across every supported
desktop target, and durable release-manifest synchronization.
([#203](#203) by
@HsiangNianian)

## @dropout/ui

## v0.1.0-rc.1

### New Features

-
[`e0cc80d`](e0cc80d):
Add a machine-checked 42-row launcher parity audit, bilingual RC1
evidence guides, isolated installer smoke tests across every supported
desktop target, and durable release-manifest synchronization.
([#203](#203) by
@HsiangNianian)

## dropout

## v0.2.0-rc.1

### New Features

-
[`e0cc80d`](e0cc80d):
Add a machine-checked 42-row launcher parity audit, bilingual RC1
evidence guides, isolated installer smoke tests across every supported
desktop target, and durable release-manifest synchronization.
([#203](#203) by
@HsiangNianian)

## Summary by Sourcery

Prepare rc.1 release candidates across docs, UI, and desktop app
packages.

New Features:
- Document the rc.1 feature set for @dropout/docs, @dropout/ui, and the
Tauri desktop app in their changelogs.

Enhancements:
- Bump @dropout/docs and @dropout/ui to version 0.1.0-rc.1 and the Tauri
desktop app to 0.2.0-rc.1, aligning manifests and configuration with the
new release candidate.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Audit and prove PCL, HMCL, and PrismLauncher parity for the release candidate

2 participants