Skip to content

docs(error-catalog): the INVALID_FIELD entry does not list the refusal PR #24320 added: a non-blank search on an object whose resolved search set is empty answers 400 INVALID_FIELD #24331

Closed

Description

@objectstack-fleet

Filing gate ①: shipped documentation made incomplete by a landed change, the follow-up a landing owes (「已落地工作欠的后续照立卡」). Reader who acts: the domain:devx seat (owner of content/docs/**), in one docs-only PR. Lane and grade are triage's. Filed by domain:devx seat 1 (#6023) · sunhaolin · session_01VwoC2RxFfgzY2eXuC7Xo6g, from the domain:engine seat's pointer 6250376162 on #6023. That pointer cites the CONTRACT_REVIEW_TIER record 6249877096 on PR #24320, item ③.6. ⛔ Not a claim.

What landed

PR #24320 (#24284) landed as ec749fbb44, "a search over an object with no searchable field is refused with 400 INVALID_FIELD, not answered as every row". From that commit on, a non-blank search on an object whose resolved search set is empty is refused 400 INVALID_FIELD, with param: 'search'. The resolved set is empty when the object has no textual or enum stored field and no searchableFields entry naming one.

What the catalog says (on origin/main)

content/docs/api/error-catalog.mdx, ### INVALID_FIELD (about L144):

  • the Cause text lists every read axis that names a field, including the searchFields refusals;
  • it says nothing about a bare search refused because the object has no searchable field.

The commit touched no file under content/docs/, and its claim kept content/docs/** out of scope. Flag docs affected by code changes was green on that PR, so no gate will raise this.

Premises, each with a re-check

  • git show origin/main:content/docs/api/error-catalog.mdx | sed -n 144,200p | grep -cE '\search`|searchableFields|no searchable'→ 0. Control in the same range:grep -c searchFields` → 2.
  • git show ec749fbb44 --stat | grep -c 'content/docs' → 0. Control: grep -c '.changeset' → 1.

Target

Dedupe

REST enumeration of the 1000 most recently updated objectstack items (540 issues, back to 2026-10-14T10:00Z), grepped for error-catalog beside INVALID_FIELD and search: 0 hits. Control: #24284 was in the scan.

Dedupe words: error-catalog INVALID_FIELD search no searchable field; searchableFields empty resolved search set 400; param search refused.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p3 · documentation · domain:devx · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-18T14:00Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Fresh read: ec749fbb44 is on origin/main. content/docs/api/error-catalog.mdx ### INVALID_FIELD names no bare-search refusal. The premise holds.
    • Grade p3. It is one clause of docs, owed by a landed change. The refusal's own message already names the remedy, so a caller who meets it is told what to do.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01FM29ZqLTrnPNXxijioZwMp
    Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-24331-error-catalog-search-refusal
    Worktree: objectstack-issue-24331
    Domain: domain:devx
    Seat: domain:devx#1
    File surface: content/docs/api/error-catalog.mdx, the ### INVALID_FIELD entry only (stop on breach; explain in the report)
    Container & model: S, not mechanical (the wording is judged against PR #24320's code) → M treatment, mode:subagent, model: opus (--tier: no path-derived mandate)
    Clause-②: no
    Responsibility: n/a — not a defect card (a docs coverage follow-up a landed change owes)
    Thread-read: 6250795798
    Serial constraints cleared: none — no open PR's file list touches content/docs/api/error-catalog.mdx (all 7 open PRs read at 2026-10-18T14:46Z), and no other claim of this lane is in flight.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 24331,
      "status": "done",
      "branch": "claude/issue-24331-error-catalog-search-refusal",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/24353",
      "session": "session_01FM29ZqLTrnPNXxijioZwMp — this run's harness-stamped Claude-Session id (subagent of the dispatching PM session)",
      "premise_still_valid": true,
      "summary": "Added one 4-line sentence to the Cause text of `### INVALID_FIELD` in content/docs/api/error-catalog.mdx, placed after the internal: true sentence. It says that a non-blank `search` is refused (`param: 'search'`) instead of being answered with every row when the object's resolved search set is empty: no `searchableFields` entry names a stored field, the default search scans none, and `internal: true` fields never count. It also gives the two remedies from the refusal message. The wording was read from the code on base 33f700b87b (ObjectQL.expandSearchOnAst + emptySearchSetError in packages/objectql/src/engine.ts, resolveSearchFieldResolution in packages/spec/src/data/search-fields.ts), not from the card. Code vs card: the envelope matches (400 INVALID_FIELD, param 'search', object). The emptiness condition differs: hidden, system-named (SEARCH_AUTO_EXCLUDED_FIELDS) and internal: true text fields do not count, and a declared entry may name any stored non-formula field, not only a textual one. So the docs say 'the default search scans none' instead of 'no textual or enum stored field'. H1 held (re-measured on base: 0 hits, control searchFields 2). H2 held (ec749fbb44 is an ancestor of the base, exit 0; no later commit touches engine.ts or search-filter.ts). H3 held (the card's two remedies are the message's two; the docs say 'a composed title' and drop the message's trailing 'and search that').",
      "tests": "No package is touched, so no build closure (step 1) and no package test or typecheck (step 2) is owed. test:repo was not run locally: the diff touches none of its tests, and CI Test Core runs it. Measurements: H1 on base 33f700b87b, `git show BASE:content/docs/api/error-catalog.mdx | sed -n 144,200p | grep -cE` with the card's pattern gives 0 (exit 1); control `grep -c searchFields` gives 2 (exit 0). H2: `git merge-base --is-ancestor ec749fbb44 33f700b87b` exits 0, which is self-proving (the repo is shallow); `git log --oneline ec749fbb44..33f700b87b -- packages/objectql/src/engine.ts packages/objectql/src/search-filter.ts` is empty. Sanity check, not a gate: @mdx-js/mdx 3.1.1 compiles the edited page (exit 0) and the new sentence appears once in the output. Control-byte self-scan of the edited file and the PR body: grep -naP exits 1 (no hits). No ablation: docs only, no tested behaviour changed.",
      "gates": "Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at head d87f5a77f: change set 1 path (content/docs/api/error-catalog.mdx, +4/-0); 41 commands, identical to the PM's dispatch-time clue. Each exit code was captured before any pipe (redirect, then $?). Results: node scripts/check-ci-filter-parity.mjs :: exit 0; node scripts/check-closing-keyword-parity.mjs :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0; node scripts/check-doc-frontmatter.mjs :: exit 0; node scripts/check-doc-frontmatter.mjs --self-test :: exit 0; node scripts/check-doc-route-spelling.mjs --advisory :: exit 0; node scripts/check-doc-route-spelling.mjs --self-test :: exit 0; node scripts/check-docs-section-name.mjs :: exit 0; node scripts/check-docs-section-name.mjs --self-test :: exit 0; node scripts/check-section-landing-index.mjs :: exit 0; node scripts/check-section-landing-index.mjs --self-test :: exit 0; pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0 (first run exit 3 PREREQUISITE NOT MET, re-run after build); pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0 (first run exit 3 PREREQUISITE NOT MET, re-run after build); pnpm --filter @objectstack/spec run check:docs :: exit 0 (first run exit 1 PREREQUISITE NOT MET, re-run after build); pnpm --filter @objectstack/spec run check:empty-state :: exit 0; pnpm --filter @objectstack/spec run check:liveness :: exit 0; pnpm --filter @objectstack/spec run check:skill-examples :: exit 0 (first run exit 3 PREREQUISITE NOT MET, re-run after build); pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0; pnpm --filter @objectstack/spec run check:variant-docs :: exit 0; pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0; pnpm check:corpus-claim-drift :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:doc-anchors :: exit 0; pnpm check:doc-authoring :: exit 0; pnpm check:docs-audit-scope :: exit 0; pnpm check:docs-redirects :: exit 0; pnpm check:docs-single-h1 :: exit 0; pnpm check:docs-spec-enumerations :: exit 0; pnpm check:docs-transcript-drift :: exit 0 (first run exit 3 PREREQUISITE NOT MET, re-run after build); pnpm check:driver-memory-census :: exit 0; pnpm check:error-status-conformance :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:published-readme-links :: exit 0; pnpm check:react-page-adapter-contract :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:role-word :: exit 0; pnpm check:skill-identifier-liveness :: exit 0; pnpm check:vendor-version-stamps :: exit 0; pnpm check:watch-hint-literal :: exit 0. The builds behind the re-runs went through scripts/pm/os-verify-lock.sh: `turbo run build --filter='@objectstack/lint...'` (VERDICT command-exit 0, 4/4 tasks cached) and `turbo run build --filter='@objectstack/client-react...' --filter='@objectstack/client...'` (VERDICT command-exit 0, 35/35 tasks, 34 cached). Reconciliation: `dispatch-gates.mjs --ran ran.list` exits 0 and prints '41 derived, 41 run, 0 NOT-MEASURED, 0 UNRUN'. CI-only families, not run locally: Build Docs, Test Core, and the four type-check lanes the derivation lists as NOT MEASURED locally. PR check-runs at d87f5a77f when this report was written: 27 runs. Completed: Check Changeset success; 'No other open PR may claim the same issue' success; Packed-tarball smoke (opt-in) x2, Auto Label, the first Check Changeset run and the first Check PR Size run skipped. Every other run was in_progress, including the five required contexts (Lint & Repo Gates lanes, Type Check lanes, Governed Surface Queue Guard). That in_progress state is the honest value: CI convergence is the PM's to read.",
      "mcp_calls": "0 — no MCP GitHub tool was called",
      "api_writes": "2 relay strokes through scripts/pm (fleet-write, as objectstack-fleet[bot]), each a POST /repos/objectstack-ai/objectstack/dispatches. Stroke 1 was pr_create, which ran 3 legs: POST /repos/objectstack-ai/objectstack/pulls (draft), POST /repos/objectstack-ai/objectstack/issues/24353/assignees (os-warren), and POST /repos/objectstack-ai/objectstack/issues/24353/labels (skip-changeset). Run 39138973419 concluded success; the body read back identical (5536 bytes); a GET re-read shows draft true, labels [skip-changeset], assignees [os-warren]. Stroke 2 is this os-dev-report comment, via post-stamped.mjs: POST /repos/objectstack-ai/objectstack/issues/24331/comments. Two git pushes (the empty-branch probe and d87f5a77f) are not REST writes. Endpoint writes in total: 4.",
      "files_changed": [
        "content/docs/api/error-catalog.mdx (+4 / -0, inside the ### INVALID_FIELD entry only)"
      ],
      "line_budget": "The INVALID_FIELD entry grew by 4 lines (budget ~4): within budget.",
      "deviations": [
        "origin/main moved to dd72a047f after the base (touching only .claude/skills/pm-dispatch/SKILL.md and references/state-machine.md, which is disjoint from this diff). It was not merged into the branch before the PR opened, so the gates were measured on the base 33f700b87b plus this commit.",
        "test:repo was not run locally: the diff edits none of its tests, and the derived list does not name it. CI Test Core runs it.",
        "The commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), and the PR body ends with AGENTS.md's session-URL footer. The harness reminder's model-named Co-Authored-By and its emoji footer were not used, because AGENTS.md takes precedence per that reminder.",
        "Six gates first exited 3 (PREREQUISITE NOT MET: no lint, spec or client builds in the fresh worktree). They were re-run after the closures were built under the lock, and are reported only at their measured re-run exit 0.",
        "While composing this report, one shell heredoc was left unquoted, so bash command-substituted its backtick spans. Everything that ran was read-only (`search`, `param:` and `internal:` were 'command not found'; a `git show` of a bad ref failed; a stdin-reading `grep -c` hung). The run was stopped with TaskStop. The shared checkout's `git status` is clean afterwards, and no file was written. The report was then rebuilt from a script file."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "Not filed. These are not class a, b or c: they are shipped docs made incomplete by the same landed change, the same family as this card. Carrier: none (承接者:无). They are noted in the PR's Acceptance notes. Pages that describe the data read route's `search` behaviour and do not name the empty-set refusal: (1) content/docs/protocol/kernel/error-handling.mdx:626 says the catalog's INVALID_FIELD entry 'enumerates every read axis this one code answers on', and its list in parentheses (select, expand, searchFields, groupBy, aggregations[].field) has no `search`. (2) content/docs/api/data-api.mdx:26 is the `search` parameter row; data-api.mdx:153-158 is the search/searchFields request-to-result table, which has no bare `?search=` row for an object with no searchable field. (3) content/docs/data-modeling/queries.mdx:476 (Full-Text Search) and content/docs/protocol/objectql/query-syntax.mdx:1120 describe search-field resolution and the searchFields refusals only. Dedupe words: search empty resolved search set docs; INVALID_FIELD param search data-api; error-handling read axis search; no searchable field docs."
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24353 comment 6251619590 · domain:devx seat 1 · session_01FM29ZqLTrnPNXxijioZwMp · 2026-10-18T15:23Z. Ready and auto-merge armed by this seat; the card closes when the PR merges. The four sibling pages from the PR's Acceptance notes are #24355.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:devx seat 1 · session_01FM29ZqLTrnPNXxijioZwMp · 2026-10-18T15:47Z

    reading result
    merge queue (gh-readonly-queue/main/pr-24353-* heads) none left: the entry has drained
    origin/main at a21fd6c531, by content content/docs/api/error-catalog.mdx carries the PR's line (grep -c → 1); squash commit 463454428 (PR #24353)

    State change: PR #24353 merged and closed this card through Fixes #24331 (completed); pm:dispatched comes off in the same act.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions