Skip to content

perf: reduce /api/tools server time on the read path - #9

Merged
amondnet merged 3 commits into
mainfrom
amondnet/reduce-api-tools-server-time-skip-stale-sync-on
Jun 25, 2026
Merged

perf: reduce /api/tools server time on the read path#9
amondnet merged 3 commits into
mainfrom
amondnet/reduce-api-tools-server-time-skip-stale-sync-on

Conversation

@amondnet

@amondnetamondnet commented Jun 25, 2026

Copy link
Copy Markdown

Summary

Sub-task of #3 (Fix A): cut /api/tools server time, the measured long pole on the web UI.

Both issues called out in #4 were verified against the code first, then fixed TDD-style.

1. Skip the stale-sync scan on reads (packages/core/sdk)

tools.list ran syncStaleConnectionTools unconditionally: a read of revised integrations plus a connection scan, on every call. Because config_revised_at stays set after the first config change, the steady state was two full reads that rebuilt nothing.

Now the read of revised integrations doubles as a revision watermark. Once every connection is confirmed synced at the current watermark, that is cached per binding and the connection scan is skipped until a new revision moves the watermark:

  • The cache is a WeakMap keyed by the underlying DB handle, then by tenant+subject. In production every per-request scoped executor in an isolate shares one long-lived handle, so the cache survives executor rebuilds and the saving lands; each test builds a fresh DB object, so entries are naturally isolated (no cross-test contamination) and GC'd with the handle.
  • The watermark is read fresh every call, so a revision on any isolate busts the cache on the next read. Lazy cross-subject convergence stays correct.
  • A failed rebuild is left uncached so the next read retries it (best-effort behavior preserved).

Net: steady-state tools.list drops from two table reads to one.

2. Filter listOperations at the storage layer (packages/plugins/openapi)

listOperations read the whole operation collection and filtered by integration in memory. Even passing a key prefix did not reach the DB (the facade applied it in JS after a full scan).

  • Added keyPrefixes to the plugin-storage list input; the facade now pushes key starts with clauses to the storage layer (LIKE 'prefix%').
  • The store passes both the v2 hashed prefix (op.<hash>.) and the legacy plaintext prefix (<slug>.), keeping the data.integration JS guard as the source of truth, so un-migrated legacy rows are never dropped and LIKE wildcard over-match is harmless.

Tests

  • New: facade list with keyPrefixes over real SQLite; openapi store listOperations (per-integration, legacy-safe, prefix-narrowing); syncStaleConnectionTools skip / cache-bust / retry, driven by a per-table query counter.
  • Existing cross-subject convergence coverage (updateSpec propagates to OTHER subjects' personal connections) exercises the new cache + starts with path on real SQLite and stays green.
  • packages/core/sdk 352/352, packages/plugins/openapi 151/151. format:check, lint, and typecheck clean.

Closes#4

Summary by CodeRabbit

  • New Features
    • 저장소 조회에서 keyPrefix 외에 keyPrefixes를 지원해 여러 접두사로 더 정확히 조회합니다.
    • OpenAPI 작업 목록 조회 범위를 통합 기준 키 프리픽스로 좁혀 처리합니다.
  • Bug Fixes
    • 오래된 연결 도구 동기화가 워터마크 기반으로 캐시되어 불필요한 재스캔을 줄이고 성능이 향상됩니다.
    • 설정 변경/재빌드 실패 시 캐시 무효화가 올바르게 적용됩니다.
  • Tests
    • 접두사 필터링, 레거시 키 호환성, 재시도/캐시 스코핑 시나리오를 확장 검증합니다.
  • Chores
    • 관련 패키지 버전을 patch로 업데이트했습니다.

`tools.list` ran the stale-connection-tools sync on every call: an
unconditional read of revised integrations plus a connection scan, even
when nothing was stale (the steady state, since config_revised_at stays
set after the first revision). Cache, per binding, the highest revision
watermark at which everything was confirmed synced, keyed by the DB
handle so the entry survives per-request executor rebuilds in a prod
isolate and stays isolated across tests. The watermark is read fresh
each call, so any new revision busts the cache and lazy convergence
stays correct; a failed rebuild is left uncached so it retries.
The openapi operation store filtered listOperations in memory after
reading the whole collection. Push the integration filter to the storage
layer via key-prefix `starts with` clauses (covering both the v2 hashed
prefix and the legacy plaintext prefix), keeping the data.integration
guard as the source of truth.
@amondnetamondnet self-assigned this Jun 25, 2026
@amondnet

Copy link
Copy Markdown
Author

/gemini review

@amondnet

Copy link
Copy Markdown
Author

@cubic-dev-ai review

@cubic-dev-ai

Copy link
Copy Markdown

@cubic-dev-ai review

@amondnet I have started the AI code review. It will take a few minutes to complete.

@amondnet

Copy link
Copy Markdown
Author

@greptileai review

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the performance of the tools.list read path and the OpenAPI operation store. It introduces a keyPrefixes option to the plugin storage layer, allowing listOperations to filter by integration at the storage layer (using both v2 hashed and legacy plaintext prefixes) rather than filtering in memory. Additionally, the stale-connection-tools sync now skips scanning connections once they are synced at the current revision watermark. Comprehensive tests have been added to verify these behaviors. There are no active review comments remaining, and we have no further feedback to provide.

@amondnet

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitaiBot commented Jun 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitaiBot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ca1f3302-e82a-4417-b1a3-50910dba0772

📥 Commits

Reviewing files that changed from the base of the PR and between a0e403e and f77140c.

📒 Files selected for processing (1)
  • packages/core/sdk/src/executor.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • chatbot-pf/reference-please(manual)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/sdk/src/executor.test.ts

Walkthrough

PluginStorage 리스트 입력이 여러 접두사를 지원하도록 바뀌고, OpenAPI operation 조회는 integration별 prefix로 스토리지 범위를 좁히며, executor는 revision watermark 기반 stale-sync 캐시와 재시도 동작을 추가했다.

Changes

API 도구 읽기 경로 변경

Layer / File(s)Summary
스토리지 리스트 입력 확장
packages/core/sdk/src/plugin-storage.ts, packages/core/sdk/src/plugin-storage.test.ts
PluginStorageListInputkeyPrefixes가 추가되고, list가 입력을 그대로 전달하며 단일/다중 prefix와 빈 입력 동작을 검증한다.
OpenAPI operation 스캔 제한
packages/plugins/openapi/src/sdk/store.ts, packages/plugins/openapi/src/sdk/store.test.ts
makeDefaultOpenapiStorepluginStorage.list에 v2 해시 prefix와 legacy 평문 prefix를 함께 전달하고, integration 범위와 legacy 행 반환을 테스트한다.
Executor stale-sync 캐시
packages/core/sdk/src/executor.ts, packages/core/sdk/src/executor.test.ts
syncStaleConnectionTools가 revision watermark 캐시와 실패 무효화를 사용하고, key prefix 조회가 DB 레벨에서 좁혀지며, 관련 테스트가 재스캔 스킵과 subject 스코프를 검증한다.
변경 기록 갱신
.changeset/reduce-api-tools-server-time.md, .please/docs/review/rejected-findings.jsonl
변경 배포 메타정보와 rejected review findings 기록이 추가된다.

Sequence Diagram(s)

sequenceDiagram
participant toolsList
participant syncStaleConnectionTools
participant pluginStorage
participant resolveTools
toolsList->>syncStaleConnectionTools: 현재 revision watermark 확인
syncStaleConnectionTools->>pluginStorage: keyPrefixes로 stale 연결 스캔
alt watermark unchanged
syncStaleConnectionTools-->>toolsList: 스캔 건너뜀
else watermark changed
syncStaleConnectionTools->>resolveTools: stale 연결 재빌드
alt 재빌드 실패
resolveTools-->>syncStaleConnectionTools: 실패
syncStaleConnectionTools-->>toolsList: 다음 읽기에서 재시도
else 재빌드 성공
resolveTools-->>syncStaleConnectionTools: 성공
syncStaleConnectionTools-->>toolsList: watermark 캐시 저장
end
end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ Warningstale-sync 캐시와 DB 레벨 integration 필터링은 구현됐지만, 변경 패키지의 vitest 실행 범위를 좁히는 작업은 보이지 않습니다.변경된 패키지만 대상으로 vitest가 실행되도록 스크립트나 CI 설정을 추가하세요.
Out of Scope Changes check⚠️ Warning기능 목표와 무관한 .please/docs/review/rejected-findings.jsonl 추가가 포함되어 있습니다.이 리뷰 메타데이터 변경은 별도 PR로 분리하거나 이번 기능 변경에서 제외하세요.
✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ Passed제목은 /api/tools 읽기 경로의 서버 시간 단축이라는 핵심 변경을 간결하게 요약합니다.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch amondnet/reduce-api-tools-server-time-skip-stale-sync-on

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-appsBot commented Jun 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR reduces /api/tools server time by adding a watermark cache that skips the stale-connection-tools scan once all connections are confirmed synced at the current config revision, and by pushing integration-scoped key-prefix filters to the storage layer in the OpenAPI plugin instead of reading the entire operation collection.

  • packages/core/sdk – watermark cache in syncStaleConnectionTools: A WeakMap<DB handle, Map<cache key, number>> stores the highest revision watermark at which every connection was confirmed synced. On subsequent reads with the same watermark the connection table scan is skipped entirely; a failed rebuild leaves the entry uncached so the next read retries. The cache key uses a NUL separator (tenant\u0000subject) preventing any collision between valid slug-style IDs.
  • packages/plugins/openapi – storage-layer keyPrefixes filtering:listOperations now passes both the v2 hashed prefix (op.<hash>.) and the legacy plaintext prefix (<slug>.) to the storage facade's list call, which translates them into LIKE 'prefix%' SQL clauses. The JS data.integration guard remains the authoritative filter, safely handling any LIKE over-match from _/% in legacy slug prefixes or hash-prefix collisions. The base-36 hash output contains only [0-9a-z], so the hashed prefix is always wildcard-free.

Confidence Score: 5/5

Safe to merge: both optimizations are additive read-path changes with comprehensive tests and correct fallback behavior on failure.

The watermark cache uses a NUL-byte key separator (confirmed in code at line 2501), a WeakMap for natural GC scoping, and leaves failures uncached so the next read always retries. The LIKE prefix scan retains a JS post-filter as the authoritative guard, and the base-36 hash output contains no LIKE wildcard characters. Test coverage spans cache skip, cache bust on revision, retry-on-failure, and cross-subject isolation. No existing behavior is removed; the only behavioral change is skipping a redundant connection-table scan in the steady state.

No files require special attention.

Important Files Changed

FilenameOverview
packages/core/sdk/src/executor.tsAdds WeakMap-backed watermark cache for syncStaleConnectionTools; NUL-separated cache key, correct allClean/failure-uncached logic, and no change to prior connection-rebuild behavior.
packages/plugins/openapi/src/sdk/store.tsAdds keyPrefixes to listRows, covering v2 hashed and legacy plaintext schemes; JS data.integration guard preserved as source of truth for correctness.
packages/core/sdk/src/plugin-storage.tsAdds optional keyPrefixes field to PluginStorageListInput; well-documented with LIKE over-match caveat.
packages/core/sdk/src/executor.test.tsNew syncStaleConnectionTools tests cover skip-on-match, cache-bust on new revision, retry-on-failure, and cross-subject isolation using a per-table query counter; thorough and well-structured.
packages/plugins/openapi/src/sdk/store.test.tsRefactored from ad-hoc inline storage into shared makeInMemoryPluginStorage; new tests cover per-integration filtering, keyPrefixes assertion, and legacy-key compat.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[tools.list called] --> B[syncStaleConnectionTools]
B --> C[Read revised integrations\nconfig_revised_at IS NOT NULL]
C --> D{revised.length == 0?}
D -- yes --> E[Return early: nothing to sync]
D -- no --> F[Compute watermark = max config_revised_at]
F --> G{staleSyncCache.get\ncacheKey == watermark?}
G -- yes: cache hit --> H[Skip connection scan]
G -- no: cache miss --> I[Read connections for revised integrations]
I --> J[For each connection: syncedAt < revisedTime?]
J -- no: already synced --> K[continue]
J -- yes: stale --> L[produceConnectionTools]
L -- success --> M[allClean stays true]
L -- failure --> N[allClean = false]
K --> O{all done?}
M --> O
N --> O
O -- allClean=true --> P[staleSyncCache.set\ncacheKey, watermark]
O -- allClean=false --> Q[Leave uncached: retry next read]
H --> R[Read tool rows and return]
P --> R
Q --> R
subgraph openapi["OpenAPI listOperations"]
S[listOperations integration] --> T[pluginStorage.list with keyPrefixes:\nop.hash. + integration.]
T --> U[DB: LIKE 'op.hash.%' OR LIKE 'integration.%']
U --> V[JS post-filter: data.integration === integration]
V --> W[Return filtered operations]
end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[tools.list called] --> B[syncStaleConnectionTools]
B --> C[Read revised integrations\nconfig_revised_at IS NOT NULL]
C --> D{revised.length == 0?}
D -- yes --> E[Return early: nothing to sync]
D -- no --> F[Compute watermark = max config_revised_at]
F --> G{staleSyncCache.get\ncacheKey == watermark?}
G -- yes: cache hit --> H[Skip connection scan]
G -- no: cache miss --> I[Read connections for revised integrations]
I --> J[For each connection: syncedAt < revisedTime?]
J -- no: already synced --> K[continue]
J -- yes: stale --> L[produceConnectionTools]
L -- success --> M[allClean stays true]
L -- failure --> N[allClean = false]
K --> O{all done?}
M --> O
N --> O
O -- allClean=true --> P[staleSyncCache.set\ncacheKey, watermark]
O -- allClean=false --> Q[Leave uncached: retry next read]
H --> R[Read tool rows and return]
P --> R
Q --> R
subgraph openapi["OpenAPI listOperations"]
S[listOperations integration] --> T[pluginStorage.list with keyPrefixes:\nop.hash. + integration.]
T --> U[DB: LIKE 'op.hash.%' OR LIKE 'integration.%']
U --> V[JS post-filter: data.integration === integration]
V --> W[Return filtered operations]
end
Loading

Reviews (4): Last reviewed commit: "test(sdk): scope the per-subject cache t..." | Re-trigger Greptile

Comment threadpackages/core/sdk/src/executor.ts Outdated
@greptile-apps

greptile-appsBot commented Jun 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR optimizes the /api/tools read path with two targeted changes: a per-binding watermark cache in syncStaleConnectionTools that skips the connection scan once every connection is confirmed synced at the current config_revised_at maximum, and storage-layer key-prefix filtering in listOperations that replaces a full-collection scan with a two-prefix LIKE query covering both the v2 hashed scheme and the legacy plaintext scheme.

  • executor.ts: Adds a module-level WeakMap<object, Map<string, number>> keyed by DB handle, storing the highest confirmed-synced watermark per (tenant, subject) binding; the connection scan is bypassed on cache hits and retried on any rebuild failure.
  • plugin-storage.ts / executor.ts facade: Extends PluginStorageListInput with keyPrefixes and pushes the union of keyPrefix/keyPrefixes as key LIKE 'prefix%' clauses to the DB; a post-filter startsWith guard corrects _/% wildcard over-matches.
  • store.ts: listRows now passes the v2 hashed prefix and the legacy slug prefix as keyPrefixes, keeping the existing data.integration JS guard as the authoritative correctness check.

Confidence Score: 4/5

The change is a focused read-path optimization with no mutations to the write path; the watermark cache logic is correct and well-tested, and the storage-layer prefix filtering preserves a JS-level correctness guard.

Both findings are theoretical: the cache-key space-separator collision requires tenant or subject IDs to contain spaces (unlikely given slug validation elsewhere), and the inner-Map growth only matters in long-lived processes handling very large numbers of distinct bindings. The new test suite covers cache-hit, cache-bust, and failure-retry paths against real SQLite. No correctness regressions were found.

packages/core/sdk/src/executor.ts — the watermark cache construction (key format and Map lifetime) is the only area that warrants a second look before merging to a high-tenant production environment.

Important Files Changed

FilenameOverview
packages/core/sdk/src/executor.tsAdds watermark cache for syncStaleConnectionTools; logic is sound but the cache-key separator and unbounded inner-Map growth are minor concerns worth noting.
packages/core/sdk/src/plugin-storage.tsExtends PluginStorageListInput with keyPrefixes; additive, backwards-compatible, and the interface doc is clear about the LIKE over-match caveat.
packages/plugins/openapi/src/sdk/store.tslistRows now pushes v2-hashed and legacy key prefixes to the storage layer; the retained data.integration JS guard preserves correctness against hash collisions and LIKE wildcards.
packages/core/sdk/src/executor.test.tsNew syncStaleConnectionTools test suite covers skip-on-cache-hit, cache-bust on new revision, and no-cache-on-failure paths; good coverage of the new behavior.
packages/core/sdk/src/plugin-storage.test.tsAdds keyPrefixes list test covering multi-prefix narrowing, single keyPrefix back-compat, and no-prefix full-collection scan.
packages/plugins/openapi/src/sdk/store.test.tsRefactored into a shared in-memory storage fixture; new tests verify per-integration isolation, prefix narrowing at the facade call site, and legacy-keyed row retrieval.
.changeset/reduce-api-tools-server-time.mdChangeset marks both sdk and plugin-openapi as patch bumps, which is appropriate for a performance-only change.

Comments Outside Diff (1)

  1. packages/core/sdk/src/executor.ts, line 252-261 (link)

    P2 Unbounded inner-Map growth: staleSyncWatermarkFor returns a Map<string, number> that accumulates one entry per unique (tenant, subject) binding for as long as the DB handle is alive. In a long-running process that serves many distinct tenants, the inner Map grows without any eviction. Each entry is tiny, so this is unlikely to be critical, but a size cap or LRU eviction policy would bound worst-case memory use in high-tenant deployments.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/core/sdk/src/executor.ts
    Line: 252-261
    Comment:
    Unbounded inner-Map growth: `staleSyncWatermarkFor` returns a `Map<string, number>` that accumulates one entry per unique `(tenant, subject)` binding for as long as the DB handle is alive. In a long-running process that serves many distinct tenants, the inner Map grows without any eviction. Each entry is tiny, so this is unlikely to be critical, but a size cap or LRU eviction policy would bound worst-case memory use in high-tenant deployments.
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---### Issue 1 of 2
packages/core/sdk/src/executor.ts:252-261
Unbounded inner-Map growth: `staleSyncWatermarkFor` returns a `Map<string, number>` that accumulates one entry per unique `(tenant, subject)` binding for as long as the DB handle is alive. In a long-running process that serves many distinct tenants, the inner Map grows without any eviction. Each entry is tiny, so this is unlikely to be critical, but a size cap or LRU eviction policy would bound worst-case memory use in high-tenant deployments.
### Issue 2 of 2
packages/core/sdk/src/executor.ts:2499
Cache-key ambiguity with a space separator: `` `${tenant} ${subject ?? ""}` `` collides when a tenant ID contains a space — tenant `"foo bar"` + subject `"baz"` produces the same key as tenant `"foo"` + subject `"bar baz"`, causing two distinct bindings to share a watermark entry and potentially skip the connection scan prematurely. A null-byte separator (`` `${tenant}\0${subject ?? ""}` ``) cannot appear in a valid slug and eliminates the ambiguity.

Reviews (2): Last reviewed commit: "perf: reduce /api/tools server time on t..." | Re-trigger Greptile

Comment threadpackages/core/sdk/src/executor.ts Outdated
From code review of #4:
- Add a regression test proving the stale-sync watermark cache is keyed per
subject: two subjects sharing one DB handle must each scan independently, so
one binding converging cannot make another skip and serve a stale catalog.
- Write the cache-key separator as an explicit unicode escape instead of an
invisible literal NUL byte (which read as a space and misled the reviewer),
and note why. No behavior change; the separator was and stays NUL.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/plugins/openapi/src/sdk/store.test.ts (1)

81-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

인메모리 facade가 LIKE 와일드카드 과매칭을 재현하지 않아 data.integration 가드가 테스트되지 않습니다.

이 facade는 JS startsWith로만 필터링하므로 실제 스토리지 레이어의 LIKE 'prefix%'(_/%를 와일드카드로 취급)에서 발생하는 과매칭을 흉내내지 못합니다. store.ts가 "source of truth"라고 명시한 rowToOperation(row)?.integration === integration 가드를 실제로 검증하는 경로가 없어, 향후 그 가드가 제거되어도 테스트가 통과합니다. 통합 슬러그에 _가 포함된 두 통합(예: a_b, axb)을 시드해 가드가 교차 통합 행을 걸러내는지 확인하는 케이스를 추가하는 것을 고려해 보세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/plugins/openapi/src/sdk/store.test.ts` around lines 81 - 90, The
in-memory storage facade in store.test.ts is only using startsWith, so it does
not reproduce the real LIKE prefix overmatching behavior and leaves the
rowToOperation(row)?.integration === integration guard untested. Update the test
setup around list to include a case where integration slugs contain
wildcard-relevant characters such as an underscore, seed two integrations like
a_b and axb with overlapping prefixes, and verify that the store.ts filtering
path still excludes cross-integration rows. Use the existing
list/input/prefixesOf and rowToOperation symbols to add an assertion that the
integration guard is what prevents the incorrect match.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/plugins/openapi/src/sdk/store.test.ts`:
- Around line 81-90: The in-memory storage facade in store.test.ts is only using
startsWith, so it does not reproduce the real LIKE prefix overmatching behavior
and leaves the rowToOperation(row)?.integration === integration guard untested.
Update the test setup around list to include a case where integration slugs
contain wildcard-relevant characters such as an underscore, seed two
integrations like a_b and axb with overlapping prefixes, and verify that the
store.ts filtering path still excludes cross-integration rows. Use the existing
list/input/prefixesOf and rowToOperation symbols to add an assertion that the
integration guard is what prevents the incorrect match.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b1efcba1-b7c7-43fa-800a-45d3fd84286e

📥 Commits

Reviewing files that changed from the base of the PR and between d958b31 and 0b0d4ef.

📒 Files selected for processing (7)
  • .changeset/reduce-api-tools-server-time.md
  • packages/core/sdk/src/executor.test.ts
  • packages/core/sdk/src/executor.ts
  • packages/core/sdk/src/plugin-storage.test.ts
  • packages/core/sdk/src/plugin-storage.ts
  • packages/plugins/openapi/src/sdk/store.test.ts
  • packages/plugins/openapi/src/sdk/store.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • chatbot-pf/reference-please(manual)

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/sdk/src/executor.ts (1)

2507-2512: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

워터마크를 벽시계 밀리초 값으로만 비교하면 같은 ms의 새 revision을 놓칠 수 있습니다.

Line 2512에서 캐시된 watermark와 숫자 동등성만 비교하므로, config_revised_at = now.getTime()으로 찍힌 두 config 변경이 같은 millisecond에 발생하면 새 변경이 있어도 connection scan을 건너뛰고 stale tool catalog를 계속 반환할 수 있습니다. revision은 벽시계가 아니라 단조 증가하는 DB revision/counter로 만들거나, 최소한 기존 row 값보다 반드시 크게 bump되도록 보장해 주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/core/sdk/src/executor.ts` around lines 2507 - 2512, The
staleSyncCache watermark check in executor.ts is using wall-clock milliseconds
from config_revised_at, so equal-ms updates can be skipped and leave stale tool
catalog data. Update the watermark logic around the revised.reduce and
staleSyncCache.get comparison to use a monotonically increasing DB
revision/counter, or otherwise guarantee each new config revision is strictly
greater than the previous one before comparing and returning early.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/core/sdk/src/executor.test.ts`:
- Around line 688-698: The cleanup in executor.test is not guaranteed if an
assertion or earlier effect fails, so the executor and SQLite handle may remain
open. Wrap the block around a.tools.list(), b.tools.list(), and the
counts.connection assertion in a try/finally or use Effect.ensuring so that
a.close(), b.close(), and Effect.promise(() => real.close()) always run. Use the
existing a, b, and real handles in executor.test to place the cleanup in the
guaranteed finalization path.
---
Outside diff comments:
In `@packages/core/sdk/src/executor.ts`:
- Around line 2507-2512: The staleSyncCache watermark check in executor.ts is
using wall-clock milliseconds from config_revised_at, so equal-ms updates can be
skipped and leave stale tool catalog data. Update the watermark logic around the
revised.reduce and staleSyncCache.get comparison to use a monotonically
increasing DB revision/counter, or otherwise guarantee each new config revision
is strictly greater than the previous one before comparing and returning early.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5178cf35-ee69-441d-a4f8-b6e091285802

📥 Commits

Reviewing files that changed from the base of the PR and between 0b0d4ef and a0e403e.

📒 Files selected for processing (3)
  • .please/docs/review/rejected-findings.jsonl
  • packages/core/sdk/src/executor.test.ts
  • packages/core/sdk/src/executor.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • chatbot-pf/reference-please(manual)
✅ Files skipped from review due to trivial changes (1)
  • .please/docs/review/rejected-findings.jsonl

Comment threadpackages/core/sdk/src/executor.test.ts Outdated

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 3 files (changes from recent commits).

Auto-approved: Performance optimizations on the read path: caching the stale-connection sync watermark and narrowing storage queries by key prefix. Both are backward-compatible, well-tested, and carry low risk.

Re-trigger cubic

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: Performance optimization adding caching and storage-layer filtering across core SDK and openapi plugin; requires human review to verify correctness and edge cases.

Re-trigger cubic

@amondnet
amondnet merged commit e12cfb2 into mainJun 25, 2026
4 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduce /api/tools server time: skip stale-sync on read, filter listOperations by integration

1 participant

@amondnet