Skip to content

fix: create daily notes from date links - #901

Open
jasonlong wants to merge 4 commits into
team-reflect:masterfrom
jasonlong:fix/lazy-daily-date-backlinks
Open

fix: create daily notes from date links#901
jasonlong wants to merge 4 commits into
team-reflect:masterfrom
jasonlong:fix/lazy-daily-date-backlinks

Conversation

@jasonlong

@jasonlong jasonlong commented Jul 21, 2026

Copy link
Copy Markdown

Summary

  • materialize a missing daily note when an ISO or relative-date wiki-link suggestion is selected
  • use the atomic no-clobber note creation boundary so concurrent/existing daily files are never replaced
  • surface background creation failures instead of silently leaving a dangling link
  • cover exact dates, relative dates, existing dailies, invalid dates, and failures

Context

The backlink symptom came from date autocomplete inserting the ISO link without running the V1-compatible daily creation side effect. This fixes that creation path directly rather than synthesizing backlinks for notes that do not exist.

Verification

  • pnpm check
  • pnpm build
  • pnpm --filter @reflect/core test src/graph/create-note.test.ts
  • pnpm --filter @reflect/desktop test src/editor/use-editor-autocomplete.test.tsx

Summary by CodeRabbit

  • New Features
    • Daily notes are now automatically materialized from date-based autocomplete selections, including “pathless date” entries.
    • Newly inserted daily-note links resolve immediately and gain backlinks without requiring navigation.
  • Bug Fixes
    • Existing daily notes are preserved and not recreated.
    • Invalid dates are rejected before any write attempts.
    • Daily-note creation failures now surface operation errors with the underlying cause.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f3619c6-8fe2-4c42-b45b-53dfdd4b302c

📥 Commits

Reviewing files that changed from the base of the PR and between dc5827d and 799906f.

📒 Files selected for processing (4)
  • apps/desktop/src/editor/use-editor-autocomplete.test.tsx
  • packages/core/src/exports/platform.ts
  • packages/core/src/graph/create-note.test.ts
  • packages/core/src/graph/create-note.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/core/src/exports/platform.ts
  • packages/core/src/graph/create-note.test.ts
  • apps/desktop/src/editor/use-editor-autocomplete.test.tsx

Walkthrough

materializeDailyNote creates missing daily files and is exported through the platform API. Date-based wikilink autocomplete now invokes it for pathless suggestions, reports failures through operations, and adds tests for creation, existing notes, invalid dates, and errors.

Changes

Daily note materialization

Layer / File(s) Summary
Core daily note materialization
packages/core/src/graph/create-note.ts, packages/core/src/exports/platform.ts, packages/core/src/graph/create-note.test.ts
Adds and exports materializeDailyNote, which derives daily paths, creates empty notes when absent, preserves existing files, and rejects invalid dates.
Autocomplete daily selection flow
apps/desktop/src/editor/use-editor-autocomplete.ts, apps/desktop/src/editor/use-editor-autocomplete.test.tsx
Pathless date suggestions now materialize daily notes on selection, skip existing daily targets, and report creation failures through the operation handler.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Editor as useEditorAutocomplete
  participant Core as materializeDailyNote
  participant Disk as createNoteIfAbsent
  Editor->>Core: Materialize selected date
  Core->>Disk: Create daily note if absent
  Disk-->>Core: Return ensured note
  Core-->>Editor: Complete selection
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 clearly summarizes the main change: creating daily notes when selecting date links.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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)
apps/desktop/src-tauri/src/db/tests.rs (1)

382-403: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract table count querying into a helper closure.

The logic for querying notes and links table counts is duplicated before and after the migration. You can optionally extract this into a small closure to make the test leaner and avoid repetition.

♻️ Proposed refactor
-    let counts_before: Vec<i64> = ["notes", "links"]
-        .iter()
-        .map(|table| {
-            conn.query_row(&format!("SELECT count(*) FROM {table}"), [], |row| {
-                row.get(0)
-            })
-            .unwrap()
-        })
-        .collect();
-
-    migrate(&mut conn).expect("migrate to v19");
-
-    let counts_after: Vec<i64> = ["notes", "links"]
-        .iter()
-        .map(|table| {
-            conn.query_row(&format!("SELECT count(*) FROM {table}"), [], |row| {
-                row.get(0)
-            })
-            .unwrap()
-        })
-        .collect();
-    assert_eq!(counts_after, counts_before);
+    let get_counts = |conn: &Connection| -> Vec<i64> {
+        ["notes", "links"]
+            .iter()
+            .map(|table| {
+                conn.query_row(&format!("SELECT count(*) FROM {table}"), [], |row| {
+                    row.get(0)
+                })
+                .unwrap()
+            })
+            .collect()
+    };
+
+    let counts_before = get_counts(&conn);
+    migrate(&mut conn).expect("migrate to v19");
+    assert_eq!(get_counts(&conn), counts_before);
🤖 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 `@apps/desktop/src-tauri/src/db/tests.rs` around lines 382 - 403, Extract the
duplicated table-count query from the test around migrate into a local helper
closure that accepts the database connection and returns counts for “notes” and
“links”. Use the closure for both counts_before and counts_after while
preserving the existing query and assertion behavior.
🤖 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 `@apps/desktop/src-tauri/src/db/tests.rs`:
- Around line 382-403: Extract the duplicated table-count query from the test
around migrate into a local helper closure that accepts the database connection
and returns counts for “notes” and “links”. Use the closure for both
counts_before and counts_after while preserving the existing query and assertion
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 713a3014-6b10-4df4-af5f-32042beb309b

