Skip to content

perf(service-settings): getMany resolves same-namespace keys with one grouped row load (#10826) - #11200

Merged
os-zhuang merged 1 commit into
mainfrom
fix/settings-getmany-10826
Aug 23, 2026
Merged

perf(service-settings): getMany resolves same-namespace keys with one grouped row load (#10826)#11200
os-zhuang merged 1 commit into
mainfrom
fix/settings-getmany-10826

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What

SettingsService.getMany(namespace, keys, ctx): validate everything up front, resolve env overrides first (an override answers without touching the store, exactly as get() does), group the remaining keys by their scope's loadRows argument (user(ns, userId), else (ns, null)), one load per group (both in parallel), and walk each key's cascade over its group's rows. The cascade is extracted from get() into a shared resolveKeyFromRows — not copied — so per-key answers deep-equal get()'s by construction. getNamespace resolves through the same grouped path (N keys → ≤2 loads).

Why (the card's own calibration honored)

resolveLocalizationContext issued three identical sys_setting namespace reads per request (queries 16–18/24, PR #10824's rig). They already ran parallel — 1 leg — so per cloud#1539 this is a query-count fix, not a latency fix, scheduled at the card's stated low priority as the same one-question-asked-repeatedly class as #10824's fixes. No caching; nothing survives the call (the #10221 failed-read TTL cache is untouched).

Tests

New settings-getmany.test.ts (6): per-key deep-equivalence with get() across scope mixes; read-count contract measured at the engine (same-scope → 1 find, mixed → 2, env-overridden → 0); unknown-key refusal parity; getNamespace through the grouped path with unchanged answers. Full service-settings suite 477 passed, package tsc 0 errors.

Serial note

The resolve-authz-context.ts caller switches to getMany in a follow-up commit on the #10825 branch after it lands (same-file serial ruling by the domain:engine seat — this PR touches only service-settings).

Part of #10826.

🤖 Generated with Claude Code

… grouped row load (#10826)
resolveLocalizationContext (and getNamespace) called get() once per
key, and every call ran loadRows over the whole namespace — three
identical sys_setting reads inside one request (queries 16-18 of 24 on
a live rig, PR #10824; already 1 leg since they run parallel, so per
cloud#1539's calibration this is a query-count fix, not a latency fix,
and the card is scheduled accordingly).
getMany(namespace, keys, ctx): validate namespace + every key up
front; resolve env overrides first (an override answers without
touching the store, exactly as get() does); group the remaining keys
by which loadRows argument their scope requires (user-scoped keys read
(ns, userId), everything else (ns, null)); ONE load per group, both
groups in parallel; walk each key's cascade over its group's rows.
The cascade is EXTRACTED from get() into resolveKeyFromRows — shared,
not copied — so per-key answers deep-equal get()'s by construction
(pinned across env overrides, scope mixes, unknown-key refusal, and
the read-count contract itself). getNamespace resolves through the
same grouped path: N keys, <=2 loads. No caching; nothing survives
the call.
The resolve-authz-context caller switches to getMany in a follow-up on
the #10825 branch (same-file serial ruling by the domain:engine seat).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size/m documentation Improvements or additions to documentation tests tooling labels Aug 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/service-settings, touching 4 documentable anchor(s).

3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/data-modeling/drivers.mdx(via SettingsService (symbol))
  • content/docs/protocol/kernel/config-resolution.mdx(via SettingsService (symbol))
  • content/docs/protocol/kernel/index.mdx(via SettingsService (symbol))
What this run could not see
  • the SDK route bridge reached 45 of 221 client-bound route-ledger rows — the other 176 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run: node scripts/docs-audit/affected-docs.mjs --bridge-coverage

Coarse fallback — 7 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 18d5fec196de76c5054901521d01732f28e5128apackageMentionDocs.

Which tree this was computed on

This run read content/docs from d11ada336a135411033cf07a2f15a8f11d2a7703 — the merge of head 0ab67230169fcdf783e8dc4a133140c060ac99b5 into base 18d5fec196de76c5054901521d01732f28e5128a, 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 d11ada336a135411033cf07a2f15a8f11d2a7703 && git checkout d11ada336a135411033cf07a2f15a8f11d2a7703
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 18d5fec196de76c5054901521d01732f28e5128a 0ab67230169fcdf783e8dc4a133140c060ac99b5 && git checkout -B drift-repro 18d5fec196de76c5054901521d01732f28e5128a && git merge --no-ff 0ab67230169fcdf783e8dc4a133140c060ac99b5
node scripts/docs-audit/affected-docs.mjs --json 18d5fec196de76c5054901521d01732f28e5128a

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

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 18d5fec196de76c5054901521d01732f28e5128a → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@os-zhuang
os-zhuang added this pull request to the merge queueAug 23, 2026
Merged via the queue into main with commit ba6c9edAug 23, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the fix/settings-getmany-10826 branch August 23, 2026 03:11
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 23, 2026
…ettings.getMany (objectstack-ai#10826) (objectstack-ai#11208)
The caller half of objectstack-ai#10826 (service half: objectstack-ai#11200). One grouped
namespace read replaces three per-key get()s — queries 16-18 of 24 on
the measured rig collapse to one, with per-key answers unchanged by
the service's equivalence contract. Feature-detected: an older service
without getMany keeps the three parallel gets (still one leg — this is
a query-count fix per the card's own calibration, not a latency fix).
A thrown getMany lands exactly where a thrown get did: failed=true and
the direct $in fallback, which reads the same three keys. Serial
constraint honored: landed after objectstack-ai#11197 (objectstack-ai#10825) on this file.
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang