Repository navigation
Spell QueryFilter and SortConfig keys snake_case in storage and on the wire (closes #3483) - #3485
Conversation
Pragmatic Code Review — PR #3485Review Type: Initial review (no prior reviews or comments on the PR). Reviewed commit Recommendation: APPROVE. No blocking findings. One non-blocking test gap is worth closing in this PR (finding 1). SummaryThe change removes Requirements Check (issue #3483)
What I verified, and howRan:
Read:
Inferred, not run: that the three new Design calls
Findings1. 🟡 Important (non-blocking): nothing asserts that
|
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review: APPROVE (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Review addressed (commit
|
Pragmatic Code Review — PR #3485Review Type: Re-Review. Reviewed commit Recommendation: APPROVE. No blocking findings. The commit does what the "Review addressed" comment says. The live-append gate now agrees with the backend on case; three narrow cases remain where it still accepts a node the backend excludes (finding 1), all older than this PR. Previous Review Summary
Status of the previous findings
What I verified, and howRan:
Read:
Inferred, not run:
Does the gate now agree with the backend?Checked operator by operator. "Declines" means the gate says no where the backend says yes; that is the safe direction. "Over-accepts" is the unsafe one.
Callers and tests that relied on the old behaviour: none in production. Is declining the safe direction? Yes. A declined node is missing until the next query load, which runs the real SQL. An over-accepted node sits in a result the query excludes, and nothing removes it until a reload. Every change in this commit moves toward declining: Code Review Findings1. 🟡 Important (non-blocking):
|
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review (re-review): APPROVE (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Re-review addressed
Addressed
SkippedNothing from this round. Previous finding 2 (write-time rejection of an undeclared sort field or filter property) stays out of this PR, as the re-review agreed. Re-Review DecisionDecision: NO RE-REVIEW NEEDED Rationale: the one logic change is the reviewer's own recommendation, applied as written to a pure predicate. It can only make the gate decline more, which is its safe direction, and each new branch has a test. The rest is a test fixture and a comment. |
…e wire (closes #3483) ADR-086 §9: a nested stored value has one spelling, snake_case, with no rename_all, and rejects unknown keys. - QueryFilter: drop rename_all = "camelCase". Its keys are case_sensitive and node_id in a saved query, a Play's selector, the generated TypeScript and the execute input alike. - SortConfig: drop rename_all and add deny_unknown_fields. - Frontend: send a definition's filters and sorting as written. The filter-key converter and the sort-field translation (modifiedAt -> modified_at) are gone; a sort names its field by the stored name. - Remove the unused DEFAULT_QUERY and QUERY_TEMPLATE_EXAMPLES, one of which sorted by dueDate, a name the backend never matched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tch the backend's case rules in the live-append gate - the_execute_input_accepts_what_the_stored_types_serialize: a stored QueryFilter and SortConfig round-trip through the execute input. - A Play selector's filter decodes case_sensitive. - matchesFilter: equals and in compare exactly and contains is case-sensitive by default, as the backend's SQL does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d gate; name every field in the agreement test - equals: an unset subject equals nothing, a property filter compares by strict equality, and a node column compares as text. - the_execute_input_accepts_what_the_stored_types_serialize: full struct literals, so a new QueryFilter field must be set there. - Record the Unicode vs ASCII case fold difference on contains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9e7bcbd to
077e9ea
Compare
Closes #3483.
What changed
ADR-086 §9 says a nested stored value has one spelling, snake_case, in storage and on the wire.
QueryFilterandSortConfigwere the two nested types stored in thequerybucket (and in a Play's selector) that did not follow it.Kind and category: no type, field, relationship or rule is added.
queryis a structured core type; this changes the keys of two nested wire types it stores.QueryFilter:rename_all = "camelCase"is gone. The keys that change arecaseSensitive→case_sensitiveandnodeId→node_id, in a saved query, a Play'sselect.filters, and the generated TypeScript. The CLI's and the agent's filter input already used these spellings.SortConfig:rename_allis gone (its keys are single words, so no key changes) and it is nowdeny_unknown_fields.buildExecuteQueryWiresends a definition's filters and sorting as written. The filter-key converter andencodeSortField(which turnedmodifiedAtintomodified_atfor five metadata columns) are deleted. A sort names its field by the stored name.DEFAULT_QUERYandQUERY_TEMPLATE_EXAMPLEShad no consumer. One template sorted bydueDate, a name the backend never matched.caseSensitiveornodeIdneeds a reset: on read that query is served with the schema defaults (all types, no filters) and the decode error is logged, and a Play selector that executes it errors.matchesFilterfollows the backend's SQL.equalsandincompare exactly, andcontainsis case-sensitive unlesscase_sensitiveisfalse.Not changed
AgentFilterItem(the execute input) stays a separate type. It is not the same shape asQueryFilter: itstypeis optional and inferred, and its operator is parsed with model-facing errors. Its keys already matched.AiChatMessageand the records nested in it) are also camelCase; Store AI chat messages as ai-chat-message child nodes with real edges #3448 replaces them with message nodes.Tests
filter_keys_are_snake_case_stored_and_on_the_wire,a_filter_with_an_unknown_key_is_rejected(now coverscaseSensitiveandnodeId) anda_sort_item_with_an_unknown_key_is_rejected. All three fail with therename_allrestored and thedeny_unknown_fieldsremoved.the_execute_input_accepts_what_the_stored_types_serializeround-trips a stored filter and sort item through the execute input;agent_filter_item_reads_an_explicit_null_as_absentcovers explicit nulls. Together they pin what lets the frontend send a definition unmodified.bun run test:changedpasses: frontend, scripts, browser, generated-types drift, Rust workspace.Docs
nodespace-docs
a5848bf:naming-conventions.mdgains the nested-stored-value rule and the one-spelling section;query-node.mdno longer says filter keys are camelCase on the wire.🤖 Generated with Claude Code