Uh oh!
There was an error while loading. Please reload this page.
fix(example-todo): remove the inert is_completed/is_overdue flags and repair every filter that read them - #8295
Merged
Conversation
… repair every filter that read them
… repair every filter that read them Both were readonly booleans defaulting to false that nothing ever wrote, while twelve view/dashboard/report/flow filters read them as if maintained. Every is_completed:true surface and the whole Overdue Tasks view were permanently empty; the eight is_completed:false filters matched completed tasks too. Removed rather than derived as formulas: a formula field is virtual, so a filter naming one matches nothing -- measured at 0 rows with no error, where the stored boolean returned every row. Deriving would have silently emptied the Due Today view, the reminder flow and both open-task reports. Every consumer now asks status / due_date directly. The hook's unreachable overdue branch is removed rather than re-armed: becoming overdue is the passage of time, not a record write, and the overdue_escalation scheduled flow already covers it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARidKDYSCD56LaygrvDPnk
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
This was referenced Aug 13, 2026
os-zhuang
marked this pull request as ready for review
August 13, 2026 04:29
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#7226
The card's premise held, and understated the cost
is_completed/is_overduewerereadonly: truebooleans defaulting tofalsethat nothing in the app ever wrote — verified onorigin/main: no hook leg, no flow node, no action handler, and the seed data set neither.The card says "no user-facing surface currently branches on either flag — no view filter, dashboard, report or dataset in the app reads them". That is no longer accurate, and it is the one part of the body I could not confirm. Twelve live references read them:
mainoverduelist viewis_overdue == true,is_completed == falseis_completed: true+completed_dateis_overdue: true, is_completed: falseis_completed: true+completed_dateis_completed: truedue_todayview, 3 distribution charts, 2 open-task reports, reminder flowis_completed: falsecreate_recordis_completed: falseSo this was a live defect, not observation-class. Six user-visible surfaces rendered a permanent zero while looking like they worked.
Why REMOVE and not derive — the measurement that decided it
The dispatch ruled
is_completedto derive-as-formula outright, andis_overdueto derive if a formula field may use the temporal functions. I verified the temporal half and it passes — but the route still fails, for a different reason that the ruling could not have anticipated.Temporal formula fields are fully supported.
packages/objectql/src/engine-write-formula-hydration.test.tspinsnow()-valued formula fields as a platform surface with a per-call snapshot determinism guarantee. Measured directly:date(record.due_date) < today()in aField.formulaevaluates correctly on all four states (past-due open, future, no due date, completed).But a formula field cannot be filtered. It is virtual — no driver materialises a column — so a
wherenaming one matches nothing, silently. Measured on this app's own sqlite-wasm driver, same engine, same rows:The middle line is decisive: eight of the twelve filters use exactly that predicate. Deriving would have taken the "Due Today" view, the daily reminder flow and both open-task reports from working to silently empty — trading a wrong answer for an invisible one, in a reference app whose whole purpose is to be copied.
This is corroborated by the platform's own vocabulary:
formulais refused on the ORDER BY axis (#7095, #6994) and the search axis (#6674) for precisely this storage fact. The filter axis has no such door —assertFilterFieldsExistjudges only unknown, not unmaterializable — which is why this fails silently rather than loudly. (Filed as a separate finding; see below.)Since derive is infeasible for both flags for one shared reason, and removal is not contested — the issue body itself names
status/due_dateas already carrying the information, and both are declared dimensions on thetask_metricsdataset — this takes the remove route the dispatch authorises as the fallback.What changed
is_completed == truestatus equals 'completed'is_completed == falsestatus not_equals 'completed'is_overdue == truedue_date less_than '{today}'ANDstatus not_equals 'completed'Across
task.object.ts,task.hook.ts,task.view.ts,task.dashboard.ts,task.report.ts,task.flow.ts, the three translation bundles and the README. Canonical operator spellings (not_equals,less_than), not the historical camelCase aliases.The hook's
afterUpdateoverdue branch is removed, not re-armed. Becoming overdue is the passage of time, not a record write — a task nobody touches crosses its due date with no update to observe — so a record hook is structurally the wrong instrument and any version of that branch would fire late or never. The clock-driven sweep already exists in the right place: theoverdue_escalationscheduled flow, which selects ondue_datedirectly.Verification
examples/app-todo/test/derived-flag-removal.test.ts(new):defineStackover keys and values, so both{ is_completed: false }(key) and{ field: 'is_completed' }(value) forms are caught, across objects, views, dashboards, reports, datasets, flows, translations and seed data in one pass.completedthrough the real hook and back out; the open/done sets must swap each way. Asserting only on a never-completed task would be green for exactly the reason the old flag was green.Reverse verification of the pins themselves, direction predicted before running: restoring
origin/main's app source turns the 3 removal pins RED and leaves the 4 engine-level tests GREEN (they exercise the engine, not the app's declarations). Observed exactly that — 3 failed, 4 passed.The last two are convention-scoped gates my new test file triggers; they were not in the dispatch's named set and were surfaced by re-deriving
scripts/pm/dispatch-gates.mjsagainst the actual diff. The path derivation confirmed the PM's reading — no path-scoped family matchesexamples/app-todo.Out of scope, filed separately
The filter axis has no unmaterializable verdict, so filtering a virtual
formulafield returns 0 rows silently on both backends while the sort and search axes refuse the same field with a 400 and a remedy. That asymmetry is what made this card's failure invisible, and it is a platform gap inpackages/metadata-protocol— a report, not an edit here, per the dispatch's scope fence.Generated by Claude Code