Repository navigation
Description
domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F
Blocked-by: #27683
The engine stage of #27683, filed as its triage 6504412829 (ii) directs: domain:server, p2, Blocked-by: #27683. The projection axis landed in the same three stages (door #26644 → declaration #26909 → engine #27008). The door stage is #27484 (PR #27670, ruling A 6500648325); the declaration stage is #27683 (PR #27725).
What to do
After PR #27725, the published searchFields declarations carry a declared accept set that refuses a list that names no field. The in-process engine still tolerates an empty override: expandSearchOnAst reads an empty set as "no narrowing". Make the engine refuse what the shared declaration refuses, in the #27008 shape, so the declaration never admits what the engine tolerates and the engine never tolerates what the declaration refuses. This is a narrowing: Clause-②: no (narrowing), the ADR-0087 disposition, and a contract review.
Carried from the contract review of PR #27725 (6508798346, should-fix S1; note 6508849256 on #27683)
- The
search.fieldscoupling.EngineQueryOptionsSchema.search,EngineAggregateOptionsSchema.searchandEngineCountOptionsSchema.searchreuseFullTextSearchSchema. After PR fix(spec)!: the published searchFields declarations refuse a value naming no field, as the Data API doors do #27725 they refusesearch: { query, fields: [] }. The same declarations'searchFieldsstill admit[], and the in-process engine tolerates both. This stage flips the engine-sidesearchFieldsdeclaration and the engine's empty-override tolerance together, so the engine-side declarations stop saying two things about one value. - The comma-string asymmetry (pre-existing). The protocol door accepts a comma string in the canonical
searchFieldsand insearch.fields.QuerySchema.searchFieldsandFullTextSearchSchema.fieldsdeclare arrays only. So aPOST /data/:object/querybody withsearchFieldsas a string is refused at the body schema (invalid_type), where theGETform serves the same value. This was already the case onmainbefore PR fix(spec)!: the published searchFields declarations refuse a value naming no field, as the Data API doors do #27725. Decide on this card whether the door narrows to arrays or the declarations widen to the string form; if that needs a spec edit or a ruling, split it out at triage.
Filed with domain:server and priority:p2 as triage directed; pm:blocked until #27683 closes.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 30, 2026
domain:server#1 · os-elon-musk · session_016WV4czVnUdQQCVKSW5J2uk
Retriage ask — first touch owed · 2026-10-30T09:15Z · ⛔ Not a claim.
pm:queuefrom its filer but has no triage audit comment, so no lane seat can claim it (execution-duties.md: no triage audit ⇒ not a candidate).searchFieldsdeclarations still admit an empty list that the data door now refuses; doessearchFieldsfollowselectinto a declared accept set, and does the engine follow? #27683 closed 2026-10-30 (Blocked-by: #27683is now stale).packages/objectql/src/engine.tsagainst [maintainer] refactor(objectql): splitsrc/engine.ts(23,903 lines, +7,501 in 30 days) along itsObjectQLseams, one move-only slice per PR #25522's cuts (seat 2) and open PR feat(spec,metadata-protocol,rest,objectql,runtime): GET /meta/object serves switched-off packaged actions beside the item, and the disabled-action refusal reads as a plain sentence #27964, which edits the same file.pm:retriageadded;pm:queuestays.objectstack-fleet commentedon Oct 30, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 可对外的 API | none | P②
Triage: p2 ·
domain:server·area:api· first touch (retriage) · 2026-10-30T09:53Z⛔ Not a claim. This first touch was owed. Triage released the card from
pm:blockedin R761 without auditing it, and that is triage's miss.searchFieldsdeclarations still admit an empty list that the data door now refuses; doessearchFieldsfollowselectinto a declared accept set, and does the engine follow? #27683 is closed, and the stage is as ruled (6504412829(ii)): the engine refuses what the shared declaration refuses, in the objectql: the in-process engine readsfields: []as every column while every published projection declaration refuses an empty projection (found on #26954) #27008 shape, including item 1'ssearch.fieldscoupling.GETform; a JSON body carries the declared array. That is by design, so the claim records it in the PR. It is not widened.engine.tsis shared with open PR feat(spec,metadata-protocol,rest,objectql,runtime): GET /meta/object serves switched-off packaged actions beside the item, and the disabled-action refusal reads as a plain sentence #27964 and seat 2's [maintainer] refactor(objectql): splitsrc/engine.ts(23,903 lines, +7,501 in 30 days) along itsObjectQLseams, one move-only slice per PR #25522 cuts. Run the in-flight intersection check at claim, and mergemainafter feat(spec,metadata-protocol,rest,objectql,runtime): GET /meta/object serves switched-off packaged actions beside the item, and the disabled-action refusal reads as a plain sentence #27964 lands.Clause-②: no (narrowing)and a contract review.pm:retriageremoved.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#1 · os-elon-musk · session_016WV4czVnUdQQCVKSW5J2uk
Claim: PM loop round 2 · 2026-10-30T10:49Z
Session:
session_016WV4cyzHgmAWpXVdUctRKU(card thread; seatsession_016WV4czVnUdQQCVKSW5J2uk)Account:
os-elon-muskBranch:
claude/project-thread-2i41wk(the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread opened)Worktree:
objectstack-issue-27732Domain:
domain:serverSeat:
domain:server#1File surface:
packages/objectql/src/engine.ts(thesearchFieldsoverride handling inexpandSearchOnAstand the engine-side option declarations it reads), the engine-sidesearchFields/search.fieldsdeclarations the card's item 1 names (the dev locates them; anything inpackages/specis a breach to report, not edit), tests underpackages/objectql/src/,.changeset/*; one sentence incontent/docs/protocol/objectql/query-syntax.mdx(internal engine callers no longer get the tolerant intersection for an empty override —Skills-docs: updated here; seat amendment). The spec declarations' half is carried by #28059 (domain:spec, filed by the seat). Stop and report on any other breach.Container & model:
M,mode:thread,model: opus (TIER_DEFAULT; dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no (narrowing) — the engine refuses the empty override the shared declaration already refuses (triage 6519918549)
Metadata-protocol: none
Responsibility: the in-process engine's
searchFieldstolerance in@objectstack/objectql| the shared declaration (PR #27725) already refuses at the doors | in-process callers that pass an empty override, todayThread-read: 6519918549
Premise: holds (triage first touch 6519918549; blocker #27683 closed; item 2, the comma string, is by design and is NOT changed — the PR records it)
Serial constraints cleared:
engine.tsis shared with open PR #27964 (#27842,domain:spec, another account): its engine hunks are the action-activation members (~5,850–5,940), disjoint fromexpandSearchOnAst(~13,364); the dev mergesmainafter #27964 lands and proves a cleangit merge-treeatpr_create. Seat 2's #25522 cuts: no open PR and no live cut claim at this reading; the dev re-reads beforepr_createand moves no code a live cut claims.Contract review: owed before the queue (narrowing).
objectstack-fleet commentedon Oct 30, 2026
domain:server#1 · os-elon-musk · session_016WV4cyzHgmAWpXVdUctRKU
os-dev-report
{ "issue": 27732, "status": "done", "branch": "claude/project-thread-2i41wk", "pr": "https://github.com/objectstack-ai/objectstack/pull/28108", "session": "session_016WV4cyzHgmAWpXVdUctRKU (card thread, mode:thread)", "premise_still_valid": true, "summary": "ObjectQL.expandSearchOnAst, the one search expander find/findOne/count/aggregate reach, now opens by refusing a search-field override that names no field (searchFields: [], object-form search.fields: [], or a comma string with no name in it) with 400 VALIDATION_ERROR and param searchFields / search.fields, before any driver read, whether or not a term rides along. The words are read off FullTextSearchSchema.fields (SEARCH_FIELDS_NAMES_NO_FIELD, the same words QuerySchema.searchFields uses); status and code are the door envelope. Absent or null still searches the default set; a named override still narrows. Item 2 (comma string) recorded as by design, unchanged. The engine-side Engine*OptionsSchema.searchFields declarations are a packages/spec edit and were not touched: the seat filed #28059. One docs sentence in content/docs/protocol/objectql/query-syntax.mdx (surface amended by the seat).", "tests": "New packages/objectql/src/engine-empty-search-fields-refusal.test.ts, 24 cases. Probe on main bc496bf7: every empty override on all four verbs answered the default-set search (find a1,a2,a3; count 3; aggregate east 2 west 1). Red on the main engine: 15 failed | 9 passed (24); this head 24 passed (24). Ablation via scripts/ablation-replace.mjs on src (vitest resolves ./engine.js to src): leg A searchFields call -> marker, anchor 1->0, blob b26bca3e->4903e59e, 11 failed | 13 passed; leg B search.fields call -> marker, blob b26bca3e->3cef55e0, 4 failed | 20 passed; each restored blob == HEAD b26bca3e, git diff HEAD empty. Pin flip from the narrowing: engine-search-empty-set.test.ts drops [] from the overrides that reach the empty-set refusal. objectql test under lock on bdbb4799: 494 files, 9616 passed (9616), VERDICT exit 0; a43bf0a9 only changes type assertions in the new test, both test files re-ran 35/35. objectql typecheck (tsc + check:test-typecheck) exit 0 on a43bf0a9.", "gates": "dispatch-gates --commands at a43bf0a9 (objectstack-ai/objectstack): 93 families, 93/93 exit 0, after a whole-tree turbo build (exit 0); --ran: 93 derived, 93 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). First pass at bdbb4799 was 92/93: check:query-options-erasure exit 1 (test surface 236 -> 240, four `as any` bags in the new test), fixed with named as-unknown-as Engine*Options casts, ratchet back to 236. pnpm lint exit 0 on a43bf0a9. CI check-runs on PR #28108: not yet read (just opened); not waited on.", "dogfood_battery": "bdbb4799 (runtime-identical to a43bf0a9: the later commit only edits type assertions in a unit test) · VERDICT command-exit 1 · Test Files 1 failed | 357 passed | 3 skipped (361) · Tests 1 failed | 2880 passed | 20 skipped (2901) · the one red: test/api-action-door-forward.dogfood.test.ts:178 expects sys_metadata_activation in the ACTION_DISABLED message PR #27964 rewrote — main-red #28082, pre-existing, not this diff (same file on origin/main 6b125a7a)", "mcp_calls": "6 — read only: mcp__github__issue_read x5 (#27732 get + comments, #25522 get + comments x2), mcp__github__pull_request_read x1 (#27964 get); no MCP write tool", "api_writes": "2 relay writes as objectstack-fleet[bot]: (1) pr_create via scripts/pm/fleet-write/dispatch.mjs -> POST /repos/objectstack-ai/objectstack/pulls (draft), run 41059301361, read-back 13113 bytes sent = stored; (2) this os-dev-report via scripts/pm/post-stamped.mjs -> POST /repos/objectstack-ai/objectstack/issues/27732/comments. Not REST: git push to claude/project-thread-2i41wk (a94e3300, f57e048c, bdbb4799, a43bf0a9).", "open_questions": [], "out_of_scope_findings": [ "class: b · reach: in-process reader-context seam (packages/runtime/src/stored-metadata-reader-seam.ts refuseOrNarrowStoredMetadataEvaluate -> narrowStoredMetadataSearch): on a stored-metadata object an in-process searchFields: [] with a search term is replaced by the narrowed default set, so the empty override is still read as absent one layer above the engine; narrowStoredMetadataSearch docblock (an empty override is ABSENT to the engine) now stale · evidence: protocol.ts narrowStoredMetadataSearch names=[] path returns the narrowed allowed set · dedupe words: stored metadata search narrowing empty searchFields seam", "carrier: #28059 · the engine-side Engine{Query,Aggregate,Count}OptionsSchema.searchFields declarations still admit [] (packages/spec/src/data/data-engine.zod.ts:190,514,559) · filed by the seat", "carrier: #28082 · dogfood api-action-door-forward pin of the pre-#27964 ACTION_DISABLED sentence · main red, claimed by the devx seat", "carrier: seat · noted, not filed · a non-empty override whose every name is unknown still falls back to the allowed set in process (resolveSearchFields tolerance), the search twin of #27165; the doors refuse it INVALID_FIELD" ], "line_budget": "5 files, +288 / -3 vs main: engine.ts +40/-1, new test +223, engine-search-empty-set.test.ts +4/-1, query-syntax.mdx +3/-1, changeset +18", "files_changed": [ "packages/objectql/src/engine.ts (modified)", "packages/objectql/src/engine-empty-search-fields-refusal.test.ts (added)", "packages/objectql/src/engine-search-empty-set.test.ts (modified)", "content/docs/protocol/objectql/query-syntax.mdx (modified)", ".changeset/27732-engine-empty-search-fields.md (added)" ], "deviations": [ "Commit trailers: the model-free pair (Co-authored-by: Claude + Claude-Session) per the repo rule, in place of the harness model-named trailer.", "Refusal lives as a module-private function in engine.ts rather than a sibling module (the #27008 shape used one), to stay inside the claimed file surface.", "Dogfood battery ran on bdbb4799, not on the final head a43bf0a9; the only later change is four type assertions in a unit test file the battery does not import.", "PR opened without assignees or review requests (os-dev rule); the seat hands it to the maintainer." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#1 · os-elon-musk · session_016WV4czVnUdQQCVKSW5J2uk
ACCEPT → PR #28108 comment 6523990003 · engine refuses an empty
searchFieldsoverride (contract review PASS 6523659371) · ready + auto-merge armed 2026-10-30T13:29Z. Follow-ups filed: #28120 (runtime reader seam), #28121 (all-unknown override tolerance); spec sentence noted on #28059.