Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ updates:

# Cargo / Rust (Tauri desktop backend)
# QNBS-v3: separate from npm — Cargo updates affect src-tauri/ only; group all together to reduce PR noise
# QNBS-v3: no cross-ecosystem grouping exists for the npm @tauri-apps/plugin-* counterparts — see docs/DEPENDABOT-TRIAGE.md's "Special-attention dependencies" row (this gap caused v1.28.5).
Comment thread
qnbs marked this conversation as resolved.
Outdated
- package-ecosystem: cargo
directory: /src-tauri
schedule:
Expand Down
20 changes: 19 additions & 1 deletion .github/workflows/tauri-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,31 @@ jobs:
GITHUB_TOKEN: ${{ github.token }}
run: node scripts/signing/verify-github-signatures.mjs

# QNBS-v3: cheap defense-in-depth gate (no pnpm install needed) so a Rust/npm plugin mismatch fails in seconds, not after the ~45min matrix — the v1.28.5 failure class.
parity-preflight:
Comment thread
qnbs marked this conversation as resolved.
name: 🔍 Tauri plugin parity preflight
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
with:
node-version-file: .nvmrc
- name: Verify Tauri plugin Rust/npm version parity
run: node scripts/check-tauri-plugin-versions.mjs
Comment thread
qnbs marked this conversation as resolved.

bundle:
name: Bundle (${{ matrix.os }})
needs: [verify-release-tag]
needs: [verify-release-tag, parity-preflight]
Comment thread
qnbs marked this conversation as resolved.
if: >-
${{
always() &&
!cancelled() &&
needs.parity-preflight.result == 'success' &&
(
github.event_name == 'workflow_dispatch' ||
needs.verify-release-tag.result == 'success'
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`@puppeteer/browsers@3.x` dependency replaced `extract-zip` with `modern-tar` entirely — the
package now has zero occurrences in the resolved graph. Lighthouse 13.4.1 requires Node
`>=22.19`, so the repository's own `engines.node` floor is raised to match. PR #682.
- **Tauri release build now fails fast on a plugin version mismatch:** `tauri-build.yml`'s
cross-platform bundle matrix (~45 min) previously started right after tag-signature
verification, with no cheap check for the exact Rust/npm plugin mismatch that broke every
platform's `v1.28.5` release build. Added a `parity-preflight` job (checkout + one dependency-free
Node script, no `pnpm install`) that runs `check-tauri-plugin-versions.mjs` before the bundle
matrix starts, on both `workflow_dispatch` and tag pushes. PR #684.

### Documentation

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<img src="https://img.shields.io/badge/Storage-IndexedDB_v8-F59E0B" alt="IndexedDB v8">
<img src="https://img.shields.io/badge/PWA-v3.0-5BB974?logo=pwa" alt="PWA v3.0">
<img src="https://img.shields.io/badge/i18n-19_locales-2942_keys-0EA5E9" alt="i18n 19 locales — 2942 keys">
<img src="https://img.shields.io/badge/Tests-7643%2B_%2F_604_files-22C55E" alt="7643+ tests / 604 files">
<img src="https://img.shields.io/badge/Tests-7644%2B_%2F_604_files-22C55E" alt="7644+ tests / 604 files">
<img src="https://img.shields.io/codecov/c/github/qnbs/WorldScript-Studio?logo=codecov&label=Coverage" alt="Codecov Coverage">
<img src="https://img.shields.io/badge/License-MIT-22C55E" alt="License MIT">
<img src="https://img.shields.io/github/actions/workflow/status/qnbs/WorldScript-Studio/.github/workflows/ci.yml?branch=main&logo=github" alt="CI Status">
Expand Down Expand Up @@ -511,7 +511,7 @@ The Settings → AI panel shows a live GPU status badge with adapter details and
| **Document Export** | docx + jszip | Word-compatible `.docx` generation (lazy-loaded) |
| **PWA** | Service Worker + Web App Manifest v3 | Offline support, installability, Workbox chunking |
| **i18n** | Custom React Context (`I18nContext.tsx`) | 2942 keys × 19 locales (de/en/es/fr/it + ar/he/fa RTL Beta + ja/zh/pt/el/fi/sv/hu/is/eu/ru/ko Beta); EN fallback; `localStorage` persistence |
| **Testing** | Vitest 4.x (7643+ tests / 604 files) + Playwright E2E | Unit/integration + cross-browser E2E; Stryker mutation (manual workflow) |
| **Testing** | Vitest 4.x (7644+ tests / 604 files) + Playwright E2E | Unit/integration + cross-browser E2E; Stryker mutation (manual workflow) |
| **Code Quality** | Biome (lint + format) + TypeScript 7 (tsgo) strict | `--error-on-warnings` in CI; zero `any` policy |
| **Visualization** | Force-directed graph | Interactive character relationship network |
| **Desktop** | Tauri v2 | Cross-platform installer; auto-updater via `latest.json` |
Expand Down Expand Up @@ -549,7 +549,7 @@ WorldScript-Studio/
│ ├── sw.js # PWA Service Worker
│ └── manifest.json # PWA Web App Manifest v3
├── tests/
│ ├── unit/ # Vitest unit tests (7643+ tests, 604 files) — count spans tests/, components/, packages/*/tests/, not just this folder
│ ├── unit/ # Vitest unit tests (7644+ tests, 604 files) — count spans tests/, components/, packages/*/tests/, not just this folder
│ │ ├── ai/ # aiSmallModules, aiCoreFallbackPaths
│ │ └── settings/ # WebLlmPanel, AiSections
│ └── e2e/ # Playwright specs + helpers.ts
Expand Down Expand Up @@ -714,7 +714,7 @@ The main pipeline is [`.github/workflows/ci.yml`](.github/workflows/ci.yml). Opt
Raw bundle-budget ceilings (KB per uncompressed asset): entry **2500 KB**, vendor **6200 KB**, other JavaScript **2500 KB**, and WASM **30000 KB**.

**Current test metrics (2026-09-07, source-synchronized; CI remains authoritative for pass/fail):**
- **7643+ unit tests** across **604 test files** — CI is authoritative for pass/fail
- **7644+ unit tests** across **604 test files** — CI is authoritative for pass/fail
- Coverage thresholds: lines ≥ 80 · branches ≥ 66 · functions ≥ 72 · statements ≥ 78 — enforced in CI (see Codecov badge for live metrics)
- i18n: **2942 keys × 19 locales** (en/de/fr/es/it + ar/he/fa RTL Beta + ja/zh/pt/el/fi/sv/hu/is/eu/ru/ko Beta)

Expand Down
2 changes: 1 addition & 1 deletion docs/DEPENDABOT-TRIAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ These need more than a changelog skim because of documented quirks elsewhere in
| `vite` | Production build uses **rolldown**, not esbuild/rollup; verify the current `vite.config.ts` and `package.json` `sideEffects` contract. Rolldown ignores `rollupOptions.treeshake` and ties tree-shaking to `package.json "sideEffects"` — a Vite bump that changes how a dependency's `sideEffects` field is honored can produce a blank-screen prod build that CI's `vite dev`-based E2E suite won't catch. Run `pnpm run build && pnpm run smoke:prod` after any Vite bump, not just CI green. |
| `zod` | Has a repo-local patch (`patches/zod@4.4.3.patch`, forces `"sideEffects": true`) applied via `pnpm patch`. A version bump may need the patch re-applied/re-verified against the new version. |
| `react` / `react-dom` | Already grouped — must stay in lockstep, split bumps cause version-mismatch errors at test time. |
| `tauri*` / `wry` / `tao` | Already grouped (`tauri-deps`) — same lockstep concern for the desktop backend. |
| `tauri*` / `wry` / `tao` (Cargo) and `@tauri-apps/plugin-*` (npm) | The Cargo-side `tauri-deps` group only covers Rust crates — Dependabot cannot group across the `npm` and `cargo` ecosystems, so a `tauri-plugin-*` Rust bump and its npm `@tauri-apps/plugin-*` counterpart always arrive as two separate, uncoordinated PRs (or just one side, if only one crate/package actually changed upstream). This exact gap caused v1.28.5's tag-triggered release build to fail on every platform (#661 bumped only the Rust side via Dependabot; `tauri build` hard-rejects a Rust/npm major.minor mismatch). **This is caught automatically:** `pnpm run tauri-plugins:check` (`scripts/check-tauri-plugin-versions.mjs`) runs unconditionally in `ci.yml`'s `quality` job on every PR — including a Cargo-only Dependabot PR — and fails closed on a mismatch; `tauri-build.yml` additionally runs the same check as a cheap `parity-preflight` job before its ~45min cross-platform bundle matrix. If a Cargo `tauri-deps` Dependabot PR fails this check: **bump the matching `@tauri-apps/plugin-*` npm package(s) to the version the failure message names, in the same PR** (or a same-day companion PR) — never dismiss or loosen the check itself. |
Comment thread
qnbs marked this conversation as resolved.
Outdated
Comment thread
qnbs marked this conversation as resolved.
Outdated
| `github/codeql-action*` | Already grouped — see incident above. |
| `@biomejs/biome` | Check the installed package version against `biome.json`'s `$schema` URL after every bump; the schema URL is versioned independently from the npm dependency declaration. |
| Any WASM/WebGPU-adjacent package (`@huggingface/transformers`, `@mlc-ai/web-llm`, `onnxruntime-web`) | These ship in `vendor-*` SW-excluded chunks (`vite.config.ts` `globIgnores`) — verify a version bump didn't change the package's exported chunk structure in a way that breaks the manual-chunk mapping. |
Expand Down
15 changes: 14 additions & 1 deletion tests/unit/workflowPolicy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,10 @@ describe('Tauri release workflow policy', () => {

it('requires successful tag verification before tagged bundles, while allowing manual builds', () => {
const bundle = extractJobBlock(tauriWorkflowSource, 'bundle');
expect(extractNeeds(tauriWorkflowSource, 'bundle')).toEqual(['verify-release-tag']);
expect(extractNeeds(tauriWorkflowSource, 'bundle')).toEqual([
'verify-release-tag',
'parity-preflight',
]);
expect(bundle).toContain('always()');
expect(bundle).toContain('!cancelled()');
expect(bundle).toMatch(/github\.event_name == 'workflow_dispatch'/);
Expand All @@ -255,6 +258,16 @@ describe('Tauri release workflow policy', () => {
expect(bundle).toContain('Skip updater signing for workflow_dispatch test builds');
});

it('requires the plugin parity preflight to pass, unconditionally, before bundling', () => {
const bundle = extractJobBlock(tauriWorkflowSource, 'bundle');
const preflight = extractJobBlock(tauriWorkflowSource, 'parity-preflight');
expect(bundle).toMatch(/needs\.parity-preflight\.result == 'success'/);
Comment thread
qnbs marked this conversation as resolved.
Outdated
expect(extractNeeds(tauriWorkflowSource, 'parity-preflight')).toEqual([]);
expect(preflight).toContain('scripts/check-tauri-plugin-versions.mjs');
expect(preflight).not.toContain('pnpm install');
expect(preflight).toMatch(/^ {4}permissions:\n {6}contents: read\s*$/m);
});

it('keeps release publication tag-only and downstream of bundle output', () => {
const release = extractJobBlock(tauriWorkflowSource, 'release');
expect(extractNeeds(tauriWorkflowSource, 'release')).toEqual(['bundle']);
Expand Down
Loading