Skip to content

Persist stable recording timestamps and use them for recordingDate - #87

Merged
bisonbet merged 3 commits into
v1.10from
codex/add-date-and-time-tracking-to-recordings
Apr 23, 2026
Merged

Persist stable recording timestamps and use them for recordingDate#87
bisonbet merged 3 commits into
v1.10from
codex/add-date-and-time-tracking-to-recordings

Conversation

@bisonbet

Copy link
Copy Markdown
Owner

Motivation

  • Recordings currently relied on file creation/modification metadata which can change and is unreliable for the actual capture time.
  • The app needs a stable, explicit timestamp captured at recording start so displayed and stored recordingDate matches the true capture time.
  • Sidecar metadata avoids depending on filesystem timestamps and supports recovery/merge/live-transcribe flows.

Description

  • Added an in-memory recordingStartedAt property to AudioRecorderViewModel and set it at the start of setupRecording() via let recordingStartDate = Date().
  • Persisted the capture timestamp to a sidecar file next to the audio file using a new RecordingTimestampMetadata struct and persistRecordingCapturedAt(_:for:) which writes a .recordingmeta file.
  • Introduced currentRecordingDate(for:) to prefer the in-memory timestamp, then read the sidecar .recordingmeta, and finally fall back to Date().
  • Updated all recording-save code paths (audioRecorderDidFinishRecording, interruption recovery, unprocessed/background recovery, merged-segments completion, and live-transcription save) to pass currentRecordingDate(for:) to RecordingWorkflowManager.createRecording(...) and to clear recordingStartedAt after persistence.

Testing

  • Attempted to run an Xcode build listing with xcodebuild -list -project 'BisonNotes AI/BisonNotes AI.xcodeproj', but it failed in this environment because xcodebuild is not available.
  • Changes were committed locally (commit message: Persist explicit recording start timestamps and use them for recording dates).

Codex Task

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a16081418

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

do {
try data.write(to: recordingTimestampMetadataURL(for: url), options: .atomic)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clean up .recordingmeta sidecars on recording deletion

persistRecordingCapturedAt now creates a .recordingmeta sidecar for every recording, but there is no corresponding cleanup path for that file type (for example, EnhancedFileManager.deleteRecording removes only the audio file and .location, and the fallback deletes in RecordingsListView/TranscriptViews also remove only known file types). This leaves orphaned metadata files behind whenever a recording is deleted, which introduces silent storage growth and stale on-disk artifacts over time.

Useful? React with 👍 / 👎.

…estamp

Address review feedback: the new .recordingmeta sidecar files were not
being cleaned up when recordings were deleted, causing silent storage
growth. Add cleanup to all four deletion paths (EnhancedFileManager,
TranscriptViews, RecordingArchiveService, orphan cleanup). Also fix
generateAppRecordingDisplayName() to use recordingStartedAt so the
display name timestamp matches the persisted recordingDate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eaf90b7d12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +286 to +287
if let recordingStartedAt {
return recordingStartedAt

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope start timestamp to the recording URL

currentRecordingDate(for:) currently returns recordingStartedAt for any URL, so a start time from one session can be applied to a different file. This is reachable when stopRecording() kicks off mergeRecordingSegments() asynchronously and the user starts a new recording before merge persistence runs: recordingStartedAt now points to the new session, and the merge path stamps the older merged file with the wrong recordingDate. That can reorder recordings and corrupt historical capture times; the in-memory timestamp should only be used for the matching active URL (or sidecar should be preferred for other URLs).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@claude please address this comment

@claude claude Bot Apr 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude finished @bisonbet's task in 1m 47s —— View job


Addressing review comment: Scope start timestamp to the recording URL

  • Gather context and read relevant files
  • Implement fix: change recordingStartedAt to a URL-keyed tuple
  • Update currentRecordingDate(for:) and generateAppRecordingDisplayName()
  • Commit and push changes

What changed:

recordingStartedAt was Date? — a bare timestamp with no URL binding. The race condition: stopRecording() kicks off mergeRecordingSegments() async, user starts a new recording before merge persistence runs, and currentRecordingDate(for: mergedURL) returns the new session's start time.

Fix: Changed recordingStartedAt: Date?recordingStartedAt: (url: URL, date: Date)? in AudioRecorderViewModel.swift. currentRecordingDate(for:) now only uses the in-memory timestamp when the URL matches the active recording:

// Before
if let recordingStartedAt {
    return recordingStartedAt  // returned for ANY url
}

// After
if let entry = recordingStartedAt, let url, entry.url == url {
    return entry.date  // only returned for the matching active URL
}
// Falls through to sidecar read for all other URLs

For any URL that isn't the currently active recording, the method now falls through to read the persisted .recordingmeta sidecar — which is exactly what was already written at recording start via persistRecordingCapturedAt. All nil-clearing sites are unchanged (assigning nil to an optional tuple works identically).

Commit: b6c66b6
|

Change recordingStartedAt from Date? to (url: URL, date: Date)? so
currentRecordingDate(for:) only returns the in-memory start time when
the provided URL matches the active recording URL. Previously, an async
merge that completed after a new recording started would pick up the new
session's timestamp for the old merged file, corrupting its recordingDate.

Co-authored-by: Tim Champ <bisonbet@users.noreply.github.com>
@bisonbet
bisonbet merged commit f9c0ee5 into v1.10 Apr 23, 2026
1 check failed
@bisonbet
bisonbet deleted the codex/add-date-and-time-tracking-to-recordings branch April 23, 2026 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant