LearnNewsExamplesServices
Frontmatter
id19016
titleThe Filter operator doc comment lists fifteen operators and the array ships sixteen
stateClosed
labels
bugdocumentationgood first issuecore
assignees[]
createdAtSep 20, 2026, 2:03 AM
updatedAtSep 20, 2026, 2:20 AM
githubUrlhttps://github.com/neomjs/neo/issues/19016
authorsloemo01
commentsCount2
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 20, 2026, 2:20 AM

The Filter operator doc comment lists fifteen operators and the array ships sixteen

Closed v13.2.0/archive-v13-2-0-chunk-22 bugdocumentationgood first issuecore
sloemo01
sloemo01 commented on Sep 20, 2026, 2:03 AM

Context

src/collection/Filter.mjs documents its own operator vocabulary in a doc comment, and that comment is the first thing a reader sees when they open the file:

/**
 * Valid values for the operator config:<br>
 * ['==','===','!=','!==','<','<=','>','>=','endsWith','excluded','included','isDefined','isUndefined','like','startsWith']
 * @member {String[]} operators
 * @protected
 * @static
 */
static operators = [
    '==', '===', '!=', '!==', '<', '<=', '>', '>=', 'doesNotStartWith', 'endsWith', 'excluded',
    'included', 'isDefined', 'isUndefined', 'like', 'startsWith'
]

Measured 2026-09-19 at dev@626051de: the comment lists fifteen operators and the array ships sixteen. The only difference is doesNotStartWith, absent from the prose and present in both the array and its implementation at :247.

The Problem

The array is the enforced vocabulary, not the comment. beforeSetOperator (:146) validates against static operators through beforeSetEnumValue, so doesNotStartWith is accepted, works, and is covered by the unit spec filed alongside this one. Nothing rejects it.

The defect is therefore documentation only, and that is exactly why it is worth its own ticket rather than a line in someone else's PR: a reader who trusts the comment concludes the operator does not exist, and a reader who checks the array finds it undocumented. doesNotStartWith has no @summary, no doc comment of its own, and no entry in the list that claims to be the valid values.

The generalisable question this raises: the comment and the array are two hand-maintained copies of one fact, and they have already drifted. Whatever the fix is, it is worth deciding whether they should stay two.

Expected behavior

The comment and the array describe the same set. Two honest routes:

  1. Add the missing operator to the prose, giving doesNotStartWith the same one-line treatment the other fifteen get, and leaving the duplication as it is.
  2. Stop duplicating, so the comment says the array is the list rather than restating it, and the two cannot disagree again.

Either is defensible; the second is the one that removes the failure mode. Whichever is chosen, the ordering inside the array currently puts doesNotStartWith between >= and endsWith, which is not alphabetical and not obviously intentional. Worth a look while the file is open.

Notes for whoever takes this

  • This is a documentation change. It does not alter an operator, the array, or any validation. src/collection/Filter.mjs is the only file that should move.
  • The existing unit spec should not need to change. FilterOperators.spec.mjs (PR #19015) iterates static operators and does not assert against the doc comment, so it holds either way. If your change makes it red, something is wrong and the spec is the thing to read first.
  • Check whether Neo.collection.Sorter carries the same duplication. It has the same shape and a coverage ticket of its own (#19007); if it repeats the pattern, say so here rather than fixing both in one PR.

Additional context

Found while pinning the operator matrix in #19003, where it was deliberately left out of scope so the doc fix could carry its own reasoning. Reported there rather than fixed, per that ticket's Out of Scope. Confirmed independently against the source before filing this.

sloemo01 cross-referenced by PR #19015 on Sep 20, 2026, 2:03 AM
sloemo01 cross-referenced by #19003 on Sep 20, 2026, 2:03 AM
sloemo01
sloemo01 Sep 20, 2026, 2:05 AM

Taking this one too, since I filed it and the fix is small.

One thing the source settled before I write anything: the house convention for this pattern puts the values inside the @member tag, not on a line above it. Siblings read:

* Valid values for labelPosition
* @member {String[]} labelPositions=['bottom','inline','left','right','top']

Filter.mjs is the odd one out: it restates its list on its own line above the tag, so the tag only says @member {String[]} operators and the list floats free of the declaration it describes. That is precisely what let it drift, and it means the fix is not only to add the missing operator but to move the list into the tag so a reader sees the values as part of the member.

Plan:

  • Move the sixteen into the @member tag in the sibling form, which removes the free-floating copy rather than adding a word to it.
  • Leave static operators itself untouched. It is the enforced vocabulary and nothing about it is wrong.
  • No operator behaviour changes, and FilterOperators.spec.mjs asserts against the array rather than the comment, so it should stay green either way. If it goes red, the spec is the thing to read first.
  • I will check whether Neo.collection.Sorter repeats the free-floating pattern and report that here rather than fixing both in one PR.

@neo-opus-grace - 2026-09-20T00:06:28Z

Triaged — bug · documentation · core · good first issue, and the premise verified independently

@sloemo01 — labels applied by a maintainer because you could not apply them yourself, not because anything was missing from the ticket.

Premise confirmed at source before labelling, rather than taken from the body:

doc lists 15 · array ships 16 · missing from doc: ['doesNotStartWith']

src/collection/Filter.mjs — the comment at :17-18 and the array at :20-23. Your reading of the mechanism holds too: beforeSetOperator validates through beforeSetEnumValue against static operators, so doesNotStartWith is accepted and nothing rejects it. Documentation-only is the correct scoping.

On the routes

You named both and identified the second as the one that removes the failure mode. That is the right call and it is the one this repo would take — two hand-maintained copies of one fact have already drifted once, and a fix that leaves them as two is a fix with a scheduled recurrence. Whoever takes it should make the comment point at the array rather than restate it.

The ordering observation is worth acting on in the same PR: doesNotStartWith sits between >= and endsWith, which is neither alphabetical nor grouped-by-kind. If the comment stops restating the list, the array becomes the only place a reader looks, and its order starts carrying meaning it does not currently have.

Three things I want to name, because they are the difference between a report and a usable ticket

  • "The existing unit spec should not need to change… if your change makes it red, something is wrong and the spec is the thing to read first." That sentence tells the next person how to interpret a failure, not just what to do. It is the part a ticket usually lacks.
  • You reported it rather than fixing it inline, and said why — out of scope in #19003, so the doc fix carries its own reasoning. That is exactly the boundary we ask of each other.
  • You pointed at Neo.collection.Sorter as a possible sibling and explicitly said not to fix both in one PR. Correct on both counts. #19007 covers Sorter's coverage; if the duplication repeats there it wants its own ticket, not a widened diff here.

Disposition

Left unassigned and yours to claim if you want it — you found it, you have the file open, and it is a clean first commit into src/. good first issue is on it for that reason. If you would rather stay on test coverage, say so and it goes into the general queue; nobody will read that as dropping it.

No ai label: that one marks agent-authored or agent-queued work, and this is neither unless an agent picks it up.

🖖 Grace

sloemo01 cross-referenced by PR #19017 on Sep 20, 2026, 2:06 AM