Wires the commit-cadence policy to an actual reminder instead of a script
nobody runs.
- scripts/commit_check_notify.py: runs scripts/commit_check.sh (piped to
bash -s so the script is never opened on the external volume), logs to
logs/commit_check.log and posts a macOS notification via osascript when the
tree is dirty. Defaults to --any (week's work) ; --age-only restores the
>threshold behaviour; --no-notify for testing.
- scripts/commit_check.sh: new --any mode (warn on any uncommitted change,
ignoring age) for the weekly job.
- LaunchAgent fires Sunday 18:00; launcher
~/.umbraaudio/umbra_commit_check.sh mirrors umbraweb_login.sh (cd project,
export PATH, exec .venv/bin/python). The venv python is the only interpreter
approved for the external volume, so a shell never reads a project file.
- Verified under launchd: detects dirty tree, notification sent, exit 1;
clean tree exits 0. Probe artifacts removed.
Mechanical nudge for the policy in AGENTS.md -> "Commit Cadence": it measures
how long the working tree has been dirty (oldest mtime among staged, unstaged
and untracked files) and exits 1 once that exceeds --days (default 7).
- Ignores submodule working-tree dirt (separate repo); still surfaces a moved
submodule pointer.
- Reports dirty age, last edit, last commit; prints a reminder block.
- --quiet silences the clean case only; --help documents exit codes.
- Bash 3.2 compatible (macOS /bin/bash); no external deps.
- Verified: clean/dirty/old-dirt/threshold/bad-args/quiet all behave.
Also cross-reference it from AGENTS.md and README.md.
Phase A: derive the active project id dynamically (active_project_id) instead of
hard-coded project_id=1 in cli/orchestrator/scripts/web; enable SQLite WAL on the
project + voice-registry DBs; parameterize tts_server/sync_voice_data.sh via
UMBRA_DATA_DIR/PROJECT_SLUG.
Phase B: reusable project_bootstrap.create_project_from_manuscript (+ async
variant for web) boots an isolated project dir + DB from a manuscript; new
POST /api/projects and /projects/new page + "New Project" button let a second
book be created and activated (active_project cookie) without touching the
current project. Fix async route (asyncio.run in running loop) and source-path
persistence ordering bugs in the new endpoint.
Phase C: list_projects() skips the legacy root .umbra so /projects is clean;
load_config() now resolves a bare project name under PROJECT_BASE even when the
dir doesn't exist yet (new-project creation no longer depends on CWD); add
tests/test_multi_project.py (5 tests).
Phase D: scripts/verify_projects.py + scripts/verify_nas.py idempotent
integrity/mirror checkers.
All 249 tests pass.
Add /api/batch/status that parses the running stale-voice rebuild log and reports
the current chapter being regenerated, utterances generated so far, completed
chapters, and last-activity age. Step-6 UI polls it every 2s and shows a
'Background rebuild in progress' panel so users see audio is actively being fixed,
not just idle errors.
- export_full_book_m4b: concat chN_full.wav chapters -> AAC m4b with full
m4b_meta.json metadata, chapter markers, and embedded cover art
- metadata: extend BookMetadata, write rich MP4 tags, add apply_ffmpeg_cover
- fix ChapterQualityChecker.check_all_chapters to use row_factory (was crashing)
- chapter_builder/staleness: validate against accepted voice modes (embedding/icl)
instead of a hardcoded single mode, ending over-regeneration of mixed chapters
- pipeline_manager: surface warnings/errors lists; add POST /api/audiobook/export-m4b
- step-6 webui: Export Full Book (.m4b) button with live status/warnings/errors