ci: cross-platform matrix, full build verify, fmt+lint enforcement#208
Merged
ci: cross-platform matrix, full build verify, fmt+lint enforcement#208
Conversation
First pass before the new fmt/lint CI gates land. cargo fmt --all on src-tauri reformatted 11 Rust files (mostly long argument lists and indentation). prettier --write . reformatted ~60 frontend/docs files (Svelte, TypeScript, JSON, Markdown). One Svelte file (HelpModal) was unstable in a single prettier pass and needed a second --write. eslint debt is not addressed here — 59 errors remain across 8 rule categories, including svelte/prefer-svelte-reactivity (Svelte 5 migration) and svelte/no-at-html-tags (security review needed). Those need real code changes and will be tracked separately.
Splitting `npm run lint` into two steps lets the cross-platform CI
land green while we clear 59 existing eslint errors (Svelte 5 runes
migration, unused vars, missing each-block keys, {@html} review).
Flip continue-on-error to false once the debt is paid.
Resolves conflict in .claude/PROGRESS.md by taking main's v0.10.0 docs content as the source of truth, then re-running prettier on the three docs files to keep them formatter-clean.
The previous merge resolution ran prettier once on this file, but prettier needs two passes to reach a fixed point on it (likely a plugin-svelte / markdown-table interaction). Without the second pass, prettier --check fails CI even though prettier --write was just run.
This was referenced May 3, 2026
Last CI run hung for 39 minutes inside Tauri's rpm bundler before the 45-minute timeout killed it. Cargo compile took only 3m17s and the .deb bundle finished in 13s; the rpm step never made progress. Pass --bundles deb,appimage to match the Linux targets we actually ship in release.yml (no rpm in the release matrix). With rpm out of the way, the job should finish well under the new 25-minute cap.
stultus
added a commit
that referenced
this pull request
May 3, 2026
Cleaned the eslint debt that has been hanging behind `continue-on-error: true` since the CI matrix landed (#208), so ESLint can stand alongside Prettier as a blocking gate. By rule: - **svelte/no-unused-svelte-ignore (×11)** — dropped now-dead `<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->` comments above modal backdrops + dropdowns. Svelte's a11y rules recognise `role="dialog"` context now and don't fire on these. Files: AboutModal, EpisodeCardsView, ExportModal, HelpModal, ImportWizardModal, MetadataModal, NewProjectDialog, PasteScriptDialog, SettingsModal (×2), StatisticsModal. Also fixed EpisodeCardsView where the actually-needed suppression was `_noninteractive_`, not `_static_`. - **svelte/require-each-key (×10)** — added stable keys to every `{#each}` block. Picked natural keys where one existed (cell.date ISO, char.name, loc.name, row.sceneNumber, line.label, tab.id, warning text), index where the list is positional and never reorders (peek headings, weekday names). - **svelte/prefer-svelte-reactivity (×12)** — split into three treatments based on use-site: - DatePicker mutated-then-assigned `Date` objects → refactored to immutable `new Date(y, m, d)` construction (cleaner anyway). - Editor's `collapsedSlots` was a mutable `Set` rebuilt on every toggle → replaced with `SvelteSet` from `svelte/reactivity`. `.add`/`.delete` now reactively triggers updates without the new-Set dance; one downstream call site changed from reassignment to `.clear()`. - StatisticsModal's seven Maps + SceneCardsView's one Map are transient compute scratchpads inside `$derived.by` callbacks that never escape — converted SceneCardsView's to a `Record<string, number>`; for the StatisticsModal block, added a single `eslint-disable svelte/prefer-svelte-reactivity` region wrapping the compute function with a rationale. - **typescript-eslint/no-unused-vars (×9)** — dropped genuinely unused vars (`isMalayalam` in Editor, `currentMode` in StoryModeView, `StatusBar` import + `startPos` local in SceneCardsView, `isPointerOverBubble` + its handlers + bindings in FormatBubble). For intentionally-unread reactive-dep names, configured `varsIgnorePattern: '^_'` / `argsIgnorePattern: '^_'` in eslint.config.js so leading-underscore signals "read for subscription". Adjusted `findReplace.ts` Plugin.state.init to drop both unused params. - **typescript-eslint/no-unused-expressions (×5)** — Svelte 5's bare-property-read pattern for `$effect` / `$derived.by` dependency declaration tripped this. Reassigned each to a `_-prefixed` const which the leading-underscore convention ignores; comment explains "read for subscription" intent. - **svelte/no-dom-manipulating (×2)** — SceneCardsView's drag ghost overlay genuinely needs imperative `replaceChildren()`. Per-line disable with rationale (the ghost owns its own subtree; Svelte runtime doesn't render into it). - **svelte/no-at-html-tags (×2)** — both sites render hand-authored literal HTML (`'Title <em>your</em> film'`) with no user-input flow. Per-line disable with the safety rationale inline. - **no-control-regex (×1)** — ExportModal's filename sanitiser intentionally strips `\x00–\x1f`. Per-line disable. CI workflow updated: ESLint step is now blocking, with a comment pointing back at this commit for the rationale. All gates green: 116 cargo tests pass, clippy clean, svelte-check 0/0 across 319 files, prettier clean, eslint clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three changes to
.github/workflows/ci.yml:cargo fmt --check,clippy, andcargo test --libonubuntu-22.04,macos-latest, andwindows-latestinstead of Linux only. Catches platform-specific Rust breakage at PR time instead of at tag time.buildjob runscargo tauri build --debugon Linux afterrustandfrontendpass — verifies the full frontend → cargo → tauri-cli pipeline actually produces a bundle. Static checks alone don't guarantee the app builds.cargo fmt --check(Rust side) andnpm run lint(=prettier --check . && eslint ., perpackage.json) to the frontend job.Also added: workflow-level
permissions: contents: read(least-privilege) andtimeout-minuteson every job (avoid runaway runs eating action minutes).Heads-up
If
cargo fmtornpm run lintfinds existing drift, this PR will fail its own CI on those checks. Fix is to runcargo fmt --all(insrc-tauri/) andnpm run formatlocally, commit the fixups onto this branch, and push.Why
Repo hygiene: existing CI was Linux-only and didn't gate on formatter / lint / full-build. Cross-platform breakage was being caught at release time instead of PR time.