📥 Commits

Reviewing files that changed from the base of the PR and between 6e18731 and 13a0d21.

📒 Files selected for processing (3)
  • apps/desktop/src-tauri/src/db/tests.rs
  • crates/index-schema/migrations/0019_lazy_daily_backlinks.sql
  • crates/index-schema/src/lib.rs

@maccman

maccman commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Can you help us understand a bit more on the context here? We should be auto-creating daily notes automatically when you type a date in or a relative time like "three days from now".

@jasonlong jasonlong changed the title fix: show backlinks for uncreated daily notes fix: create daily notes from date links Jul 21, 2026
@jasonlong

jasonlong commented Jul 21, 2026

Copy link
Copy Markdown
Author

Ugh, for some reason my LLM is commenting on my behalf here. In a nutshell, the original issue I was seeing was this:

  1. Start typing [[next Mon in today's daily note and select an autocomplete option
  2. ISO formatted link is properly inserted into note
  3. Click on link for next Monday and there's no backlink from today

Leaving LLM's comment below...


You’re right — I traced this back through the V1 backlink-menu contract. Selecting an ISO or generated relative-date suggestion is supposed to materialize the daily note immediately. The current V2 autocomplete inserted the normalized ISO target, but unlike the ordinary Create row, the pathless date suggestion had no onSelect creation callback.

I initially addressed the downstream backlink symptom in the schema, which was the wrong layer and would have made manually typed dangling date links look like backlinks to nonexistent notes. I’ve replaced that approach in dc5827d: selecting a new date suggestion now atomically creates the empty daily/YYYY-MM-DD.md file (without replacing an existing/concurrently-created daily), and both exact and relative date paths are covered by tests. Once indexed, the existing backlinks view works unchanged.

Copilot AI left a comment

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.

Pull request overview

This PR restores the V1-style side effect for date-based wiki-link autocomplete by materializing missing daily notes when the user selects an ISO or relative-date suggestion, using the atomic no-clobber creation command and surfacing failures to the user.

Changes:

  • Add materializeDailyNote(date, generation) in @reflect/core to atomically create an empty daily note at daily/YYYY-MM-DD.md.
  • Wire the editor autocomplete selection flow to materialize “pathless” date suggestions in the background and report failures via operations UI.
  • Add unit/browser tests covering exact dates, generated relative dates, existing dailies, invalid dates, and error surfacing.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/core/src/graph/create-note.ts Adds materializeDailyNote helper that creates an empty daily note via createNoteIfAbsent.
packages/core/src/graph/create-note.test.ts Adds tests for daily note materialization behavior (create, no-clobber, invalid dates).
packages/core/src/exports/platform.ts Exports materializeDailyNote for desktop consumption via @reflect/core.
apps/desktop/src/editor/use-editor-autocomplete.ts Triggers daily-note materialization on selecting a pathless date suggestion; surfaces failures.
apps/desktop/src/editor/use-editor-autocomplete.test.tsx Adds tests for the new autocomplete selection behavior (success, no-op for existing, error surfacing).
Comments suppressed due to low confidence (1)

apps/desktop/src/editor/use-editor-autocomplete.test.tsx:125

  • This block also calls act(...)/waitFor(...) without importing them or obtaining act from renderHook. Align with the existing pattern in this file by awaiting renderHook to access its act helper and using vi.waitFor for the async expectation.
    const { result } = renderHook(() => useEditorAutocomplete())
    const items = await result.current.onWikilinkSearch('2026-07-27')

    act(() => {
      items[0]!.onSelect?.()

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +70 to +79
const { result } = renderHook(() => useEditorAutocomplete())
const items = await result.current.onWikilinkSearch(query)

act(() => {
items[0]!.onSelect?.()
})

await waitFor(() =>
expect(materializeDailyNote).toHaveBeenCalledWith('2026-07-27', 7),
)
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.

3 participants