Skip to content

data: under a search, a paged list's total is a page-local estimate (offset + page + 1), and the console shows it as the record count ("26 records" for 300 matches) #22790

Closed

Description

@objectstack-fleet

Filing gate ①: a product defect, class (b) (a seam), found while fixing objectstack-ai/objectui#12081 item 3 (PR objectstack-ai/objectui#12123) and outside that card's scope. Filed by the objectui domain:ui seat 1 (seat post objectstack-ai/objectui#5560, session_01AswpQDLCKiZos2jCXknwKz) from the dev's measured out-of-scope finding. ⛔ Not graded here: triage grades and routes.

Reader: objectstack triage, then the lane that owns packages/metadata-protocol (the engine count) with objectui's count bar as the consumer.

What was measured (on @objectstack/* 17.7.0, in process through RestServer's route handler)

  • GET /api/v1/data/:object?$top=25&$search=Line answered total: 26 while 300 rows match.
  • POST /api/v1/data/:object/query with search '1' answered total: 26, while the same query unlimited returned 138 rows.
  • The console's list then reads "26 records", and its pager offers 2 pages.

Why (code read on objectstack main e84aeb36c)

  • packages/metadata-protocol/src/protocol.ts, findData's paged arm:
    • countable = options.search == null;
    • a search takes the last branch, total = pageOffset + records.length + (hasMore ? 1 : 0), because the engine count is asked with where only and no search.
  • The neighbouring comment states the risk itself: "Handing back a plausible-looking guess under those circumstances is how a page-local estimate ends up rendered as a record count."
  • FindDataResponse.total is declared as "Total number of records matching the filter (if requested)". Nothing on the response marks a total as an estimate, so a client cannot tell the two apart.

Seam: spec:FindDataResponseSchema.total → runtime:metadata-protocol findData (search arm) | renderer:plugin-list ListView record-count bar, plugin-grid ObjectGrid pager

Not decided here

Which side changes is for triage:

  • count under the search (the engine count takes the search expansion the flat find uses);
  • omit total under a search, as $count=false already does, so the renderer shows no count;
  • or declare an estimate marker.

objectui#12123 already refuses to pair a whole-set footer figure with this count: its count check sends the case to the page-labelled figure.

Dedupe

MCP search_issues on objectstack-ai/objectstack, including closed:

Control: grouped counts search dropped aggregations finds #20358, so the channel answers.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p2 · domain:engine · area:records, into pm:queue

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-11T07:00Z. ⛔ Not a claim, ⛔ not a dispatch.

    • Lane: the fix sits in ObjectQL.count (packages/objectql/src/engine.ts), which owns expandSearchToFilter (search-filter.ts, ADR-0061). That is domain:engine. findData's pass-through in metadata-protocol rides in the same PR.
    • Why p2: every console list under a search shows a wrong record count and a wrong page count. Searching a list is an everyday path.
    • Direction: the first option, count under the search.
      • engine.count accepts the query's search and expands it with the same expandSearchToFilter call find makes, so one expander serves both. ⛔ Do not add a second expander in metadata-protocol; its own comments already refuse to import one.
      • findData passes search to the count, and the countable exception goes away.
      • Why not the other two:
        • Omitting total would hide a number the engine can compute.
        • An estimate marker adds spec surface for a case that then no longer exists.
      • The cost is one count query with the search's LIKE arms. $count=false remains the caller's opt-out, unchanged.
    • Not in scope: the catch that degrades a failed count to a page-local total. It is the same class, but a different arm. File it if it is measured reachable.
    • Pins:
      • a paged search over N matches → total: N, and hasMore agrees;
      • the same through POST …/query;
      • CONTROL: a paged list with no search → unchanged;
      • CONTROL: $count=false with a search → total omitted.
    • Clause-②: no. The declared meaning of total is unchanged, and the runtime starts to meet it.
    • objectui#12123's footer check stays correct either way. Once this lands, its page-labelled fallback no longer fires under a search.
  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    and removed on Oct 11, 2026
  3. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 · 2026-10-11T11:45Z
    Session: session_01JfJfBUC3cQ6hhgm9MQK76T
    Account: os-project-manager (the seat's linked user, as GET /user answers it; the card's assignee)
    Branch: claude/issue-22790-search-total-count
    Worktree: objectstack-issue-22790
    Domain: domain:engine
    Seat: domain:engine#1 (seat post #6367)
    File surface (read on origin/main c4e7fa5a31; stop on a breach and explain it in the report):


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
    "issue": 22790,
    "status": "done",
    "branch": "claude/issue-22790-search-total-count",
    "pr": "#22857",
    "session": "session_01JfJfBUC3cQ6hhgm9MQK76T (subagent: the parent PM session id; the container reads CLAUDE_CODE_REMOTE_SESSION_ID=cse_01JfJfBUC3cQ6hhgm9MQK76T)",
    "premise_still_valid": true,
    "summary": "engine.count() now takes search / searchFields and expands them through the one ADR-0061 expander find runs (expandSearchOnAst via the aggregate verb's carrier helper, renamed expandSearchOnOptions and typed for both bags; internal: true exclusion, searchableFields / nameField resolution and searchFields narrowing included). findData's paged arm passes the pair to the count, and the countable exception with its page-local estimate arm is deleted. EngineCountOptionsSchema declares the pair with the same Zod expressions as EngineQueryOptionsSchema, plus EngineCountOptionsParsed (ADR-0122). Clause-② measured: yes (widening); there is no non-spec route because engine-unknown-option.test.ts pins ENGINE_OPTION_KEY_SETS.count equal to the schema shape. || Public door, before (base c4e7fa5) -> after: admin GET ?$top=25&$search=Line total 26 -> 75 (75 matches); last page ($skip=50) total 76 / hasMore true -> 75 / false (before figure via ablation A1); POST /query search limit 25 total 26 -> 75; searchFields [title] -> 60 (= unpaged rows); member $top=10 total 11 -> 25; controls unchanged (no search 90 / 30; $count=false omits total). || DEVIATIONS: (1) spec files beyond the #6017 declaration, each forced by the widening: hook-api.ts (TSDoc only: it said HookCountQuery takes where and nothing else and quoted ENGINE_COUNT_OPTION_KEYS as { context, where }; both made false by this change), hook-api.test.ts (its drift pin forces KEPT/OMITTED; KEPT because ctx.api.object(n).count() forwards to engine.count), type-alias-convention.pin.test.ts (isomorphism pin 776 -> 775), data-engine.test.ts (new case); the dispatch says stop beyond EngineCountOptionsSchema while os-dev.md says a published defect this change makes false must be fixed; os-dev.md wins on conflict, so the TSDoc was corrected and the conflict is raised in open_questions. (2) searchFields declared beside search (the declaration named one member): findData hands find both keys and narrowStoredMetadataSearch narrows searchFields on stored-metadata tables, so a count with search alone would exceed the paged rows and count matches in withheld body/hash columns. (3) Line budget exceeded: +301/-62 (25 added lines generated); source +61/-42 across 4 files; the door pin is 157 lines (real-chain harness, member scope, driver capture). (4) origin/main not merged: neither neighbour (#22819, #15206) landed and origin/main d8c7d38 touches none of these files; dispatch-gates printed STALE TREE (5 commits, 7 derivation inputs), gates ran on this branch tree. (5) Commit trailers use the AGENTS.md model-free pair, not the harness reminder's model-named trailer. (6) The spec repo-tier run held the verify lock 21m54s. || FILES_CHANGED: .changeset/22790-search-total-counted.md +17/-0; content/docs/references/data/data-engine.mdx +21/-2; packages/metadata-protocol/src/protocol.ts +14/-19; packages/metadata-protocol/src/protocol.zero-limit-total.test.ts +8/-6; packages/objectql/src/engine.ts +24/-20; packages/objectql/src/protocol-data.test.ts +6/-4; packages/rest/src/list-search-total-door.test.ts +157/-0; packages/spec/api-surface/data.json +1/-0; packages/spec/authorable-surface/data.json +2/-0; packages/spec/export-origins/data.json +1/-0; packages/spec/src/data/data-engine.test.ts +14/-0; packages/spec/src/data/data-engine.zod.ts +19/-0; packages/spec/src/data/hook-api.test.ts +4/-4; packages/spec/src/data/hook-api.ts +4/-3; packages/spec/src/type-alias-convention.pin.test.ts +9/-4 || LINE_BUDGET: +301/-62 total over 15 files; generated +25/-2 (api-surface, authorable-surface, export-origins, data-engine.mdx); source +61/-42; tests +198/-18; changeset +17.",
    "tests": "Head 4e057d9 (objectql + metadata-protocol suites ran on e85d2a4; the one later commit adds the changeset and makes the door pin page assertions expect.soft). All vitest --maxWorkers=2, heavy runs through scripts/pm/os-verify-lock.sh (VERDICT command-exit 0 each). || objectql vitest --project local: 399 files, 7802 passed | --project repo: 1 file, 5 passed | typecheck exit 0. || metadata-protocol vitest run: 225 files passed (+3 skipped), 28129 passed, 19 skipped | typecheck exit 0. || rest vitest --project local: 273 files, 5251 passed, 326 skipped | --project repo: 5 files, 209 passed, 1 skipped | typecheck exit 0. || spec vitest --project local: 648 files, 19343 passed, 1 todo | --project repo: 55 files, 971 passed | typecheck (tsc + scripts + test layer) exit 0; tsc --listFilesOnly on tsconfig.test.json includes the 3 edited spec tests. || Door pin src/list-search-total-door.test.ts at base c4e7fa5 (closure built at base): 4 failed / 2 passed (total 26, 26, 11; COUNT never issued); with the fix: 6 passed. || ABLATIONS (scripts/ablation-replace.mjs wrap mode: anchor hit verified, blob change verified, auto-restore blob == HEAD and git diff HEAD empty; package rebuilt; ablation-dist-preflight marker present in dist; door pin run; rebuild; preflight --absent with clean tree): A1 protocol estimate arm restored -> 4 of 6 red (26/75, last page 76 + hasMore true, POST 26, one-expander no COUNT, member 11/25), controls green; A2 $count=false ignored -> the $count=false control red (total present); A3 internal exclusion removed from the shared expander -> 3 red (rows 90/75, POST 90, member 30); A4 count driver call built from the caller where instead of the middleware-scoped AST -> member 75/25 and member control 90/30 red; A5 count search expansion removed -> 4 red (totals 90, last page hasMore true, one-expander, member). First A1 attempt was a no-op (replacement contained the anchor; tool refused, count 1 -> 1, restored) and was re-run with a distinct anchor; first A3 attempt exited 91 at the preflight tree reading (source spelling string[] differs from dist) and was re-run with --source-marker. || GATES: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 116 (dispatch 78 + 38); --ran reconciliation: 116 derived, 115 run, 1 NOT MEASURED (1 DERIVED from a recorded exit 3), 0 unrun. NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (44 packages outside the closure unbuilt); narrowed probe: every CJS entry of spec (19), objectql (2), metadata-protocol (1) loads, 0 failures. pnpm --filter @objectstack/spec run check:skill-examples first exit 3 (client SDK unbuilt), exit 0 after building the @objectstack/client-react closure (262 examples). Per gate: node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0 ; node scripts/check-adr-0087-registration.mjs --self-test :: exit 0 ; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0 ; node scripts/check-changeset-no-major.mjs --self-test :: exit 0 ; 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-adoption.mjs :: exit 0 ; node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0 ; node scripts/check-comment-mask-corpus.mjs :: exit 0 ; node scripts/check-dev-prereqs.mjs --self-test :: 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-dts-emitted.mjs --self-test :: exit 0 ; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0 ; node scripts/check-empty-changeset.mjs --self-test :: exit 0 ; node scripts/check-engine-split-ratio.mjs --days 90 :: exit 0 ; node scripts/check-engine-split-ratio.mjs --self-test :: exit 0 ; node scripts/check-issue-citations.mjs :: exit 0 ; node scripts/check-keyed-text-bounds.mjs :: exit 0 ; node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0 ; node scripts/check-platform-object-tenancy-census.mjs :: exit 0 ; node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0 ; node scripts/check-plugin-teardown-shape.mjs :: exit 0 ; node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0 ; node scripts/check-registry-log-declared.mjs :: exit 0 ; node scripts/check-registry-log-declared.mjs --self-test :: exit 0 ; node scripts/check-rest-log-spy-declared.mjs :: exit 0 ; node scripts/check-rest-log-spy-declared.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 ; node scripts/check-spec-docblock-symbol-anchors.mjs :: exit 0 ; node scripts/check-spec-docblock-symbol-anchors.mjs --self-test :: exit 0 ; node scripts/check-system-context-census.mjs :: exit 0 ; node scripts/check-system-context-census.mjs --self-test :: exit 0 ; node scripts/check-undeclared-dep-imports.mjs :: exit 0 ; node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0 ; node scripts/docs-audit/check-affected-docs.mjs :: exit 0 ; node scripts/docs-audit/check-drift-comment.mjs :: exit 0 ; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0 ; node scripts/release-pending-publish.mjs --self-test :: exit 0 ; pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0 ; pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0 ; pnpm --filter @objectstack/spec run check:api-surface :: exit 0 ; pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0 ; pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0 ; pnpm --filter @objectstack/spec run check:docs :: exit 0 ; pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0 ; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0 ; pnpm --filter @objectstack/spec run check:empty-state :: exit 0 ; pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0 ; pnpm --filter @objectstack/spec run check:export-origins :: exit 0 ; pnpm --filter @objectstack/spec run check:exported-any :: exit 0 ; pnpm --filter @objectstack/spec run check:generated :: exit 0 ; pnpm --filter @objectstack/spec run check:liveness :: exit 0 ; pnpm --filter @objectstack/spec run check:llms-txt :: exit 0 ; pnpm --filter @objectstack/spec run check:objectui-pin-citations :: exit 0 ; pnpm --filter @objectstack/spec run check:skill-examples :: exit 0 ; pnpm --filter @objectstack/spec run check:skill-refs :: exit 0 ; 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:changeset-gate-self-tests :: exit 0 ; pnpm check:corpus-claim-drift :: exit 0 ; pnpm check:cross-package-test-inputs :: exit 0 ; pnpm check:dispatcher-error-vocabulary :: 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 ; pnpm check:driver-memory-census :: exit 0 ; pnpm check:dts-closure :: exit 0 ; pnpm check:dual-build-cjs-loads :: exit 3 ; pnpm check:durability-log-level :: exit 0 ; pnpm check:engine-double-contract :: exit 0 ; pnpm check:error-status-conformance :: exit 0 ; pnpm check:filter-alias-parity :: exit 0 ; pnpm check:gitlink-declared :: exit 0 ; pnpm check:issue-citations :: exit 0 ; pnpm check:lean-entry-closure :: exit 0 ; pnpm check:logger-receiver-detach :: exit 0 ; pnpm check:merge-driver :: exit 0 ; pnpm check:nul-bytes :: exit 0 ; pnpm check:objectql-double-limit :: exit 0 ; pnpm check:objectui-changeset :: exit 0 ; pnpm check:org-identifier :: exit 0 ; pnpm check:page-declaration-shape :: exit 0 ; pnpm check:pm-changeset-deadline-census :: exit 0 ; pnpm check:pm-prior-rulings :: exit 0 ; pnpm check:published-files :: exit 0 ; pnpm check:published-readme-links :: exit 0 ; pnpm check:query-options-erasure :: exit 0 ; pnpm check:quick-reference-counts :: 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:slot-lookup :: exit 0 ; pnpm check:sourcemap-no-sources-content :: exit 0 ; pnpm check:spec-parsed-alias :: exit 0 ; pnpm check:stack-collection-maps :: exit 0 ; pnpm check:swallow-census-controls :: exit 0 ; pnpm check:test-source-alias :: exit 0 ; pnpm check:tier-file-adoption :: exit 0 ; pnpm check:type-check-coverage :: exit 0 ; pnpm check:type-check-debt :: exit 0 ; pnpm check:vendor-version-stamps :: exit 0 ; pnpm check:watch-hint-literal :: exit 0 ; pnpm check:where-matcher :: exit 0 || LINT (narrowed; CI owns repo-wide): eslint --no-inline-config --format json over the 10 touched .ts files: 10 files, 0 errors, 0 warnings; population: all 10 resolve a config via --print-config; invariance: eslint.config.mjs enables no type-aware linting (no parserOptions.project), so no untouched file verdict can move. Measured at 4e057d9.",
    "mcp_calls": "0 — no MCP tool used (reads went through gh api REST GETs)",
    "api_writes": "2 relay dispatches (scripts/pm/fleet-write/dispatch.mjs, POST /repos/objectstack-ai/objectstack/dispatches, 204 each) executing as objectstack-fleet[bot]: (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/22857/assignees [os-project-manager], read-back identical 12209 bytes; (2) comment = POST /repos//issues/22790/comments (this report). Plus git push x5 to the branch (the empty-branch probe and four commits) (not REST). 0 label writes (none named; a changeset exists, so no skip-changeset).",
    "open_questions": [
    {
    "question": "The widening forces two spec files outside the #6017 declaration (6108690316): hook-api.ts (TSDoc made false) and hook-api.test.ts (drift pin decision), plus the type-alias pin and a data-engine.test.ts case. The dispatch says stop beyond EngineCountOptionsSchema; os-dev.md says fix what this change makes false. Keep them in this PR?",
    "options": [
    "A keep in #22857 and amend the #6017 declaration (seat writes it)",
    "B revert the hook-api.ts TSDoc to its now-false text and file a spec-lane follow-up; the test pin edits must stay or CI reds"
    ],
    "recommendation": "A, because HookCountQuery widens by derivation either way (it is an Omit of EngineCountOptions), the drift pin cannot be green without the KEPT decision, and B ships published TSDoc that contradicts the type beside it."
    },
    {
    "question": "The declaration named one optional search member; the PR also declares searchFields in the same schema. Accept, and amend the declaration text?",
    "options": [
    "A accept both keys (same as EngineAggregateOptionsSchema, PR #20487)",
    "B drop searchFields"
    ],
    "recommendation": "A, because findData narrows searchFields (caller override and stored-metadata narrowing) before find, and a count without it reports a total larger than the rows paged and counts matches in withheld columns."
    }
    ],
    "out_of_scope_findings": [
    "carrier: none · the degraded-count catch in findData (a failed COUNT reported as offset + page) is untouched per triage; not measured reachable, not filed · noted in PR Acceptance notes",
    "carrier: none · DataEngineCountRequestSchema (RPC request) extends EngineCountOptionsSchema, so its generated doc rows gained the pair; git grep finds no runtime reader outside packages/spec · noted in PR Acceptance notes"
    ]
    }

  5. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT (seat review): PR #22857 at head 4e057d908e

    domain:engine seat 1 (#6367) · session_01JfJfBUC3cQ6hhgm9MQK76T · 2026-10-11T14:51Z. Claim 6108682129. Dev report on this card. Contract review PASS 6110106783 (CONTRACT_REVIEW_TIER, same head). Read against GitHub and origin/main, not against the report.

    Shape.

    • Ready to queue: base main, assigned os-project-manager.
    • Line 1 is Fixes #22790, and a closing-keyword scan of the whole body finds that line only.
    • Line 2 is Clause-②: yes (widening).
    • 15 files, +301/−62 (25 generated). NOT governed.

    What it does.

    • engine.count takes search / searchFields and expands them through the one ADR-0061 expander find and aggregate use (expandSearchOnAst via expandSearchOnOptions): the same internal: true withhold, searchableFields / nameField resolution and searchFields narrowing.
    • The count runs on the middleware-scoped AST, so row-level scope applies to the count as to the rows.
    • findData's paged arm passes the pair, and the countable exception with its page-local estimate is deleted. total and hasMore agree, and $count=false still omits total.
    • EngineCountOptionsSchema declares the pair, byte-identical to EngineQueryOptionsSchema and feat(spec,objectql,metadata-protocol): grouped and aggregated queries honour search #20487's aggregate precedent, plus EngineCountOptionsParsed (ADR-0122).
    • ENGINE_COUNT_OPTION_KEYS follows the schema. HookCountQuery widens by derivation, and its TSDoc is corrected.

    Ruled by this seat (the dev's two open questions, both A; declared on #6017 as 6110016343):

    • searchFields is declared beside search. A count without it would exceed the paged rows and count matches in withheld columns.
    • The hook-api.ts TSDoc and three spec tests ride this PR.

    Evidence read.

    • Public door, before → after (admin): a search over 75 matches answered total 26 → 75. The last page's hasMore went from true to false.
    • POST …/query: 26 → 75. With searchFields, the count equals the unpaged rows (60).
    • Member: 11 → 25 (row scope applied).
    • Controls unchanged: no search; $count=false omits total.
    • Ablations, each red where predicted: A1 (the estimate arm restored), A2 ($count=false), A3 (the internal-field withhold), A4 (the count off the scoped AST), A5 (the count's expansion removed).
    • Packages:
      • objectql 7,802;
      • metadata-protocol 28,129;
      • rest 5,251 + repo 209;
      • spec 19,343 + repo 971.
    • Gates: 116 derived, 115 run, 1 NOT MEASURED locally (check:dual-build-cjs-loads). CI's Build Core carries it, and it concluded success.
    • CI on this head: 35 check-runs, all concluded (33 success, 2 rostered skips; check-expected-skips OK).

    Changesets checked.

    • @objectstack/spec minor (the additive optional members).
    • @objectstack/objectql minor and @objectstack/metadata-protocol patch (the behaviour fix). The four packages share one fixed group.
    • The visible total change is a correction toward the declared meaning, not a narrowing.

    Noted, not filed:

    • skills/objectstack-query/SKILL.md near line 27 now understates count's accepted keys. skills/** is Tier H, so it is the maintainer's docs follow-up, noted for the round report.
    • DataEngineCountRequestSchema inherits the pair in its generated docs only. No reader exists outside packages/spec.
    • The degraded-count catch is untouched, per triage.

    Landing.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #22857 → 55382dc02a · domain:engine seat 1 (#6367) · session_01JfJfBUC3cQ6hhgm9MQK76T · 2026-10-11T15:24Z

    • Merged through the queue at 2026-10-11T15:24:10Z as 55382dc02a. The two readings:
      • The merge commit is an ancestor of origin/main, and findData's countable exception is gone from protocol.ts.
      • The queue branch gh-readonly-queue/main/pr-22857-* is gone.
    • The card closed completed through Fixes #22790. pm:dispatched was removed in this act, and bug, domain:engine, area:records and the grade stay. The lane's closed set since 14:55Z is this card alone.
    • What landed (@objectstack/spec minor, additive; @objectstack/objectql minor; @objectstack/metadata-protocol patch; Clause-②: yes (widening)):
      • A paged list's total under a search is counted under that search, through the one ADR-0061 expander find uses, and on the row-scoped AST. total and hasMore agree.
      • EngineCountOptionsSchema declares search and searchFields.
    • For objectui (domain:ui, fix(plugin-grid,i18n): a paged grid's footer reads the whole matched set, or says it reads the page (objectui#12081 item 3) objectui#12123): the count bar's page-labelled fallback no longer fires under a search, as triage 6106471041 foresaw.
    • Noted for the round report: skills/objectstack-query/SKILL.md (Tier H) now understates count's accepted keys.
    • Records: claim 6108682129, contract review PASS 6110106783, and this seat's ACCEPT 6110260586. The spec declarations are 6108690316 and 6110016343 ([PM seat] domain:spec — 🟢 os-warren · session_019G5ZnRrTMiwcHG6iZM19zf #6017).

    Generated by Claude Code

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

Metadata

Metadata

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:enginepriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions