Existing agents created before this PR have persona system_prompt and model
values snapshotted onto the agent record. With the new precedence logic
(agent record wins when set), those stale snapshots would be treated as
explicit user overrides, blocking persona updates from taking effect.
Migration: on load, clear system_prompt and model for any record where
persona_id is set. Safe because the old code ignored agent-level overrides
for persona-backed agents — no user has ever set a meaningful override.
Persists after first run so it only executes once.
Also: replace silent unwrap_or_default() on persona-load errors with
eprintln! warnings so corrupted persona files don't silently spawn agents
with no prompt.
resolve_effective_prompt_and_model() now uses this precedence:
1. Agent record system_prompt/model (explicit user override via Edit) → wins
2. Persona's live values (when persona_id resolves) → default
3. None → no prompt/model
To distinguish 'stale snapshot from creation' vs 'explicit user override',
persona-backed agents no longer snapshot system_prompt/model at creation time.
These fields start as None and only get populated when a user explicitly sets
an override via the Edit Agent dialog.
This matches how env_vars already work: per-agent overrides persona on collision.
Tests updated to cover all precedence scenarios:
- Agent override wins over persona
- Persona used when no agent override (the common case)
- Mixed: agent model override + persona prompt
- Fallback when persona not found
- No persona, no record → None
Item 2: build_deploy_payload() now calls resolve_effective_prompt_and_model()
instead of reading stale record.system_prompt / record.model directly. Provider-
backed agents now get the same fresh-persona-read behavior as local spawns.
Item 3: Added doc comment and inline note to resolve_prompt_falls_back_when_persona_not_found
clarifying it tests prompt/model resolution in isolation — a full spawn would
fail closed at resolve_persona_env() if the persona is missing (env_vars may
hold required API credentials).
Extract resolve_effective_prompt_and_model() as a pure, testable function
that resolves the effective system prompt and model for a managed agent.
When persona_id is set, looks up the persona in the store and returns its
current values. Falls back to the record snapshot when no persona is linked
or the persona can't be found.
Add 5 unit tests covering:
- persona_id matches → reads fresh prompt + model
- no persona_id → falls back to record snapshot
- persona_id not found in store → falls back to record snapshot
- no persona and no record prompt → returns None/None
- persona has no model → returns None (doesn't inherit record model)
The release notes extraction failed on two counts: awk errors when
CHANGELOG.md doesn't exist (first release has no changelog), and
head -n -1 is a GNU extension unsupported on macOS runners. Guard
with a file existence check and replace head with sed '$d'.
## 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.