Skip to content

🗄️ feat: Record When a Conversation Was Archived - #14863

Open
berry-13 wants to merge 3 commits into
perf/set-convo-pinnedfrom
feat/conversation-archived-at
Open

🗄️ feat: Record When a Conversation Was Archived#14863
berry-13 wants to merge 3 commits into
perf/set-convo-pinnedfrom
feat/conversation-archived-at

Conversation

@berry-13

Copy link
Copy Markdown
Collaborator

Summary

The archived chats dialog has a "Date Archived" column that was bound to createdAt, so it showed when the chat was created rather than when it was filed away. Nothing recorded the latter.

Conversations now carry archivedAt, set on archive and cleared on unarchive, and the column reads it. Clearing matters: a stale stamp would resurface the chat in archive ordering the next time it was filed away. The archive view sorts on the new field.

Chats archived before the field existed have no stamp and fall back to createdAt, which is exactly what that column already showed for them, so no existing row changes appearance.

Stacked on #14862.

The cursor

archivedAt is absent on every previously archived chat, so in the pagination cursor the missing-value group is the common case here rather than an edge case. Two things had to be right:

The cursor already had null-aware paging clauses written for title. BSON orders a missing field before every string and every date identically, so that logic generalises; the two sortBy === 'title' checks became a named sortFieldIsNullable covering both rather than a second special case.

The encode side did new Date(primaryValue ?? 0).toISOString(), which would turn an absent stamp into 1970 and page from the epoch, replaying the whole archive. A null primary now survives as null, which is the signal the decode side uses to know it is inside the missing-value group.

Deployment note

This adds { user, isArchived, archivedAt, _id } to the conversation schema's indexes, which builds on startup.

I deliberately did not backfill archivedAt for existing archived chats. There is no record of when those were archived, so a backfill would not recover the data, it would manufacture it, and nothing would then distinguish a real stamp from a fabricated one. The fallback is honest about not knowing, and the legacy set only shrinks: every archive from now on writes a real stamp.

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Testing

Four cursor tests cover the paging risk: descending and ascending across a mixed set of stamped and unstamped rows, asserting every chat appears exactly once (the set of ids seen equals the expected set and the count matches, so a repeat fails), plus null ordering and the rejected-sort-field guard.

Verified against a real database: archived a chat with updatedAt 2026-03-05, it got archivedAt = today while updatedAt was unchanged, and the dialog showed today's date for it while the two pre-existing archived chats still showed their unchanged fallback dates. Toggling the column header re-sorted ascending through the real backend. Unarchiving cleared the stamp and removed it from the archive view.

Test Configuration:

Local dev server, MongoDB, Chromium.

cd packages/data-schemas && npx jest src/            # 2026 passed, 59 suites
cd api && npx jest server/routes/__tests__/convos.spec.js   # 44 passed
cd client && npx jest src/components/Nav/SettingsTabs       # 105 passed
cd client && npx tsc --noEmit

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

@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: 14d373a341

ℹ️ 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 thread packages/data-schemas/src/schema/convo.ts
Comment thread packages/data-schemas/src/schema/convo.ts Outdated
Copilot AI lite review requested due to automatic review settings August 15, 2026 05:30
@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch from 14d373a to da1cebf Compare August 15, 2026 05:30
@berry-13

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: da1cebf5c0

ℹ️ 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".

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

Adds first-class support for tracking when a conversation was archived (archivedAt) across the data schema, API, cursor pagination, and the Archived Chats UI, so “Date Archived” reflects archive time (with a safe fallback for legacy archived chats).

Changes:

  • Introduces archivedAt on conversations; stamps it on archive and clears it on unarchive.
  • Updates archived-conversation cursor sorting/pagination to support sorting by archivedAt (with null/missing-aware paging) and adds targeted tests.
  • Switches the Archived Chats table default sort and displayed date column to use archivedAt ?? createdAt.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/data-schemas/src/types/convo.ts Adds archivedAt to the conversation document type.
