Skip to content

docs(spec): the element-number D3 entries name the route hop — arrays are lowered by parseFilterAST before the analytics wire (#15828) - #15941

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-15828-d3-entry-route-hop
Sep 5, 2026
Merged

docs(spec): the element-number D3 entries name the route hop — arrays are lowered by parseFilterAST before the analytics wire (#15828)#15941
os-zhuang merged 1 commit into
mainfrom
claude/issue-15828-d3-entry-route-hop

Conversation

@claude

@claude claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #15828

The narrowed, spec-side DOCUMENTATION half of #15828, per the director ruling comment (maintainer, 2026-09-05, verbatim 「15828 按前端缺陷处理」). The user-visible adapter fix is objectui#7752 and is not in this PR.

Prose only. FilterArraySchema, FilterConditionSchema and AnalyticsQuerySchema's type are untouched; no accept-set, runtime or test-behaviour change. AnalyticsQuerySchema.where is still FilterConditionSchema and still refuses an array — which is the protocol working, not a defect.

Why the old text was wrong

packages/spec/src/data/filter.zod.ts, the FilterArray docblock (#5158 ruling C): a FilterArray is input-only authoring sugar, "lowered to a FilterCondition at the single sink parseFilterAST (@objectstack/spec/data) the moment it arrives, and only the lowered FilterCondition travels any further". A POST body's where is transport, not a door.

The element-number-filter-rule-array D3 entry recorded its runtime prerequisite one hop too late — "authored array → adapter lowering → filter AST → accepted by lowerAnalyticsWhere". lowerAnalyticsWhere (service-analytics) is the in-process door (#5334) for callers reaching analyticsService.query directly. The wire's door is the runtime route POST /analytics/query, which parses where with AnalyticsQueryRequestSchema before any service code runs, so an un-lowered array is refused there. objectui#6302's gate measured the service function, not the route, and the entry inherited that hop.

Changes

File Change
packages/spec/src/migrations/entries/semantic/18.element-number-filter-rule-array.ts The reason clause now names the real path and the deciding hop: translateFilterArray yields AST tuples that are still a FilterArray, so the adapter must lower with parseFilterAST BEFORE the wire; the route parses where as a FilterCondition only; lowerAnalyticsWhere is the in-process door. Cites #15828 and objectui#7752. Every other sentence and the whole acceptanceCriteria are byte-identical.
packages/spec/src/data/analytics.zod.ts The where .describe() gains one sentence pointing array authors at the parseFilterAST lowering. Type unchanged.
packages/spec/src/migrations/registry.ts GENERATEDpnpm --filter @objectstack/spec gen:migration-registry, never hand-edited. Diff is exactly the entry clause above.
content/docs/references/api/analytics.mdx, content/docs/references/data/analytics.mdx GENERATEDpnpm --filter @objectstack/spec gen:docs, the one artifact check:generated proved stale. Diff is exactly the new .describe() sentence in the two prop tables.
.changeset/analytics-where-names-the-route-hop.md @objectstack/spec patch — a published package's describe text changed.

18.element-record-picker-filter-rule-array.ts was read for the same claim and does not make it: its measured path is the record picker's find() / convertQueryParams hop, and it names neither the analytics wire nor lowerAnalyticsWhere (grep -i 'analytics|lowerAnalytics|wire' returns nothing in that file). Left unchanged, as the dispatch directed.

Verification

  • pnpm --filter @objectstack/spec check:generated — 15 artifacts, 1 stale (content/docs/references/**), regenerated with gen:docs; re-run green. The migration-registry gate was already green after gen:migration-registry. No skills/** file moved, so no landing path changed.
  • Gate family, node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at 9b431caf: 93 derived commands, all 93 run, each exit code captured by redirect before any pipe. Reconciled with --ran: 93 derived famil(ies) accounted for — 93 run, 0 NOT-MEASURED. Six first answered PREREQUISITE NOT MET rather than a finding (five exit 3 for unbuilt @objectstack/lint / @objectstack/formula / @objectstack/client-react, one shallow-clone pinned fixture); all cleared and re-run green except the one below.
  • pnpm --filter @objectstack/spec typecheck green; pnpm --filter @objectstack/spec test476 test files, 12787 tests, all passed (272s).
  • Declared narrowing, CI's to close: pnpm check:dual-build-cjs-loads still reports PREREQUISITE NOT MET — it reads emitted bytes for 86 packages and needs a whole-monorepo pnpm build, which is a repo-level scan CI owns. Nothing was measured there; it is not a green. This diff changes no package.json, no exports and no build config, so it cannot move that gate. turbo ls --affected lists 75 packages, because nearly everything depends on @objectstack/spec; the changed package's own suite is run above and the remaining 74 are CI's full run.
  • One derivation caveat: origin/main advanced to ea03c7c16 while this branch was being deepened, and dispatch-gates flags the tree as one commit stale on scripts/engine-double-contract.pinned.json. That roster belongs to check:engine-double-contract, which is outside this card's derived 93, and this branch touches none of its inputs.

Generated by Claude Code

…are lowered by parseFilterAST before the analytics wire (#15828)

The `element-number-filter-rule-array` semantic migration entry recorded its
runtime prerequisite at the wrong hop: "authored array → adapter lowering →
filter AST → accepted by `lowerAnalyticsWhere`". Per the `FilterArray` docblock
(#5158 ruling C) a `FilterArray` is input-only sugar lowered at the single sink
`parseFilterAST`; the wire's door is `POST /analytics/query`, which parses
`where` with `AnalyticsQueryRequestSchema` (a `FilterCondition` only) before any
service code runs. `lowerAnalyticsWhere` is the in-process door (#5334) for
direct `analyticsService.query` callers, not the wire's.

Prose only: the entry's reason clause, one sentence on
`AnalyticsQuerySchema.where`'s `.describe()`, the regenerated migration registry
and the two regenerated docs reference pages. No schema, accept-set, runtime or
test-behaviour change. The adapter-side fix is objectui#7752.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TezFG8ZMrNH6n5VTNpPpdH
@github-actions github-actions Bot added the size/s label Sep 5, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 129 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f1e91595f706b7eefb73457754f4eb05fa13e362packageMentionDocs.

Which tree this was computed on

This run read content/docs from bb41334210b9ed8afd268276eb26c90f7bca2308 — the merge of head 9b431caf47eb09b77fc5969253251086eeebab58 into base f1e91595f706b7eefb73457754f4eb05fa13e362, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin bb41334210b9ed8afd268276eb26c90f7bca2308 && git checkout bb41334210b9ed8afd268276eb26c90f7bca2308
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f1e91595f706b7eefb73457754f4eb05fa13e362 9b431caf47eb09b77fc5969253251086eeebab58 && git checkout -B drift-repro f1e91595f706b7eefb73457754f4eb05fa13e362 && git merge --no-ff 9b431caf47eb09b77fc5969253251086eeebab58

node scripts/docs-audit/affected-docs.mjs --json f1e91595f706b7eefb73457754f4eb05fa13e362

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tooling labels Sep 5, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 5, 2026 16:13
@os-zhuang
os-zhuang enabled auto-merge September 5, 2026 16:14
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 5, 2026
Merged via the queue into main with commit ceb4877 Sep 5, 2026
36 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-15828-d3-entry-route-hop branch September 5, 2026 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:data size/s tooling

Projects

None yet

2 participants