Skip to content

feat(state): track library timestamps - #203

Merged
thewrz merged 5 commits into
mainfrom
feat/issue-195
Jul 21, 2026
Merged

feat(state): track library timestamps#203
thewrz merged 5 commits into
mainfrom
feat/issue-195

Conversation

@thewrz

@thewrz thewrz commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Why

List controls need stable modified and date-added sort keys without losing first-seen history when a library scan is only partial.

What

  • records filesystem modification timestamps on scanned sounds
  • persists first-seen timestamps in a versioned, legacy-compatible metadata envelope
  • distinguishes complete scans from detectable partial scans before pruning stale timestamps
  • protects corrupt, malformed, or future-version metadata from destructive overwrite
  • reconciles timestamps during startup and manual rescans while keeping usable in-memory results after save failures

Design decisions

  • uses epoch milliseconds and standard-library time conversion with checked integer conversion
  • treats missing roots, non-directory roots, and walk errors as incomplete; an existing empty directory remains complete because portable code cannot distinguish an intentionally empty library from an unmounted empty mountpoint
  • keeps custom metadata and first-seen timestamps in separate maps so default customizations remain pruned

Testing

  • cargo fmt -- --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo test (614 library tests plus binary/integration/doc targets)
  • cargo deny check
  • cargo build --release
  • Live PipeWire feature suite: 6/8 pass; two persistent-sink cleanup assertions also fail unchanged on main
  • CI green

🤖 Co-authored by Codex. Closes #195.

Summary by CodeRabbit

  • New Features

    • Library scans now record each sound’s last modification time.
    • Scan results indicate whether the library was fully scanned, improving handling of unavailable or invalid folders.
    • Sound metadata now tracks when sounds were first discovered.
    • Metadata supports versioned storage while remaining compatible with existing files.
  • Bug Fixes

    • Prevented unreadable or unsupported metadata files from being overwritten.
    • Rescans now safely update sound listings and playback state, including partial scans.

thewrz and others added 2 commits July 20, 2026 08:19
Co-Authored-By: Codex <noreply@openai.com>
Record filesystem modification times and persist stable first-seen timestamps across complete and partial scans. Preserve legacy metadata while blocking unsafe overwrites of unreadable or future formats.

Co-Authored-By: Codex <noreply@openai.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 34ec9977-41b4-4865-8778-55fd4918bbb1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Library scans now return completeness and filesystem modification times. Sound metadata stores first-seen timestamps with versioned persistence and safe overwrite handling. Application startup and rescans consume LibraryScan, reconcile metadata, refresh sounds, and reset duration state.

Changes

Timestamped library metadata

Layer / File(s) Summary
Library scan contract
src/state/library.rs, src/state/library/scan_tests.rs, src/state/mod.rs
Library::scan returns LibraryScan, records modified_ms, reports incomplete roots, and validates epoch conversion.
Sound metadata reconciliation and persistence
src/state/sound_meta.rs, src/state/sound_meta/persistence.rs, src/state/error.rs, docs/superpowers/specs/...
SoundMetaStore tracks first-seen IDs, persists versioned custom and added maps, supports legacy loading, and refuses unsafe overwrites.
Application scan integration
src/main.rs, src/app/mod.rs, src/app/library_scan.rs
Startup and rescans pass LibraryScan through HonkHonk, reconcile metadata, refresh sounds, reconcile playback, and reset duration loading.
Sound entry fixture updates
benches/support/mod.rs, src/app/macros/tests.rs, src/app/playback/test_support.rs, src/app/recording.rs, src/app/mod.rs
Benchmarks and test fixtures initialize SoundEntry.modified_ms as None.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Main
  participant Library
  participant HonkHonk
  participant SoundMetaStore
  Main->>Library: scan configured directories
  Library-->>Main: return LibraryScan
  Main->>HonkHonk: construct with scan
  HonkHonk->>SoundMetaStore: reconcile first-seen IDs
  HonkHonk->>HonkHonk: refresh sounds and duration state
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: tracking library timestamps.
Linked Issues check ✅ Passed The changes implement #195 by adding modified_ms, first-seen added timestamps, pruning, and metadata round-tripping.
Out of Scope Changes check ✅ Passed The changes stay focused on timestamp tracking and its supporting persistence and test updates, with no clear unrelated code changes.
Docstring Coverage ✅ Passed Docstring coverage is 82.35% which is sufficient. The required threshold is 80.00%.

Comment @coderabbitai help to get the list of available commands.

@thewrz

thewrz commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator Author

Local adversarial review gate

External Claude review was not authorized, so I used two independent local adversarial review passes against the exact pushed head (3ebd13d). The first pass found three items and the second pass found one additional malformed-envelope compatibility issue. All 4/4 findings were handled before push, with regression coverage added where applicable. A final head/status check confirms the reviewed commit is unchanged and the worktree is clean.

@thewrz

thewrz commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/app/library_scan.rs (1)

32-39: 🗄️ Data Integrity & Integration | 🔵 Trivial

Consider surfacing reconciled-metadata save failures to the user.

save_reconciled_meta only logs via tracing::warn! when store.save() fails (e.g. the new UnsafeMetadataOverwrite case introduced in this PR). This mirrors the existing persist_config/persist_slots pattern elsewhere in app/mod.rs, so it's consistent with established convention rather than a regression — flagging only as broader guidance, since the app already has a NoticeQueue/Notice::error mechanism that could make silent metadata-persistence failures (favorites/volume/rename edits, first-seen timestamps) visible to the user instead of only appearing in logs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/library_scan.rs` around lines 32 - 39, Surface failures from
store.save() in save_reconciled_meta through the app’s existing
NoticeQueue/Notice::error mechanism, alongside or instead of the tracing
warning. Ensure reconciled metadata persistence failures, including
UnsafeMetadataOverwrite, are visible to users while preserving the existing
should_save guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/app/library_scan.rs`:
- Around line 32-39: Surface failures from store.save() in save_reconciled_meta
through the app’s existing NoticeQueue/Notice::error mechanism, alongside or
instead of the tracing warning. Ensure reconciled metadata persistence failures,
including UnsafeMetadataOverwrite, are visible to users while preserving the
existing should_save guard.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: afa9b243-45d0-450a-a447-1bf0c914b2b0

📥 Commits

Reviewing files that changed from the base of the PR and between 1a2cdb5 and 3ebd13d.

📒 Files selected for processing (14)
  • benches/support/mod.rs
  • docs/superpowers/specs/2026-07-20-issue-195-design.md
  • src/app/library_scan.rs
  • src/app/macros/tests.rs
  • src/app/mod.rs
  • src/app/playback/test_support.rs
  • src/app/recording.rs
  • src/main.rs
  • src/state/error.rs
  • src/state/library.rs
  • src/state/library/scan_tests.rs
  • src/state/mod.rs
  • src/state/sound_meta.rs
  • src/state/sound_meta/persistence.rs

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 20, 2026
@thewrz

thewrz commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator Author

CodeRabbit body nitpick disposition

Handled 1/1 body-only nitpicks with no code change. I verified that reconciliation save failures follow the app’s existing metadata/config/slot persistence convention: retain usable in-memory state and emit a contextual warning. CodeRabbit explicitly identified this as broader guidance rather than a regression. Adding a one-off notice only for scan reconciliation would make persistence-error behavior inconsistent; user-facing persistence notices should be addressed holistically in a separate scoped change.

@thewrz
thewrz marked this pull request as ready for review July 20, 2026 19:43
thewrz and others added 2 commits July 20, 2026 14:54
The merge of main (#202 shared type-to-filter) brought in a test that
constructs SoundEntry without the modified_ms field this PR introduces,
breaking compilation; also restores rustfmt mod-declaration ordering in
app/mod.rs disturbed by the same merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thewrz
thewrz merged commit 8990d1c into main Jul 21, 2026
7 checks passed
@thewrz
thewrz deleted the feat/issue-195 branch July 21, 2026 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(state): capture file modified-time + first-seen (date-added) timestamps

1 participant