Repository navigation
fix: say when a date filter or task date names a day the calendar lacks - #668
Conversation
|
Validate modifiedOnDate's date before converting it
Pre-existing: modifiedOnDate hands its caller-supplied date straight to dayToEpochMsRange, so a date the calendar lacks is answered with the converter's own outcome (its internal failure, or bounds that match nothing) instead of the calendar-date message this PR now raises for every other date input. The guard the PR added to the sibling modified filter is the fix template. Failure scenario: A caller passes a date the calendar lacks to modifiedOnDate (e.g. { date: "2026-02-30" } via the daily-review prompt's date argument): dayToEpochMsRange runs on an impossible day with no calendar check, so the caller gets the converter's internal error or an empty day listing — a model asking about that day is never told the date does not exist. Suggested fixReject params.date with classifyIsoDate before dayToEpochMsRange — or route it through assertFilterDate with a label of its own — so a malformed or impossible date fails the same two ways the filter bounds now do.umm-actually · deepseek/deepseek-v4.1-flash |
|
Validate modifiedOnDate's date before converting it
modifiedOnDate feeds params.date straight into dayToEpochMsRange, while the modified filter this PR hardens asserts the bound first precisely so the converter never sees a bad date (the new comment states that ordering). A calendar-invalid or malformed date reaching the daily-review prompt's activity lookup therefore fails at the converter instead of returning the shared 'not a calendar date' remediation. Failure scenario: daily-review invoked with date '2026-02-30' (or 'yesterday') → modifiedOnDate passes it to dayToEpochMsRange unvalidated → the converter's luxon parse fails (or NaN epoch bounds reach the SQL bind) and the prompt degrades with a generic fallback, with no 'is not a calendar date' guidance for the caller. Suggested fixCall `assertFilterDate(params.date, "modified")` before `dayToEpochMsRange(params.date)` in modifiedOnDate, so the shared two-tier remediation covers that call site too.umm-actually · z-ai/glm-5.3-flash |
|
umm-actually re-reviewed at 1 new finding(s) posted (4 tracked finding(s) across all runs). Context notes
umm-actually · z-ai/glm-5.3-flash |
|
Replying to the two umm-actually findings "Validate modifiedOnDate's date before converting it" (comments 6093266719 and 6093266800): this is intentional, because neither failure scenario can occur.
The prompt's own wording for a missing day ("Could not compute the next day…") only names the format. That is the same gap this PR fixes for the filters, but it sits in the daily-review prompt, which another open change rewrites to say the date is not a calendar date. 🔍 ship-check · pr-monitor · claude-opus-5-5 |
A date in YYYY-MM-DD form that names a missing day, such as 2026-02-30, was answered with "Use YYYY-MM-DD", the form the caller had already used. The vault_search created/modified filters, the vault_list_tasks date filters, and the vault_create_task / vault_update_task date params now say the date is not a calendar date; text not in that form keeps the format message. classifyIsoDate in src/utils/ makes the split for all of them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rtTaskDate, share vault_search's Filters and Errors text - classifyIsoDate's doc uses the verb it does, names both Luxon reasons, and says a month or day can be out of range - assertFilterDate and assertTaskDate return early on a real day, and their docs say which tool descriptions quote their messages - assertFilterDate gets its own section banner, since full-text search and task listing both call it - comments say why a modified bound never reaches dayToEpochMsRange's check, what a task date filter's column name is used for, and what null means for an update's date params - both vault_search description variants interpolate one Filters and one Errors section; the served text is unchanged Ship-Check: code-quality · claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… exactly - createTask and updateTask: an impossible scheduled or start date is rejected with a message that names the field. No test covered these checks before, so dropping one let the date reach the note. - listTasks: the malformed date filter and missing .md extension tests compare the whole error message instead of a substring. Ship-Check: test-audit · claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every other created and modified bound already had a rejection test; a created.after bound naming a day the calendar lacks now does too. Ship-Check: test-audit · claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
28 assertions passed a string to toThrow, which matches any message that contains it. They now pass an Error, which vitest compares whole. Six of them named only part of the message and now name all of it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0dfbd88 to
fd3c110
Compare
Summary
A date in YYYY-MM-DD form that names a day the calendar lacks, such as
2026-02-30, was answered with "Use YYYY-MM-DD", the form the caller had already used. A model told only the format sends the same date again. These inputs now say the date is not a calendar date, and text that is not in YYYY-MM-DD form keeps the format message:vault_searchcreated/modifiedboundsinvalid created.on date: "March 10". Use YYYY-MM-DD (e.g. 2026-07-03).created.on date "2026-02-30" is not a calendar date. Pass a real date in YYYY-MM-DD format.vault_list_tasksdate filters (all six)invalid due.before date: "July 3rd". Use YYYY-MM-DD (e.g. 2026-07-03).done.after date "2026-04-31" is not a calendar date. Pass a real date in YYYY-MM-DD format.vault_create_task/vault_update_taskdue,scheduled,start,createdinvalid date: due "2026-2-3" (use YYYY-MM-DD)invalid date: due "2026-02-30" is not a calendar date. Pass a real date in YYYY-MM-DD format.The task-date messages keep their
invalid dateprefix, so the two task tools' Errors entry ("a date param fails calendar validation; pass a real YYYY-MM-DD date") still describes both cases and their text is unchanged. Covering the task dates as well as the filters makes every date input that had this message give the same answer.Changes
src/utils/classify-iso-date.ts(new):classifyIsoDatesorts text into a real YYYY-MM-DD day, text not in that form, or a month or day that doesn't exist. Luxon checks the form first (unparsable) and then the calendar (unit out of range), which is the split.search-queries.ts:assertFilterDateuses it for the note and task date filters, under its own section banner, with a note thatvault_searchandvault_list_tasksquote both messages.task-mutations.ts:validateDateis renamedassertTaskDate(matchingassertFilterDate) and uses it for task create and update.vault_search(both descriptions) andvault_list_taskssplits into one bullet per remedy.vault_search's Filters and Errors sections, which were word-for-word copies in its two descriptions, are now one shared string each; the text clients receive is byte-identical to the split above (snapshots unchanged by that commit).Tests
classify-iso-date.test.ts: real days, missing days (February 30, February 29 outside a leap year, month 13, month 00, day 00), and malformed text (single-digit parts, a timestamp, a five-digit year, slashes, a month name, whitespace, empty).created.after), the task filters, and task create and update for every date field, each asserting the full message.server-error-contracts.test.ts: both tiers forvault_searchandvault_list_tasksover HTTP; the two task-date contracts now assert the full result.toThrowassertions intask-mutations.test.tsandhybrid-search.test.tsexact: they passed a string, which matches any message containing it, and now pass anError, which vitest compares whole. Six of them had named only part of the message.Review
vault_searchsections above; the test audit added the coverage listed above.main's tool list against this branch's, default and embedding-off): onlyvault_searchandvault_list_taskschanged, every fact of the old bullet survives, both new failures are listed, and the unchanged task-tool bullet is still accurate. It also listed older gaps in parts of these two tools this PR does not touch:vault_search's opening omits file content,filters.typeis case-sensitive but unsaid,filters.related's value format, two repeated sentences, Returns'type/tagsempty values, andvault_list_tasks' opening repeating its Returns fields. The code-quality pass's two wording proposals (aninvalid <bound> dateplaceholder, and splitting the task tools' date bullet) went to the same round.Live Test Results
Head: 0dfbd88
Image:
ghcr.io/aliasunder/vault-cortex:test, built from this head by Test Deploy run 38020919921 (succeeded 03:37 UTC) and serving the instance. The "before" column was taken over the same connector just before the deploy; every "after" message is new code, which also confirms the container was re-created from the test build.vault_searchfilters.modified.on: "2026-02-30"invalid modified.on date: "2026-02-30". Use YYYY-MM-DD (e.g. 2026-07-03).modified.on date "2026-02-30" is not a calendar date. Pass a real date in YYYY-MM-DD format.vault_searchfilters.created.before: "March 10"invalid created.before date: "March 10". Use YYYY-MM-DD (e.g. 2026-07-03).(unchanged form message)vault_list_tasksdue.on: "2026-02-30"invalid due.on date: "2026-02-30". Use YYYY-MM-DD (e.g. 2026-07-03).due.on date "2026-02-30" is not a calendar date. Pass a real date in YYYY-MM-DD format.vault_list_tasksdone.after: "2026-7-3"invalid done.after date: "2026-7-3". Use YYYY-MM-DD (e.g. 2026-07-03).(a single-digit month and day is a form error)vault_create_taskdue: "2026-02-30"invalid date: due "2026-02-30" (use YYYY-MM-DD)invalid date: due "2026-02-30" is not a calendar date. Pass a real date in YYYY-MM-DD format.vault_update_taskscheduled: "2026-13-01"invalid date: scheduled "2026-13-01" is not a calendar date. Pass a real date in YYYY-MM-DD format.vault_update_taskstart: "tomorrow"invalid date: start "tomorrow" (use YYYY-MM-DD)(unchanged form message)vault_searchfilters.created.on: "2026-10-09", folder of session logsvault_list_tasksdone.on: "2026-10-09"on this repo's boardThe task probes named a note path that does not exist; the date check runs first, so nothing was written (the folder lists empty afterwards).
Rebased onto main at
8a512669asfd3c11004f1fde4db9095413bce095af7a75a196with no conflicts. The diff outside test files is unchanged (git patch-id --stableover it iscae8ea9fbefore and after), so the live test above still covers this head. The full suite passes on the rebased head: 117 files, 5,346 tests.🤖 Generated with Claude Code