## Summary
- run only Dart formatting for mobile changes during pre-commit
- move Flutter static analysis to the path-scoped pre-push graph
- fix case-sensitive `Justfile` triggers for the Rust and Tauri pre-push
gates
- skip whole-tree desktop/web formatting for lockfile-only commits while
retaining every lockfile-triggered pre-push check
No test suite was removed or narrowed. Cargo formatting remains
workspace-scoped; frontend and mobile source changes still select their
existing formatters.
## Benchmark
Warm isolated timings on an M2 Max:
- `dart format .`: 1.92–2.23s
- `flutter analyze`: 5.58–7.51s
- old forced full pre-commit: 10.16–18.40s
- current forced full pre-commit at `f18d9b5`: 5.42–7.09s, median 6.29s
(45% lower)
- current forced full pre-push at `f18d9b5`: 2m45s, effectively
unchanged from the prior warm 2m41s run
- lockfile-only pre-commit after the follow-up: 0.18–0.19s across three
runs
The new mobile analysis lane finishes before the existing mobile test
lane, so it added no observed full-push wall time.
## Validation
At pushed head `79626be60d89ba34e0fe136f254cc38cf1f1c2b8`:
- `lefthook validate`
- isolated temporary-repository selection test:
- `Justfile` selects both Rust and Tauri pre-push gates
- `pnpm-lock.yaml` selects neither mutating frontend formatter
- desktop/web source files still select their formatter
- lockfile-only pre-commit: 0.19s, 0.19s, 0.18s
- pre-push hook passed on the exact pushed head
Earlier full-cycle validation at
`f18d9b5802f11543e8afbef3cd54c5928817e32b`:
- forced full pre-commit: 5.42s, 6.29s, 7.09s
- forced full pre-push: 2m45s; all lanes passed
- mobile tests: 1,465 passed
---------
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- make the differential file-size ratchet a first-class repository gate
- run the same unfiltered gate from pre-push, `just check`, and CI
- remove hidden file-size coupling from Desktop, Web, and Mobile lint
commands
- isolate ratchet Git subprocesses from hook-exported repository state
## Why
The Desktop ratchet grew to govern `desktop/src-tauri/crates/**`, but
the pre-push `desktop-check` command remained path-filtered to non-Tauri
files. That contract drift allowed a Tauri Rust file-size regression
through local validation.
The ratchet already computes its own merge-base diff, so duplicating
governed paths in Lefthook and CI adds drift risk without meaningful
runtime savings. One root gate owns the policy now.
## Testing
- `just file-size-check`
- oversized untracked probe under `desktop/src-tauri/crates/**` fails
with the 1,000-line ceiling
- file-size core tests with hook-style `GIT_DIR` / `GIT_WORK_TREE`
environment
- `lefthook dump` confirms the unfiltered pre-push command
- mandatory pre-push suite passed on
`3217003db10c84d8a0c5f636ec4c92936777a002`
- `git diff --check`
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
The local pre-push gate ran biome (`desktop-check`) and node:test
(`desktop-test`) for desktop changes but never `tsc`, so TypeScript
errors surface no earlier than CI's `desktop-core` job (`just
desktop-build` = `tsc && vite build`). A branch with type errors passes
every local hook today.
This adds a `desktop-typecheck` pre-push command running `just
desktop-typecheck` (`tsc --noEmit`) with the same glob/exclude as
`desktop-check`, and updates the hook documentation in `AGENTS.md`. CI
is unchanged — it already typechecks via `desktop-build`.
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
## Summary
- combine Desktop Tauri clippy and tests into one pre-push command
- run clippy first, then tests
- keep unrelated pre-push commands parallel
## Why
PR #3555 added clippy as a separate command while the pre-push group
uses `parallel: true`. That can start clippy and tests simultaneously
against the same Cargo target directory, leaving one command waiting on
Cargo's build lock and making pushes appear stalled.
Serializing only these two Cargo-heavy checks avoids lock contention
while retaining the CI-equivalent clippy command and existing test
coverage.
## Validation
- `lefthook validate`
- forced `desktop-tauri-checks` through Lefthook with an instrumented
`just`; observed `desktop-tauri-clippy` followed by `desktop-tauri-test`
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- run Desktop Tauri clippy from pre-push for every path that can affect
the Tauri crate
- reuse `just desktop-tauri-clippy`, keeping the local command identical
to Desktop Core CI
- leave the existing Tauri test hook unchanged
## Why
PR #3553 exposed a hook gap: `cargo test` allowed an unused-import
warning that CI's `clippy -D warnings` correctly rejected. Running the
same recipe before push catches that class of failure locally without
duplicating CI flags in Lefthook.
## Validation
- `lefthook run pre-push --command desktop-tauri-clippy --force`
- confirmed it invokes `cargo clippy --manifest-path
desktop/src-tauri/Cargo.toml --all-targets -- -D warnings`
- command passed
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
`DCO Check` is a required status check on this repo and the top failing
check on open contributor PRs, but nothing documented it and nothing
surfaced it locally — a missing `Signed-off-by` trailer only showed up
as a red check after the PR was already open.
## `lefthook.yml`
New `commit-msg` hook that appends the `Signed-off-by` trailer:
```yaml
commit-msg:
commands:
signoff:
run: 'git interpret-trailers --if-exists doNothing --trailer "Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed ''s/ [0-9]* [+-][0-9]*$//'')" --in-place {1}'
```
`GIT_COMMITTER_IDENT` is the identity that performed the commit, which
is what a DCO sign-off certifies and what native `git commit -s` uses.
Committing someone else's work with `--author` or `git commit -C`
therefore signs off as you, not as the original author.
`--if-exists doNothing` makes it idempotent: `git commit -s` still
yields exactly one trailer, and an existing sign-off from a different
signer is preserved rather than supplemented. An empty commit message
still aborts — the hook does not turn one into a commit body containing
only a trailer.
Git runs `commit-msg` for `git commit` and `git merge` only. Other flows
bypass it and need their own sign-off flag — `git rebase --signoff`,
`git cherry-pick -s`. Note `-s` is `--strategy` on `git rebase`, so only
the long flag works there. The header comment and both docs state the
scope rather than promising blanket coverage. Installed by `just hooks`;
`commit-msg` carries no `glob` because it rewrites the message, not
files.
## `CONTRIBUTING.md`
`Before You Open a PR` gains a paragraph on sign-off: commit with `git
commit -s`, what the trailer certifies, that the required `DCO Check`
blocks merge without it, `git rebase --signoff main` to repair
already-pushed commits, and what the hook does and does not cover.
`CI Gate` gains one sentence pointing at `just fix-all` for
formatting-only failures.
## `AGENTS.md`
`Quality Gates` gains the same requirement framed for agents, including
the sequencer caveat and the reminder to include `-s` in
programmatically built commit commands.
## Related issue
none found
---------
Signed-off-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
## Summary
- Activate lefthook pre-commit and pre-push hooks that have existed in `lefthook.yml` since the initial desktop app but were never wired up.
- Add `just hooks` recipe: sets `core.hooksPath = .hooks` and runs `lefthook install --force` to generate hook scripts.
- Wire hook installation into `scripts/dev-setup.sh` so hooks activate automatically on `just setup`.
- Enable `parallel: true` for pre-commit hooks (pre-push already had it) — all 5 format/lint checks run simultaneously.
- Add `just mobile-fmt` recipe (`dart format .`) and `just fmt-all` recipe (Rust root + Tauri Rust + Dart) as one-shot formatters.
- `.hooks/` is gitignored since lefthook generates machine-specific scripts.
- Update `AGENTS.md`: document pre-commit/pre-push hooks in Quality Gates, add `just fmt-all` and `just hooks` usage, upgrade worktree fmt gotcha from CI note to commit blocker, add `just mobile-fmt` to mobile commands; also backfill CLI-first updates (`SPROUT_AUTH_TAG`, complete exit codes, `--format compact` flag position, two new gotchas).
All hook commands delegate to `just` recipes as the single source of truth.