packages/data-schemas/src/schema/convo.ts Persists archivedAt and adds an archive-list index aligned to the new sort.
packages/data-schemas/src/methods/conversation.ts Adds archivedAt as a valid sort field; updates cursor paging and projection to include it.
packages/data-schemas/src/methods/conversation.spec.ts Adds tests covering archivedAt cursor paging across stamped/unstamped rows.
packages/data-provider/src/types/queries.ts Extends list sort options and minimal conversation shape to include archivedAt.
packages/data-provider/src/schemas.ts Extends Zod schema so API payloads can include nullable/optional archivedAt.
packages/data-provider/src/config.ts Excludes archivedAt from persisted conversation data (consistent with other metadata fields).
client/src/components/Nav/SettingsTabs/General/ArchivedChatsTable.tsx Defaults sorting to archivedAt and renders archivedAt ?? createdAt in the “Date Archived” column.
api/server/routes/convos.js Stamps archivedAt on archive and clears it on unarchive while preserving updatedAt.
api/server/routes/tests/convos.spec.js Updates archive route expectations and adds tests for stamping/clearing archivedAt.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/data-schemas/src/methods/conversation.ts
Comment thread packages/data-schemas/src/methods/conversation.ts
Comment thread packages/data-schemas/src/methods/conversation.ts
@berry-13

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: 72d5ccb0c3

ℹ️ 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".

@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch from 72d5ccb to ba3c93e Compare August 15, 2026 05:56
@berry-13

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: ba3c93eb13

ℹ️ 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".

@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch from ba3c93e to 67313df Compare August 15, 2026 06:10
@berry-13

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: 67313df446

ℹ️ 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".

@berry-13

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 67313df446

ℹ️ 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".

@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch from 67313df to 780ee4f Compare August 15, 2026 14:24
@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch 2 times, most recently from d449471 to d428faf Compare August 15, 2026 19:45
@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch from d428faf to 92e45a7 Compare August 15, 2026 19:59

@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: 92e45a76f3

ℹ️ 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 thread packages/data-schemas/src/methods/conversation.ts
Comment thread api/server/routes/convos.js Outdated
@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch from 92e45a7 to 821ca9c Compare August 15, 2026 21:25

@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: 821ca9c4c3

ℹ️ 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 thread api/server/routes/convos.js Outdated

@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: 458c0cc814

ℹ️ 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 thread packages/data-schemas/src/methods/conversation.ts
@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch from 458c0cc to d627c86 Compare August 15, 2026 21:41
The archived chats dialog has a "Date Archived" column that was bound to
createdAt, so it showed when the chat was created rather than when it was
filed away. Nothing recorded the latter.

Conversations now carry archivedAt, set on archive and cleared on
unarchive, and the column reads it. Chats archived before the field
existed have no stamp and fall back to createdAt, which is exactly what
that column already showed for them.

The archive view sorts on the new field. archivedAt is absent on every
previously archived chat, so the missing-value group is the common case
here rather than an edge case: the cursor's null handling, written for
titles, now covers both, and an absent stamp survives the cursor as null
instead of collapsing to the epoch and replaying the whole archive.
- Protect `archivedAt` from saveMessageToDatabase's unset sweep. Any
  persisted field missing from endpointOptions is unset, so sending a
  message in an archived chat cleared the stamp while leaving isArchived
  true, silently dropping it into the legacy fallback group.
- Order the legacy group by the createdAt the dialog displays rather than
  by last activity. The cursor's secondary key is now chosen per sort
  field, so the fallback the cell renders and the order the server
  returns cannot disagree.
- Put that secondary key in the archive index too, so paging the legacy
  group does not fall back to a blocking sort.
Opening an archived chat and hitting the archive shortcut, or retrying
the POST, sent isArchived: true again and replaced Date Archived with
now. saveConvo now stamps only on the unarchived-to-archived transition
and still clears the field on unarchive.
@berry-13
berry-13 force-pushed the feat/conversation-archived-at branch from d627c86 to eed576f Compare August 15, 2026 23:25
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