feat(golbat): discover instance capabilities from /api/status - #1258
feat(golbat): discover instance capabilities from /api/status#1258jfberry wants to merge 2 commits into
Conversation
Add a GolbatCapabilities service that reads GET /api/status from every
configured Golbat endpoint and keeps { features, limits, filters } per
instance, keyed by the endpoint base url. Discovery runs from
DbManager.getDbContext (startup and config reload), refreshes every five
minutes, and rechecks an instance immediately, debounced to once per
30 s, when a scanner call answers 400/422 — the first sign of a
downgrade. A 404 or non-JSON body means an older Golbat with no
capabilities; any other failure keeps the last good result.
Pokestop.getAvailable now decides showcase focus support from
supportsFilter(mem, 'showcase_focus') when the status route advertises
filters, and only falls back to the deprecated per-response
showcase_focus_filter flag for a build that does not. The hard error on
an unsupported build is unchanged; only the source of truth moves. The
header builder shared by the evaluator and the service is extracted
into scannerHeaders.js.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016611GTrQ2W8WcznKrLQnMv
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 12e3acca32
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if ( | ||
| this.now() - instance.lastFetchAt < | ||
| GolbatCapabilities.RECHECK_DEBOUNCE_MS | ||
| ) { | ||
| return |
There was a problem hiding this comment.
Allow the unsupported verdict to force a status recheck
When Golbat is upgraded within 30 seconds of the startup or periodic status fetch, Pokestop.getAvailable() receives the new payload without showcase_focus_filter and calls recheck(), but lastFetchAt was just set by the preceding fetch, so this branch returns without requesting the updated status. The availability call consequently throws instead of recovering on the same pass, leaving the previous or empty filter drawer until the next scheduled availability refresh. The unsupported-capability path needs a forced retry or debounce logic that still permits this first corrective recheck.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 4e0dbae. Confirmed the scenario: recheck() shared its 30 s floor with the periodic status fetch, so an upgrade landing inside that window left the pass throwing until the next availability refresh. The availability path now calls refresh() (still single-flight, no debounce); it is already throttled by the availability refresh window, so it cannot hammer Golbat. The debounce stays on the hot-path recheck triggered by 4xx scanner responses. The test for this path now drives the real registry with a fake transport, with the upgrade landing 10 s after discovery.
The unsupported showcase-focus verdict in Pokestop.getAvailable called the debounced recheck(), which shares its 30 s floor with the periodic status fetch. A Golbat upgrade landing inside that window left the availability pass throwing until the next one. Use refresh() there: it is still single-flight, and the path is already throttled by the availability refresh window. The debounce stays on the hot-path recheck triggered by 4xx scanner responses. The replaced test now drives the real registry with a fake transport so it exercises the debounce instead of a mocked method. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016611GTrQ2W8WcznKrLQnMv
|
Focused tests and changed-file lint/format checks passed, but targeted reproductions confirmed credential-isolation, timeout-handling, retry-throttling, and endpoint-prefix defects in the new capability discovery paths. Full review comments:
|
Scope
Adds a Golbat capability registry so ReactMap can learn what each configured Golbat instance supports from
GET /api/status, with showcase focus as the first consumer. This lets Golbat drop the deprecated per-responseshowcase_focus_filterflag once builds without afiltersblock are gone (Golbat PR #404 adds the block).server/src/services/GolbatCapabilities.js(new). Reads/api/statusfor every configured endpoint using the existingX-Golbat-Secret/ basic-auth headers and theapi.fetchTimeoutMstimeout. Stores{ features, limits, filters }per instance, keyed by the endpoint base url (mem). A 404 or a non-JSON body records a legacy result (older Golbat,filters: null); any other failure (401, 5xx, network error, timeout) keeps the last good result. Refreshes every 5 minutes on an unreferenced timer, single-flight per instance.recheck(mem)re-reads immediately, at most once per 30 s per instance. Consumer API:get(mem),advertisesFilters(mem),supportsFilter(mem, key). Logs each instance's advertised filters/features/limits at info only when they change.DbManager.getDbContextawaits discovery alongside the schema checks, so the registry is populated before the first availability refresh at startup and on config reload.evalScannerQuerytriggers a recheck of the calling instance when Golbat answers 400 or 422 (the first sign of a downgrade). The header builder it shared with the new service moves toserver/src/utils/scannerHeaders.js.Pokestop.getAvailabledecides showcase focus support fromsupportsFilter(mem, 'showcase_focus')when the instance advertises filters, and falls back to the legacyshowcase_focus_filterresponse key only when the status route reported no filters block. An unsupported verdict re-reads the status (single-flightrefresh, not the debouncedrecheck, since this path is already throttled by the availability refresh window) before throwing, so an upgrade that drops the legacy flag recovers on the same pass even seconds after a periodic status fetch. The hard error (no SQL masquerade) is unchanged.GolbatStatus/GolbatInstanceadded topackages/types/lib/server.d.ts;showcase_focus_filtermarked@deprecatedand optional there and in the mapper's JSDoc.golbatlogger tag added.Out of scope, as briefed: no change to which filters ReactMap sends, no new consumer beyond showcase focus, no Golbat changes.
limitsare stored for a later clamp consumer but nothing reads them yet.Testing
yarn test: 103 server tests pass (14 new for the service, 2 new for the evaluator fast path, showcase availability tests rewritten per Golbat generation).yarn lintclean on all touched files; Prettier clean;tsc --noEmit -p jsconfig.jsonreports no new errors (the 21 pre-existing errors inPokestop.jsare unchanged).config/local.json). Suggested manual checks on a dev stack: start ReactMap against a PR Restrict areas without auth #404 Golbat and confirm the[GOLBAT]info line listsshowcase_focus; point it at a current-main Golbat and confirm the line saysno filters block (older Golbat)while showcase availability still loads via the legacy flag; stop Golbat and confirm a[GOLBAT] … keeping the last known capabilitieswarning without the drawer changing.🤖 Generated with Claude Code
https://claude.ai/code/session_016611GTrQ2W8WcznKrLQnMv