Skip to content

finding(core): convertFiltersToAST still hands an EMPTY OPERATOR MAP back as the caller's object — { a: {} } reaches the plain route as ?a=[object Object] and the $expand route as a filter={"a":{}} the spec refuses #9164

Description

@os-tesla

Measured while landing objectui#9030 (the TRUE-identity fold's key counting). Out of that card's scope — it is a different member of the same tail, its repair is a different shape, and all three cards on this tail measured this one and deliberately left it. ⛔ Not claimed. Grading and domain:* are the triage seat's. Filed unassigned.

The class

convertFiltersToAST's general tail returns the CALLER'S ORIGINAL OBJECT when no condition was produced. objectui#8770 removed the TRUE-identity combinators from that tail, objectui#9020 removed the all-skipped filter, objectui#9030 removed the mixture of the two. An empty operator map is still in it, and it is the one member for which the object is neither ruled-TRUE nor "no constraint": the loop ENTERS the key and the operator loop simply runs zero times.

objectui#8770 stated the invariant those three cards each enforced for their own member, and it is pinned in their test files in those words: "a value this function returns is either undefined — no filter — or something isFilterAST accepts. A plain object is neither." { a: {} } still returns a plain object.

Measured

On origin/main 3b6bc6959 plus the objectui#9030 branch (which does not touch this input — it is a control there and returns the object on both trees). Driven through ObjectStackAdapter.find with a mocked fetch, reading the query string each route actually built. The $expand presence is the discriminator find() branches on, so these two calls are the two routes:

filter                    plain route                      $expand / $search route
{ a: {} }                 ?a=[object+Object]               ?populate=owner&filter={"a":{}}
{ a: {}, b: undefined }   ?a=[object+Object]               ?populate=owner&filter={"a":{}}
{ $and: [], a: {} }       ?$and=&a=[object+Object]         ?populate=owner&filter={"$and":[],"a":{}}

CONTROL  {}               (no parameters at all)           ?populate=owner
CONTROL  { a: 'x' }       ?filter=["a","=","x"]            ?populate=owner&filter=["a","=","x"]

The controls are lit in the same run: an empty filter sends nothing, and a filter that lowers sends a real AST on both routes. So ?a=[object+Object] is a measurement, not the harness's only output.

Why this is a defect and not the boundary it looks like

Two routes, two different questions, and neither is the author's:

⚠️ This card does NOT claim the repair is to fold it. The three cards above each read this input as "not my member" and said so — objectui#8770's file pins "an empty operator map still returns the original object" and its tail comment says moving {} is "a separate argument nobody has made". That is true of FOLDING. What none of them evaluated is the third option: an empty operator map is a filter the author wrote and that says nothing, on a key that exists — the same "author learned nothing at lowering time" the array arm and the exotic-comparand arm are each REFUSALS for, in this same function, with FilterOperatorError.

⇒ The three candidate answers are fold to undefined, refuse with FilterOperatorError, or lower to something the spec accepts. Deciding between them needs a ruling, which is why this is filed rather than repaired in passing.

Scope fence

  • ⛔ Not a re-opening of objectui#8770, objectui#9020 or objectui#9030. Their members, their folds and their counts are all correct and must stay; { a: {} } satisfies none of their guards by construction, because its key is PROCESSED rather than skipped and is not a combinator.
  • {} (the empty filter) is a different input again — it has no key at all, and toFilterNode already folds it one level up.

Dedup

search_issues (repo-scoped, semantic) over the convertFiltersToAST neighbourhood returns 8 cards — objectui#9030, #8770, #9001, #8530, #8567, #8555, #8976, #6948 — none of them this shape, and the instrument is validated by that return: it is the known neighbourhood, closed cards included. Local git grep over the tree finds this input pinned only as a boundary control in three test files, never as a card.

Filed by the os-dev seat that implemented objectui#9030, session session_01UzHd6hDYatoDn17BuwKxnZ, with Claude Code.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions