Repository navigation
fix: shared advisory-lock session and seven open bugs (#2169) - #2240
Merged
Merged
Conversation
Changes the advisory locks every background loop takes (new internal/advisorylock), /readyz, the database pool floor, the storage forecast, manage_asset update and patch, the call catalog's outcome filter, full-text matching on seven search surfaces (migration 000209), the api/graphql operation ranking, the Google API refusal hint, the api and graphql connection editors, and the deployment guide's image pins; eight tickets: 1. #2169 a replica starved its own pool: each advisory-locked loop held a pooled connection for its whole pass while the pass drew from the same pool. Every try-lock held across work (catalog scan, maps, storage and webhook alerts, retention, capacity, call catalog and audit sweeps, thumbnail sweeps, catalog import, resource reclassification, connlimit slots, the connoauth refresher) now goes on one session per process; a key the process holds is refused, a session whose connection broke is ended, and .semgrep/go-advisory-lock.yml refuses a try-lock taken elsewhere. database.max_open_conns below 4 is refused at startup (dbobs.CheckPoolSize), and /readyz answers 503 database_pool_starved after 30s with no connection handed out. 2. #2203 storage forecast: a store's first day is left out of every fit, the 30-day rate waits for two weeks of history, and a replica that finds a sample within the interval takes none. 3. #2234 manage_asset update and patch grant newly declared references before the new version exists (Declarer.Widen), drop the ones no longer declared once the content is stored, and put them back when the content write fails. 4. #2231 the outcome filter on /api/v1/admin/calls and /api/v1/portal/calls: a count states the outcome as conditions, asks the satisfied rule only of calls an artifact names (citedSet) and reads supersession from one ordered pass over reads; a satisfied page joins the cited set; both run with JIT off. Migration 000208 adds idx_call_records_supersession. On the dev catalog (111,919 records) every outcome answers in 0.32s or less, from 3.6 to 4.7s. 5. #2230 a name is matched by its words: PostgreSQL read "acceptance-1627-1792487495133911000" as "acceptance" and the signed numbers -1627 and -1792487495133911000, so a search by its words never matched. Migration 000209 reads -, _, ., / and : as word breaks beside the text as written in the resource, asset, collection, prompt, knowledge page, script and catalog dataset search functions, the memory index and the folder search. An api or graphql operation not yet embedded is blended at a cosine of zero, as the SQL rankers blend a row the vector arm cannot see. 6. #2224 the deployment guide's compose example pins pgvector/pgvector:pg16, Keycloak 26.7.5 and Trino 453 to digests their registries serve, and make docs-images-check (scripts/docs-image-digests.sh, run in the E2E Nightly) resolves every digest the docs pin. 7. #2237 googlekey.APIHint reads a Google API refusal by its status and details[].reason: SERVICE_DISABLED, ACCESS_TOKEN_SCOPE_INSUFFICIENT, and any other 401 or 403 in Google's shape; no product's message text. 8. #2236 the api and graphql connection editors set oauth_token_lifetime as "Token lifetime" under the OAuth block. Also: certifi 2026.10.19 in docs/requirements.txt (osv); the import ratchet gains the internal/advisorylock edges; the asset references built-in page, docs/server storage, configuration, observability, deployment and api-gateway, docs/memory/overview, docs/portal/admin-connections, CLAUDE.md and llms-full.txt. Closes #2169 Closes #2203 Closes #2234 Closes #2231 Closes #2230 Closes #2224 Closes #2237 Closes #2236
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2240 +/- ##
==========================================
+ Coverage 94.80% 94.82% +0.02%
==========================================
Files 1376 1378 +2
Lines 111500 111643 +143
==========================================
+ Hits 105705 105871 +166
+ Misses 5778 5755 -23
Partials 17 17 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Changes the advisory locks every background loop takes (new
internal/advisorylock),/readyz, the database pool floor, the storage forecast,manage_assetupdateandpatch, the call catalog's outcome filter (GET /api/v1/admin/calls,GET /api/v1/portal/calls), full-text matching on seven search surfaces and memory (migration 000209), API and GraphQL operation ranking (internal/opranking), the Google API refusal hint onapi_invoke_endpoint, the api and graphql connection editors, and the deployment guide's image pins. Eight tickets:max_open_conns: 5, four loops held four connections and nothing finished, while/readyzstayed 200.internal/advisorylock): the catalog scan, maps, storage and webhook alerts, retention, the capacity listing, the call catalog and audit sweeps, thumbnail sweeps, catalog import, resource reclassification, connlimit slots and the connoauth refresher. However many locks a replica holds, they pin one connection, which goes back to the pool with the last lock. The locked passes run on the pool..semgrep/go-advisory-lock.ymlrefuses apg_try_advisory_locktaken anywhere else. connoauth's blocking per-callStore.Lockstays on a connection of its own, since a lock that waits cannot share a session.database.max_open_connsbelow 4 is refused at startup, naming the minimum (dbobs.CheckPoolSize)./readyzanswers 503database_pool_starvedwhen every connection of the pool has been in use, with none handed out within 500ms, for 30 seconds. A database that is down opens no connections and does not trip it.manage_assetupdateandpatchrecord the newly declared references beside the asset's existing ones before the new version exists (Declarer.Widen), apply the exact declared set once the content is stored, and put the references back when the content write fails. A kept reference keeps its token.citedSet, joined by hash), and reads supersession from one pass over the reads in (created_at, event_id) order;idx_call_records_supersession.On the dev catalog (111,919 records) every outcome answers in 0.32s or less, from 3.6 to 4.7s.
acceptance-1627-1792487495133911000asaccept,-1627and-1792487495133911000, so a search foracceptance 1627 1792487495133911000never matched the file lexically, andq3-2024-report.csvwas one token.-,_,.,/and:as word breaks, beside the text as written, in the names, titles, paths, file names, tags and categories of the resource, asset, collection, prompt, knowledge page, script and catalog dataset search functions, in the memory content index and in the folder search, and rebuilds those indexes.internal/opranking(API and GraphQL operations), where an unembedded match scored 0.4 and lost to any near neighbour above 0.67; it is now blended at a cosine of zero, as every SQL ranker blends a row the vector arm cannot see.pgvector/pgvector:pg16(the platform's migrations create the vector extension, whichpostgres:16-alpinelacks), Keycloak 26.7.5 with itsKC_BOOTSTRAP_ADMIN_*variables, and Trino 453, each to the digest its registry serves.make docs-images-check(scripts/docs-image-digests.sh) resolves every image the docs pin to a digest and runs in the E2E Nightly, where network is available; it refuses all three of the old digests.googlekey.APIHintchooses the hint fromerror.statusanderror.details[].reason:SERVICE_DISABLEDenables the API,ACCESS_TOKEN_SCOPE_INSUFFICIENTadds the scope tooauth_scope, any other 401 or 403 in Google's error shape grants the service account access inside the product. No code, test or doc names a product's message text; the ticket's existing test sample was one, so the 401 samples carry other messages.oauth_token_lifetime; an empty field stores nothing and the 15-minute default applies; a negative value is refused with the server's message.Also:
certifi2026.10.19 indocs/requirements.txt(the osv gate flagged 2026.6.17); the import ratchet gains theinternal/advisorylockedges andpkg/audit/postgres -> internal/logsan.Upgrading
call_records. Each runs once, in the migration, and takes time in proportion to those tables.database.max_open_connsof 1 to 3 is refused at startup.Type of Change
Related Issues
Closes #2169
Closes #2203
Closes #2234
Closes #2231
Closes #2230
Closes #2224
Closes #2237
Closes #2236
Filed from this work: #2239 (
make preverifyrunsmigrate-checkwhen a migration changes).Readers of this state
/readyzgains the 503 statusdatabase_pool_starved. Read by readiness probes; no portal page reads it.GET /api/v1/admin/storage:rate_7d_min_history_hoursandrate_30d_min_history_hoursnow count a store's first day (48 and 360 when its whole history is kept, 24 and 336 otherwise), and a 30-day rate appears after two weeks. The Storage page reads them unchanged ("Not enough history, x of y").GET /api/v1/admin/callsand/api/v1/portal/callsreturn the same shape; only their speed changes.api_invoke_endpoint'shinton a Google service-account connection gains the scope step and now answers every 401/403 in Google's shape.oauth_token_lifetimeis now set from the api and graphql editors (ApiGatewayAuthFields); the MSW mock'sacme-billing-apicarries it.internal/apidocs/swagger.jsonis unchanged.Testing
Acceptance through the real surface on the local dev stack (two replicas behind the proxy), per ticket after the last change to each; every criterion passed: 2169 (2/2), 2203 (2/2), 2231 (1/1), 2230 (2/2), 2234 (2/2), 2236 (1/1, api and graphql), 2237 (1/1, against the real Google Sheets API). Transcripts are in
build/<n>/acceptance.md;make acceptance-checkconfirms every changed acceptance file's criteria passed in their recorded run.build/2224/docs-images-check.txt.Real-Postgres:
acceptance-1627-…file is the first hit among 30 embedded look-alikes, hybrid and lexical.make migrate-checkon pg16 and pg17, and the SQL statement gate.UI:
ApiGatewayAuthFieldstests, theconnections-oauthPlaywright spec against MSW, and light and dark screenshots (admin-admin-connection-token-lifetime).make verifypassed: the full Go race and coverage run (total 94.0%, patch 96.1%), the schedule lane, the real-database lane, the full vitest suite (3,236) and Playwright (296).One early run of
TestRealDB_LockedPassesFinishOnASmallPoolfailed and its output was not captured; every run since, including 100 runs of the advisorylock RealDB tests at-cpu=1,2, passed.Ran
make testlocallyTested manually
Added new tests for changes (if applicable)
Checklist
make lint)