Summary
spacedock status --where does not validate that the queried field exists. An unknown or
misspelled field name is silently read as the empty string in applyFilters, so the clause matches
the wrong set with no error or warning — most dangerously, a != clause on an unknown field
matches every entity (silent match-all). A user mistake becomes a confidently-wrong result.
Repro (spacedock 0.19.0, contract 1)
# unknown field + "!=" → returns ALL entities, no error/warning
spacedock status --workflow-dir <wd> --where "nosuchfield!=x"
# the common way users hit it: TWO conditions in ONE --where string
# (the intuitive-but-wrong syntax) → silently returns ALL
spacedock status --workflow-dir <wd> --where "sprint=A sprint-readiness!=defer"
# unknown field + "=" → returns NONE, no error
spacedock status --workflow-dir <wd> --where "nosuchfield=x"
The correct form (separate flags) ANDs correctly and works:
spacedock status --workflow-dir <wd> --where "sprint=A" --where "sprint-readiness!=defer"
Root cause (internal/status/parse.go)
parseWhereFilters validates that an operator is present (whereSyntaxHelp) but never that the
field exists.
- For a compound single string it
Cuts on the first operator (strings.Cut(whereArg, "!="), ~L187),
so "sprint=A sprint-readiness!=defer" parses to field="sprint=A sprint-readiness", op="!=",
value="defer" — a garbage field name, no error.
applyFilters (~L215): fieldVal := e.fields[f.field] returns "" for an unknown field (map zero
value). For != with a non-nil value, fieldVal == *f.value is "" == "defer" → false → match
stays true → the clause is satisfied by every entity. (For =, "" != value → excludes
everyone.)
So an unknown field degrades to "absent", and "absent != X" is vacuously true for all → silent
match-all.
Impact
- Typos (
--where "spint=foo") silently return the wrong set with no signal.
- The intuitive compound-in-one-string syntax silently returns the unfiltered set — users
reasonably expect either AND-semantics or an error.
- Real downstream footgun: a two-condition "active-sprint" task-selection recipe in a sibling project
fell back to rg over the state dir precisely because a compound --where "didn't filter" — without
realizing the correct form is repeated --where flags. A loud error would have pointed straight at
the fix.
Expected
Validate f.field against the entity's known fields (frontmatter keys + computed/projectable columns)
at parse or apply time, and error with a clear message (à la whereSyntaxHelp) on an unknown field,
e.g.:
--where: unknown field "sprint=A sprint-readiness" (known: id, slug, status, sprint, sprint-readiness, pr, mod-block, ...)
Turning the silent wrong-result into a loud, fixable error is the fix; the silent match-all is the
dangerous part.
Not a bug (for contrast)
Multiple --where flags already AND correctly — parseWhereFilters returns a slice and applyFilters
is conjunctive. Verified: --where "sprint=repeatable-pairing" --where "sprint-readiness!=defer" → 0
results, while each clause alone returns its own set. So this report is about field validation, not
a missing AND operator.
Summary
spacedock status --wheredoes not validate that the queried field exists. An unknown ormisspelled field name is silently read as the empty string in
applyFilters, so the clause matchesthe wrong set with no error or warning — most dangerously, a
!=clause on an unknown fieldmatches every entity (silent match-all). A user mistake becomes a confidently-wrong result.
Repro (spacedock 0.19.0, contract 1)
The correct form (separate flags) ANDs correctly and works:
Root cause (
internal/status/parse.go)parseWhereFiltersvalidates that an operator is present (whereSyntaxHelp) but never that thefield exists.
Cuts on the first operator (strings.Cut(whereArg, "!="), ~L187),so
"sprint=A sprint-readiness!=defer"parses tofield="sprint=A sprint-readiness",op="!=",value="defer"— a garbage field name, no error.applyFilters(~L215):fieldVal := e.fields[f.field]returns""for an unknown field (map zerovalue). For
!=with a non-nil value,fieldVal == *f.valueis"" == "defer"→ false →matchstays
true→ the clause is satisfied by every entity. (For=,"" != value→ excludeseveryone.)
So an unknown field degrades to "absent", and "absent
!=X" is vacuously true for all → silentmatch-all.
Impact
--where "spint=foo") silently return the wrong set with no signal.reasonably expect either AND-semantics or an error.
fell back to
rgover the state dir precisely because a compound--where"didn't filter" — withoutrealizing the correct form is repeated
--whereflags. A loud error would have pointed straight atthe fix.
Expected
Validate
f.fieldagainst the entity's known fields (frontmatter keys + computed/projectable columns)at parse or apply time, and error with a clear message (à la
whereSyntaxHelp) on an unknown field,e.g.:
Turning the silent wrong-result into a loud, fixable error is the fix; the silent match-all is the
dangerous part.
Not a bug (for contrast)
Multiple
--whereflags already AND correctly —parseWhereFiltersreturns a slice andapplyFiltersis conjunctive. Verified:
--where "sprint=repeatable-pairing" --where "sprint-readiness!=defer"→ 0results, while each clause alone returns its own set. So this report is about field validation, not
a missing AND operator.