Skip to content

feat: daily narrative memory tables + wagl day CLI (#120)#128

Merged
GoZumie merged 4 commits intodevfrom
feat/daily-entries-table
Mar 24, 2026
Merged

feat: daily narrative memory tables + wagl day CLI (#120)#128
GoZumie merged 4 commits intodevfrom
feat/daily-entries-table

Conversation

@GoZumie
Copy link
Member

@GoZumie GoZumie commented Mar 22, 2026

What

Append-only daily narrative layer: daily_entries, daily_memories (junction), daily (materialized summary).

CLI: wagl day

  • wagl day — show today's narrative
  • wagl day --date 2026-03-21 — specific date
  • wagl day --list — list all dates with entries
  • wagl day --update — add an entry with context
  • wagl day --invalidate <id> --reason '...' — soft-delete with audit trail
  • wagl day --include-invalidated — show everything including soft-deleted

Schema

Why

Multiple sessions (Becoming, Building, work) write memories throughout the day. The daily table provides a temporal narrative view without mutating individual items.

Closes #120

PR Review by Greptile

Greptile Summary

This PR introduces an append-only daily narrative layer (daily_entries, daily_memories, daily) as part of the v1→v2 schema migration, and exposes it via the new wagl day CLI subcommand with read, append, soft-invalidate, and list operations. It also threads two new provenance fields (environment, origin_domain) through MemoryItem, all existing CLI write paths, the MCP handler, and the HTTP server — a clean, backward-compatible addition thanks to #[serde(default)] and Option typing.

  • Schema migration is properly wrapped in a transaction, version-gated, and covered by a new test in migrate.rs.
  • memory_item_from_row helper eliminates ~120 lines of repeated row-deserialization across five query sites — a meaningful DRY improvement.
  • daily_entries.date has no index in either the init schema (lib.rs:489) or the migration (migrate.rs:220); queries filtering by date (get_daily_entries, invalidate_daily_entry's pre-lookup) will full-scan as the table grows over years of use.
  • --date combined with --invalidate is not caught by validate_day_args, so the date value is silently discarded rather than returning a clear error.
  • link_daily_memory / daily_memories is scaffolded but never called from the Day command, leaving the described "links entries to memory_items" feature incomplete in this PR.
  • Two temporal-recall queries (query_recent_high_valence, query_open_todos_with_filter) were correctly updated to include the new columns but bypass the MEMORY_ITEM_SELECT constant, creating a future divergence risk.

Confidence Score: 4/5

  • Safe to merge after adding the missing daily_entries.date index and the --date/--invalidate guard; all other findings are non-blocking cleanups.
  • The core feature (append-only daily entries, soft-invalidation, materialized summary, v1→v2 migration) is well-implemented, transactionally safe, and test-covered. The memory_item_from_row refactor is a clear improvement. The missing index is a performance concern rather than a correctness bug, the silent --date discard is a UX rough edge, and the daily_memories gap is incomplete scaffolding — none of these break the primary user path. One targeted fix (the index) would make this a clean merge.
  • crates/db/src/lib.rs and crates/db/src/migrate.rs for the missing daily_entries.date index; crates/cli/src/main.rs for the --date/--invalidate validation gap.

Important Files Changed

Filename Overview
crates/db/src/lib.rs Core DB layer: adds environment/origin_domain to MemoryItem, introduces memory_item_from_row helper to eliminate duplicated row-mapping, and implements all five daily narrative methods (insert_daily_entry, get_daily_entries, get_daily_summary, list_daily_dates, invalidate_daily_entry, link_daily_memory, refresh_daily_summary). Missing index on daily_entries.date; two temporal-recall queries bypass the new MEMORY_ITEM_SELECT constant; link_daily_memory is never called.
crates/db/src/migrate.rs Bumps schema version 1→2 and adds migrate_v1_to_v2_inner which creates the three daily tables inside a transactional wrapper. Migration tests are updated and a new migration_v1_to_v2_adds_daily_tables test is added. Missing index on daily_entries.date in the migration DDL (matches init schema gap).
crates/cli/src/main.rs Adds Cmd::Day with full argument parsing, validate_day_args, validate_day_date, today_local_date_string, and default_origin_domain. Threads environment/origin_domain through all existing Put, Canon, and ingest call sites. --date is not validated as incompatible with --invalidate, causing silent discard.
crates/core/src/types.rs Adds environment and origin_domain optional fields (with #[serde(default)]) to MemoryItem, and introduces DailyEntry and DailySummary structs. Clean, backward-compatible change.
crates/cli/src/ingest_cmd.rs Fills in the new environment/origin_domain fields when constructing MemoryItem inside run_ingest_transcripts. Minimal, correct change.
crates/cli/tests/temporal_recall_smoke.rs Adds environment: None, origin_domain: None to three test fixtures to satisfy the updated MemoryItem struct. No logic changes.
crates/mcp/src/handler.rs Sets environment: None, origin_domain: None in the MCP handler's MemoryItem construction. Minimal, correct change.
crates/server/src/lib.rs Exposes environment and origin_domain in PutItemRequest and passes them through to MemoryItem. Backward-compatible (both fields are Option).

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as wagl CLI (main.rs)
    participant DB as MemoryDb (db/lib.rs)
    participant SQLite

    Note over CLI,SQLite: wagl day --update "Finished auth refactor"
    User->>CLI: wagl day --update <content> [--context <label>]
    CLI->>CLI: validate_day_args()
    CLI->>CLI: today_local_date_string()
    CLI->>DB: insert_daily_entry(date, context, content)
    DB->>SQLite: INSERT INTO daily_entries
    DB->>DB: refresh_daily_summary(date)
    DB->>SQLite: SELECT valid entries WHERE date=?
    DB->>SQLite: INSERT OR REPLACE INTO daily (preserves summary)
    DB-->>CLI: entry id
    CLI->>DB: get_daily_entries(date, false)
    CLI->>DB: get_daily_summary(date)
    CLI-->>User: JSON {action, id, date, entries, daily}

    Note over CLI,SQLite: wagl day --invalidate <id> --reason "..."
    User->>CLI: wagl day --invalidate <id> [--reason <text>]
    CLI->>CLI: validate_day_args()
    CLI->>DB: invalidate_daily_entry(id, reason)
    DB->>SQLite: SELECT date FROM daily_entries WHERE id=?
    DB->>SQLite: UPDATE daily_entries SET invalidated=1
    DB->>DB: refresh_daily_summary(date)
    DB->>SQLite: INSERT OR REPLACE INTO daily
    DB-->>CLI: ok
    CLI-->>User: JSON {action, id, reason}

    Note over CLI,SQLite: wagl day [--date YYYY-MM-DD]
    User->>CLI: wagl day [--date <date>]
    CLI->>CLI: validate_day_date() if date provided
    CLI->>DB: get_daily_entries(date, include_invalidated)
    CLI->>DB: get_daily_summary(date)
    CLI-->>User: JSON {date, count, entries, daily}
Loading

Comments Outside Diff (1)

  1. crates/db/src/lib.rs, line 978-997 (link)

    P2 Inline queries not using MEMORY_ITEM_SELECT

    Two queries — query_recent_high_valence (line 982) and query_open_todos_with_filter (line 1025) — still hardcode the full column list instead of using the new MEMORY_ITEM_SELECT constant. Both were manually updated to include environment, origin_domain, which is correct for now, but they will silently diverge if MEMORY_ITEM_SELECT is changed in the future. The same applies to the analogous query at line 1025.

    Consider replacing both inline projections with MEMORY_ITEM_SELECT:

    &format!(
        "SELECT {} FROM memory_items \
         WHERE created_at >= ?1 \
           AND d_score IS NOT NULL \
           ...",
        MEMORY_ITEM_SELECT, actionable_filter
    ),

Last reviewed commit: "feat: add environmen..."

Greptile also left 3 inline comments on this PR.

@GoZumie GoZumie requested a review from ChrisCompton as a code owner March 22, 2026 01:28
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

wagl/crates/db/src/lib.rs

Lines 815 to 819 in 13b3dc5

id: existing.id,
created_at: existing.created_at,
tags,
files,
..item.clone()

P2 Badge Preserve provenance fields during dedupe-key upserts

This merge keeps id, created_at, tags, and files from the existing row, but it takes environment and origin_domain only from the incoming item. Because the new provenance fields are optional on the HTTP API (PutItemRequest) and other callers can omit them, any idempotent write with upsert=true will clear previously captured provenance for that dedupe key. That turns routine updates into silent metadata loss.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@GoZumie
Copy link
Member Author

GoZumie commented Mar 22, 2026

Self-review notes:

wagl day subcommand with --update, --date, --list, --invalidate, --include-invalidated.
✅ Append-only daily_entries table with soft invalidation (invalidated_at + reason).
✅ daily_memories junction table for linking entries to memory items.
✅ daily table for materialized summaries.
✅ Migration test for v1→v2 schema.

⚠️ Merge order: This branch shares the combined commit with PR #127. Merge #127 first, then rebase this to show only the daily-table delta. Or merge both together since they are the same changeset implementing #119 + #120.

@GoZumie GoZumie force-pushed the feat/daily-entries-table branch from 13b3dc5 to 9ab3418 Compare March 23, 2026 10:34
…ECT, upsert provenance)

- Add CREATE INDEX on daily_entries.date in init schema and v1→v2 migration
  (prevents full-table scans as daily entries accumulate over time)
- Add --date + --invalidate validation: return clear error instead of silently
  discarding --date (invalidation looks up by ID only)
- Refactor query_recent_high_valence and query_open_todos to use MEMORY_ITEM_SELECT
  constant instead of hardcoded column lists (prevents future divergence)
- Fix upsert provenance: preserve environment/origin_domain from existing row
  when incoming item does not supply them (prevents silent metadata loss on
  idempotent writes via MCP/server that omit optional provenance fields)
- Add TODO comment for link_daily_memory in Day --update handler (scaffolded
  but not yet called; needs content-similarity lookup to be built first)

Closes remaining review items from Greptile (3/5→4/5) and Codex P2 flag.
@GoZumie
Copy link
Member Author

GoZumie commented Mar 23, 2026

Addressed all review feedback in commit c3b141a:

Fixed:

  • Missing index on daily_entries.date — added CREATE INDEX in both init schema and v1→v2 migration
  • --date + --invalidate validation gap — now returns a clear error instead of silently discarding --date
  • Temporal queries bypass MEMORY_ITEM_SELECTquery_recent_high_valence and query_open_todos_with_filter now use the constant (no more future-divergence risk)
  • Codex P2: upsert provenance lossenvironment and origin_domain are now preserved from the existing row when the incoming item omits them (same merge pattern as id, created_at, tags, files)
  • link_daily_memory scaffolding — added a TODO comment in the Day --update handler explaining what it needs (content-similarity lookup) before it can be wired up

Not fixed (intentional):

  • link_daily_memory itself — incomplete scaffolding, documented via TODO. Implementing the lookup is a separate task.

CI should be green. Ready for merge when you are.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

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: c3b141a5bb

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@GoClio
Copy link
Member

GoClio commented Mar 24, 2026

🔍 Review Status (2026-03-24)

CI is all green ✅ and the branch is mergeable, but holding on the following before proceeding:

🔴 P1 — Bundle data-loss regression
Automated review flagged that bundle_cmd.rs (export + import) does not serialize/deserialize the new daily_entries or daily_memories tables. A user can write narrative entries via wagl day --update, export a bundle, and silently lose all of it on import. Since bundles are the primary backup/share path, this is a blocking regression.

🟡 P2 — Missing index on daily_entries.date
Queries on WHERE date = ?1 without an index will do full table scans as the table grows.

🟡 P2 — --date silently ignored with --invalidate
validate_day_args guards --date + --list and --date + --update, but not --date + --invalidate. The date is silently discarded.

🟡 P2 — daily_memories table never populated from CLI
link_daily_memory exists and the table is created, but nothing calls it. If this is deferred scaffolding, a comment noting the intended call site would help.

Will hold merge until at minimum the P1 bundle issue is resolved. Happy to delegate the fix to CCA.

…128 P1)

Closes the data-loss regression identified in PR #128 review:
- Add DailyEntry + DailySummary variants to BundleRecord (wagl.bundle.daily_entry / wagl.bundle.daily_summary)
- Add MemoryDb::all_daily_entries() and all_daily_summaries() for bulk export
- Add MemoryDb::upsert_daily_entry() and upsert_daily_summary() for idempotent import (INSERT OR IGNORE by id / date)
- Update export_bundle() to write all daily entries (including invalidated) and summaries
- Update import_bundle() to restore daily entries and summaries; entries drive summary content via refresh_daily_summary, summary import restores the hand-authored summary field
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

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: ac863a8b4b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@GoClio
Copy link
Member

GoClio commented Mar 24, 2026

🔍 Review Update (2026-03-24 14:35 CST)

P1 bundle data-loss regression → ✅ RESOLVED in ac863a8b

The latest commit adds DailyEntry/DailySummary variants to BundleRecord, plus export/import support for both tables. The primary blocking issue is closed.

CI: All checks green ✅ (CodeQL, fmt + test, CI pipeline)

Remaining P2 items (non-blocking):

  • 🟡 Missing index on daily_entries.date — full table scan on date filter as data grows
  • 🟡 --date + --invalidate not validated — date is silently discarded
  • 🟡 daily_memories table scaffolded but link_daily_memory never called from CLI

These are cleanup items, not correctness issues. Can be followed up in a separate PR.

@Zumie-BI — CI is green, P1 resolved. Ready for your approval if the feature looks good. 🚀

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@GoClio
Copy link
Member

GoClio commented Mar 24, 2026

✅ CI All Green — Ready to Merge

All checks passed on commit ac863a8b:

Check Status
fmt + test ✅ pass
Analyze (actions) ✅ pass
Analyze (rust) / CodeQL ✅ pass

P1 bundle data-loss regression resolved ✅
All P2 review threads resolved (non-blocking, tracked for follow-up PR)

@Zumie-BI — PR is clean and ready. Approve when you're good. 🚀

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

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: 0ec67ed879

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

let invalidated_i: i64 = if entry.invalidated { 1 } else { 0 };
self.conn
.execute(
"INSERT OR IGNORE INTO daily_entries (id, date, context, content, invalidated, invalidate_reason, created_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",

Choose a reason for hiding this comment

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

P1 Badge Upsert existing daily entries during bundle import

upsert_daily_entry uses INSERT OR IGNORE, so importing a newer bundle snapshot does not apply later changes to an existing entry (notably invalidated/invalidate_reason). This breaks incremental restore/sync workflows: an entry invalidated in the source DB remains active in the target DB after re-import, and refresh_daily_summary then rebuilds daily.content from that stale active row.

Useful? React with 👍 / 👎.

@GoZumie GoZumie merged commit 54bef13 into dev Mar 24, 2026
4 checks passed
@GoZumie GoZumie deleted the feat/daily-entries-table branch March 24, 2026 21:23
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.

2 participants