Skip to content

feat: expose authenticated MCP Global Ask - #270

Open
seonghobae wants to merge 76 commits into
feat/event-lineage-node-keeps-gnb-focus-v2170from
agent/authenticated-mcp-global-ask
Open

feat: expose authenticated MCP Global Ask#270
seonghobae wants to merge 76 commits into
feat/event-lineage-node-keeps-gnb-focus-v2170from
agent/authenticated-mcp-global-ask

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Product result

Adds an authenticated Streamable HTTP MCP resource server so MCP clients can
ask LineageWeave Global Ask without direct SQL access, a second identity store,
or bearer-token forwarding.

Exact stack state

  • Head: e1c31db3387ec051e6327332d373293242b9e5eb
  • Base branch: feat/event-lineage-node-keeps-gnb-focus-v2170
  • Exact base: bcdc4594abe467627c71378adeceb61624d02d67
  • The branch is ready for review; parent work was preserved through ordinary
    merges and no force push or protected-branch bypass was used.

Contract and security boundary

  • MCP exposes bounded, read-only, idempotent global_ask with explicit
    verify_external behavior and no persisted side effect.
  • The shared account/RBAC/ABAC resolver is reused; source metadata is
    authorized before post-scoped body/vision work, and Global Ask SQL applies
    public/corporate scope before body disclosure.
  • Cited media rechecks the live post_read grant immediately before bytes are
    returned.
  • OAuth protected-resource metadata, exact issuer/JWKS/expiry/kid/resource
    audience checks, bounded key rotation, and Host/Origin validation remain in
    force.
  • Keycloak's existing realm uses the idempotent dedicated audience reconciler;
    MCP waits for that reconciler and SearxNG readiness.
  • All model and vision work stays behind contextual-orchestrator with automatic
    capability/model selection; no provider API or model name is selected here.

Review disposition

Current review reports were checked against the exact tree. The previously
reported MCP auth, media indexing, external-verification parsing, source
prompt-boundary, SQL authorization, and Keycloak audience issues are addressed
in the branch or by the current database/compose boundary; no new source fix
was needed in this pass.

Verification

  • Backend: 829 passed, 16 skipped, 3 warnings.
  • Focused MCP/auth/verification/media/ingestion suite: 95 passed.
  • Frontend: 166 passed; lint, production build, and Storybook build passed.
  • git diff --check and CodeGraph sync passed.

Merge gate

Review this exact head. Merge only after an independent formal approval, all
required Checks are terminal-success on this SHA, and no valid unresolved
review thread remains. If a Check fails, fix its root cause, validate locally,
push normally, and re-check the new exact head.

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 296578e6-8f32-4c0a-998d-5cde3d7dda2d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

인증된 MCP Streamable HTTP 서버와 읽기 전용 global_ask 도구를 추가했다. JWT·JWKS·ABAC 검증, 권한 있는 게시글 근거, 자동 오케스트레이션, 선택적 외부 검증, 인용 이미지 반환 및 Compose 배포를 구성했다.

Changes

인증된 MCP Global Ask

Layer / File(s) Summary
설정과 토큰 인증
backend/app/config.py, backend/app/auth.py, backend/app/mcp_auth.py, tests/test_config.py, tests/test_mcp_auth.py
게이트웨이와 MCP 설정을 추가했다. JWKS 구조, JWT kid, issuer, audience, subject, scope 및 계정 권한 검증을 구현했다.
오케스트레이션과 근거 컨텍스트
lineageweave/post_chat.py, lineageweave/image_content.py, lineageweave/post_content_normalization.py, backend/app/post_chat_ingestion.py, tests/test_post_chat_conduct_contract.py, tests/test_image_content.py
Post Ask와 비전 요청에 mode="auto", 구조화 응답, 세션 ID, 메타데이터 및 300초 기본 타임아웃을 적용했다. 게시글 소스에 발생 시각과 lineage 관계를 추가했다.
내부 Global Ask와 미디어
backend/app/global_ask.py, backend/app/global_ask_media.py, tests/test_mcp_global_ask.py, tests/test_mcp_global_ask_media.py, tests/test_mcp_citation_boundary.py
권한 있는 게시글을 검색하고, 제한된 소스·인용·타임라인을 생성한다. 인용된 래스터 이미지를 제한된 MCP 콘텐츠 블록으로 반환한다.
외부 근거 검증
backend/app/global_ask_verification.py, tests/test_global_ask_external_verification.py, tests/test_global_ask_external_verification_contracts.py
Searxng 결과를 공개 HTTP(S) URL로 제한하고 중복 제거한다. contextual-orchestrator의 supported, refuted, insufficient_evidence 판정을 검증한다.
MCP 서버와 배포
backend/app/mcp_server.py, docker-compose.yml, docker/keycloak/realm-export.json, docs/integrations/MCP.md, tests/test_mcp_server.py
OAuth 보호 MCP 서버와 /mcp Streamable HTTP 앱을 추가했다. Host·Origin·DNS rebinding 검사를 적용하고, 별도 Compose 서비스와 Keycloak audience mapper를 구성했다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: 🟠 High · up to 10ace

This PR adds an authenticated MCP path to Global Ask, but private content can still be loaded before authorization, persisted identity configuration can reject valid clients after an audience change, and untrusted source text can weaken prompt isolation; an authorization race remains open as well. These concrete security and availability risks should be fixed before merge, alongside completion of the required exact-head checks.

Sequence Diagram(s)

sequenceDiagram
  participant Client as MCP 클라이언트
  participant MCP as MCP 서버
  participant Keycloak as Keycloak
  participant Database as 게시글 데이터베이스
  participant Orchestrator as contextual-orchestrator

  Client->>MCP: global_ask(question, access token)
  MCP->>Keycloak: JWT audience·scope·subject 검증
  Keycloak-->>MCP: 인증된 주체 반환
  MCP->>Database: 권한 있는 게시글과 lineage 검색
  Database-->>MCP: 소스 게시글과 타임라인 반환
  MCP->>Orchestrator: JSON Schema 기반 답변 요청
  Orchestrator-->>MCP: 답변과 인용 반환
  MCP-->>Client: 구조화 결과와 콘텐츠 블록 반환
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 인증된 MCP Global Ask 노출이라는 PR의 주요 변경 사항을 간결하고 명확하게 설명합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/authenticated-mcp-global-ask

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@seonghobae
seonghobae changed the base branch from main to feat/event-lineage-node-keeps-gnb-focus-v2170 August 20, 2026 21:23
@seonghobae

Copy link
Copy Markdown
Contributor Author

@opencode-agent Please review exact head b34050dca8d9756d628e86c0a1506fc5e1c31e5f, including the shared OIDC/JWKS boundary, metadata-first/body-second ABAC loading, MCP media reauthorization, structured orchestrator contract, and the stack integration with PR #264. Treat predecessor-head evidence as non-transferable.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Review exact current HEAD eb83c9c. The branch was advanced while preserving concurrent restack commits; current base feat/event-lineage-node-keeps-gnb-focus-v2170 is an ancestor of this head. Local locked dev+backend full suite: 823 passed, 16 skipped, 3 warnings. The uv.lock conflict with main was resolved by retaining the branch 2.13.0 metadata.

Hosted Checks are queued for this exact head. Please re-run/review this SHA and publish the independent formal approval required by the protected ruleset; no merge claim until terminal Checks, required approvals, exact-head last-push approval, and post-merge SHA evidence.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Fresh exact-head evidence for eb83c9c: frontend lint passed; frontend tests 15 files / 155 tests passed; production build passed; Storybook build passed (only the existing large-chunk warning). Backend remained 823 passed, 16 skipped, 3 warnings. Hosted required Checks are still queued after the branch update.

Please bind any formal review to this exact SHA and complete the protected merge gate only after terminal hosted results and independent approvals.

@seonghobae
seonghobae marked this pull request as ready for review August 20, 2026 23:15
devin-ai-integration[bot]

This comment was marked as resolved.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Review exact current HEAD 1881a3c (base 3ed21fe):

  • Rechecked the current authenticated MCP Global Ask tree after its remote import normalization. The MCP verifier keeps the exact resource audience, Global Ask resolves the authenticated subject to the account before source retrieval, and external verification remains explicit and separately reported.
  • Focused verification: uv run --locked --extra dev --extra backend python -m pytest -q tests/test_mcp_server.py tests/test_mcp_global_ask.py tests/test_mcp_citation_boundary.py tests/test_mcp_external_opt_in.py tests/test_mcp_external_optin.py tests/test_mcp_auth.py → 47 passed.
  • Hosted Checks are queued for this exact HEAD and formal independent approval is absent; protected merge remains blocked.

…b-focus-v2170' into agent/authenticated-mcp-global-ask

# Conflicts:
#	CHANGELOG.md
…b-focus-v2170' into agent/authenticated-mcp-global-ask
…b-focus-v2170' into agent/authenticated-mcp-global-ask
seonghobae added a commit that referenced this pull request Aug 21, 2026
* feat: queue post-content analysis durably

* fix(import): allow repeated source lookup keys

* fix(docs): assign post-content ADR a unique number

* feat: add keyverse-bound mcp api key management

* revert: keep MCP key management out of buyer root stack

The prior commit added a second local MCP credential authority to #258 even though authenticated MCP Global Ask is owned by draft PR #270. Restore the exact pre-injection Buyer tree without rewriting history; the isolated commit remains available for separate evaluation against #270's OAuth resource-server contract.

* security: document safe composed SQL

* fix: preserve OIDC post deep links

* ci: verify audited safe-SQL suppressions

* ci: harden audited safe-SQL repair anchors

* fix(ci): remove self-modifying SQL repair workflow

* test(security): reject dynamic asyncpg statement construction

* fix: render resolved post structure for ordinary paragraphs

* fix: hide source offsets from image accessibility labels

* fix: requeue incomplete post embeddings

* fix: align static SQL contract with safe composition

* ci: repair PR 258 static SQL review findings

* ci: repair PR 258 one-shot template

* fix: pass embedding model to backend

* fix(ci): remove self-modifying PR 258 repair workflow

* fix(ci): remove PR 258 workflow template

* fix(security): bind customer-hint SQL to a static statement

* fix(security): precompile demo-scope SQL statements

* fix(security): precompile relationship-network SQL

* fix(security): precompile Keyman backfill selectors

* fix(security): precompile summary backfill selectors

* test: apply image-region embedding migration in API fixture

* fix(security): precompile content backfill selectors

* fix(security): move synthetic cleanup identifiers into PostgreSQL

* test(security): require static reviewed asyncpg statements

* fix(backfill): preserve process-unit semantic hint name

* fix: wire provider embeddings through orchestrator

* fix: retain embedding provider URL during startup

* fix: keep orchestrator provider URL for embedding startup

* chore: stage exact SQL review repair payload

* fix(security): keep relationship-network SQL literal

* fix(security): keep demo-scope SQL literal

* fix(security): keep customer-hint SQL literal

* fix(security): keep Keyman selector SQL literal

* fix(security): use one literal summary selector

* fix(security): use one literal content selector

* fix: requeue incomplete post content jobs

* fix(security): keep synthetic cleanup SQL literal

* test(security): require literal reviewed SQL statements

* fix: keep ADR numbers unique and remove repair artifact

* feat: queue real post content backfill through valkey

* chore: configure project test import path

* fix(security): keep queue backfill SQL literal

* test(security): cover queue backfill SQL boundary

* perf: parallelize visual region evidence

* fix: require a majority of tokens for relation corroboration

corroborating_evidence_url treated a single distinctive name token
as enough corroboration for an organization's real-world footprint.
An invented name containing an ordinary dictionary word (e.g.
"Fictitious", "Nonexistent") could match unrelated search results
on that one word alone, flipping a genuinely uncorroborated relation
to corroborated. Now requires a majority of a multi-token name's
tokens to co-occur in the same result; single-token names fall back
to that one token since there is no majority to require.

Also renumbers migrations/0012_role_responsibility_agent_type.sql
to 0060 -- it collided with the already-mainlined
0012_report_leftover_pair.sql -- and updates every reference plus
the migrate.sh replay allowlist.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

* test(frontend): match embedded image accessibility label

* docs: ground orchestration policy in primary sources

* style: tokenize repeated colors and add dark-mode badge variants

App.css hardcoded ~13 color sites (lineage-link accent colors,
actor-type badges, verification-status badges, a subtle border) that
duplicated the same values across the file with zero dark-mode
coverage -- the pastel badge backgrounds would have stayed light in
dark mode, clashing against the dark chrome. Promotes them to
semantic tokens in styles/tokens.css with light and dark variants,
following the file's existing --color-accent-* pattern, and points
every App.css occurrence at the new custom properties.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

* docs(adr): record buyer surface Figma file

* docs+test: ADR and regression test for badge/accent tokens

Adds ADR 0099 documenting the design-token pass (Figma File ID
1Su3lDRmiZdcUs47t1QwIX, reusing ADR 0002's already-cleared boundary)
and a CHANGELOG.d fragment. Adds frontend/src/styles/tokens.test.ts
so a future edit can't silently drop the dark-mode half of a badge
token or reintroduce the retired inline hex colors.

Also drops a duplicate 0060_* case arm in migrate.sh's replay
allowlist left over from a concurrent edit.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

* fix: keep 0060 migration allowlist entry as its own case arm

My earlier cleanup merged 0060_* into the 0012-0050 case arm, but
test_migration_replay_window_includes_post_content_queue asserts the
exact substring "0050_*)" is present -- merging broke that literal
match. Restores the separate appended arm, matching the pattern
already used for 0051_*/0052_*.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

* fix(security): audit every reviewed SQL composition site

* fix: align embedded image accessibility assertion

* fix: recover post content queue leases

* fix: allow slow structured post adjudication

* fix: bound post content queue retries

* fix: align integration fixtures with current contracts

* feat: persist requester and processor evidence

* docs: record product gap baseline

* fix: keep summaries available when enrichment times out

* docs: align product gap evidence with current head

* fix: fence stale post-content worker leases

* test: apply action migration to projection fixtures

* fix: stop failed evidence panels from loading forever

* docs: record bounded summary refresh evidence

* fix: document audited asyncpg queries

* docs: track latest protected-head audit

* docs: record entity-resolution PR correction

* fix: preserve semantic source unit boundaries

* fix: preserve oidc deep links across callback storage

* fix: render buyer-facing image evidence

* fix: label unavailable image evidence

* docs: avoid oidc adr number collision

* docs: avoid buyer image adr number collision

* fix: bind summary actions to source-grounded projects

* test: cover project-bound summary action round trip

* docs: record buyer gap checkpoint evidence

* docs: align image evidence ADR heading

* docs: align OIDC ADR heading

* fix: preserve legacy action evidence delimiters

* docs: refresh buyer gap audit checkpoint

* docs: record current project action head

* feat: bind summary events to source-grounded projects

* docs: record full checkpoint verification

* fix(summary): normalize project keys before persistence

* docs: refresh exact-head buyer gap audit

* test(summary): cover project key sentinel normalization

* test(image): cover source placement and OCR rendering

* fix: preserve stale summary buyer continuity

* fix: keep post content recovery alive

* test(summary): cover stale continuity and retry

* feat: add explicit post content retry

* test(queue): cover explicit retry rejection

* docs(queue): complete retry command docstrings

* fix(ontology): align person mention direction with KG triples

* docs: record audited safe SQL gate

* fix: reconcile backfill content with job ledger

* fix(ui): preserve indentation after mixed content

* docs: record post content recovery evidence

* docs(ui): clarify indentation matching boundary

* test(ui): cover missing source unit fallback

* fix: serialize per-post vision region analysis

* fix(ui): preserve adjacent table boundaries

* fix: preserve honest image evidence rendering

* fix: separate source whitespace from explicit structure

* docs: record source indentation buyer gap

* fix: retain partial image regions

* docs: record partial image region gap

* test: cover partial parent vision failure

* feat: enrich semantic hints from source catalogs

* fix: reject non-decomposed vision regions

* docs: refresh protected gate baseline

* docs: record corrected image region evidence

* fix: trim source catalog lookup codes

* docs: record catalog hint boundary

* docs: record exact-head validation evidence

* docs: record live browser acceptance

* docs: refresh live gate topology

* fix: reject unbounded visual locator regions

* docs: refresh exact-head product gap audit

* test: cover visual region fallback branches

* docs: refresh exact-head product gap audit

* test: cover visual region fallback branches

* docs: record current audit head

* docs: repair stacked audit traceability

* fix: fall back from malformed visual locator output

* docs: refresh stacked PR exact heads

* docs: record audit refresh head

* docs: refresh visual locator exact-head evidence

* style: normalize merged branch whitespace

* docs: refresh current visual stack state

* docs: record visual stack audit head

* docs: align visual stack gate states

* fix: preserve semantic footnote structure

* docs: record footnote structure checkpoint

* fix: classify OOXML footnote containers

* fix: distinguish footnote citations from definitions

* docs: record footnote citation guard

* docs: record fresh runtime aggregate evidence

* docs: align runtime evidence head

* docs: record embedding provenance guard

* docs: align stacked audit head

* test: keep invalid locator fallback coordinate-free

* docs: keep PR 320 status under its checkpoint

* docs: refresh PR 324 exact-head evidence

* fix: refresh content after summary ingestion

* fix: bound OIDC return state parsing

* fix: restrict synthetic cleanup to demo scopes

* test: cover empty synthetic cleanup

* fix: validate buyer image sources at render boundary

* docs: record current exact-head gap checkpoint

* docs: retain current buyer stack roots

* fix: safely handle malformed region locator output

* fix: expose unexpected content channel defects

* fix: expose recoverable content batch failures

* fix: safely handle malformed region locator output

* docs: record current exact-head review gates

* docs: align orchestrator runtime pin

* docs: refresh current queue roots

* docs: record buyer-stack restack

* docs: record MCP key boundary closure

* style: use deferred region result annotation

* feat: enforce Korean UI standards on top of latest PR stack

- Re-apply UI·UX Standard Guide Ver.3.0 layout (app-shell, login-card, footer)
- Update i18n translation dictionary to match standard Korean vocabulary (조회, 티켓 작성, 로그인 등)
- Preserve existing i18n localization hooks instead of hardcoding
- Preserve all stacked PR functionality (BuyerNav, LLM extraction fixes, backend parsing)

* feat: parameterize brand name for future admin configuration

- Replaced hardcoded 'LineageWeave' and 'BRAND' with  state.
- Prepared for admin mode integration where tenant/brand name can be dynamically fetched.

* feat: add admin screen for tenant configuration

- Added Admin destination to BuyerNav
- Created AdminPanel for configuring brandName dynamically
- Wired up AdminPanel rendering in App.tsx
- Added i18n support for new admin terms

* feat: backend API and DB connection for admin tenant settings

- Created migration 0103_tenant_settings for persistent brand name storage
- Added GET/PATCH /api/settings endpoints in backend main.py
- Wired App.tsx and AdminPanel.tsx to fetch and update via actual API

* fix: revert bad chunking sed from uiux restack

* fix: rename duplicate ADR 0117 to 0118

* docs: correct UI UX ADR number

* feat: close extraction gaps (5W1H, events, Keymen) and update baseline

---------

Co-authored-by: Claude Sonnet 5 <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@seonghobae

Copy link
Copy Markdown
Contributor Author

@opencode-agent @devin-ai-integration Please review exact current head e1c31db against base bcdc459. Current MCP/auth/ABAC/Keycloak review findings were verified against this tree; local full and focused suites are green.

…b-focus-v2170' into HEAD

# Conflicts:
#	backend/app/auth.py
#	lineageweave/post_content_normalization.py
@seonghobae

Copy link
Copy Markdown
Contributor Author

Restacked onto current Event Lineage head 39f2126 with normal merge commit 515bb0b.

Local verification on the pushed tree: backend 871 passed, 17 skipped; frontend 177 passed; lint, build, Storybook build, compileall, actionlint, and diff checks passed. Provider diagnostics remain fail-closed, JWKS selection remains exact, and partial visual-region evidence retains parent context. Awaiting independent review and hosted Checks on the current head.

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 1 new potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment on lines 255 to 269
if regions:
region_results.extend(
_describe_image_region(
region_index,
chunk.image_data,
chunk.label,
region,
vision_client,
with ThreadPoolExecutor(max_workers=min(8, len(regions))) as executor:
region_results.extend(
executor.map(
_describe_image_region_in_context,
(copy_context() for _ in regions),
range(len(regions)),
repeat(chunk.image_data),
repeat(chunk.label),
regions,
repeat(vision_client),
repeat(session_id),
repeat(metadata),
)
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Vision image analysis floods the gateway with nested parallel calls

When a post has several embedded images that each decompose into regions, the image-analysis step runs images and their regions in two stacked thread pools (ThreadPoolExecutor at post_content_normalization.py inside per-image tasks launched from another ThreadPoolExecutor at post_content_normalization.py), so up to 64 provider calls fire at once for one post.

Nested pools contradict the adjacent serialization decision

The inline ponytail note at post_content_normalization.py records that per-post VISION calls were deliberately serialized because "nested image/region pools overwhelmed the gateway and turned valid region evidence into failures" and that bounded concurrency should be reintroduced only after provider capacity is measured. This PR replaces both the previously sequential per-image loop (now the outer pool at line 370) and the previously sequential per-region generator (now the inner pool at line 256) with ThreadPoolExecutors, each max_workers=min(8, ...). Because each outer per-image worker opens its own inner region pool, effective concurrency reaches 8*8 = 64 simultaneous describe/locate_regions calls per post, exactly the nesting the note warns produced region-evidence failures. Region and chunk failures are swallowed and downgraded to "failed"/"content unavailable", so overload silently degrades extracted image evidence rather than erroring.

Prompt for agents
The image-analysis path in lineageweave/post_content_normalization.py reintroduces concurrency that the adjacent ponytail comment (lines 252-254) explicitly forbids until provider capacity is measured. normalize_post_body now runs image chunks in a ThreadPoolExecutor (around line 370), and _describe_image_chunk runs each chunk's regions in a second ThreadPoolExecutor (around line 256). Because the region pool is nested inside the per-image pool, worst-case concurrency is 8*8=64 concurrent gateway calls per post, which the comment says overwhelmed the gateway and turned valid region evidence into failures. Decide on a single bounded concurrency level: either keep the two loops serial (as documented) or cap total in-flight provider calls (e.g. a single shared bounded executor / semaphore across both image and region work) so nesting cannot multiply the worker counts. Also update or remove the now-inaccurate ponytail comment to reflect the chosen design.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@seonghobae
seonghobae enabled auto-merge (squash) August 21, 2026 05:49
Sign up for free to 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.

2 participants