Skip to content

feat(BA-5947): expose model_cards connection on VFolderGQL#11480

Open
fregataa wants to merge 11 commits intomainfrom
BA-5947-vfolder-model-cards-resolver
Open

feat(BA-5947): expose model_cards connection on VFolderGQL#11480
fregataa wants to merge 11 commits intomainfrom
BA-5947-vfolder-model-cards-resolver

Conversation

@fregataa
Copy link
Copy Markdown
Member

@fregataa fregataa commented May 4, 2026

Summary

  • Add a reverse-direction modelCards connection on VFolderGQL (a vfolder may back multiple cards since the model card unique constraint is on (name, domain, project), not on vfolder).
  • The nested resolver accepts the full Relay argument set (filter, orderBy, before/after, first/last, limit/offset) and is nullable per BA-5956.
  • Scoping is delegated to the parent VFolder resolver via a new typed VFolderModelCardSearchScope; the resolver calls adapters.model_card.search_by_vfolder(scope, input) (sibling to the existing admin_search / project_search).

Test plan

  • pants check / pants lint clean
  • Schema dump regenerated; modelCards field nullable, no leakage of vfolder_id into the public ModelCardV2Filter

Resolves BA-5947

Copilot AI review requested due to automatic review settings May 4, 2026 10:53
@github-actions github-actions Bot added size:XL 500~ LoC comp:manager Related to Manager component labels May 4, 2026
@github-actions github-actions Bot added the area:docs Documentations label May 4, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a reverse GraphQL relationship from VFolderGQL to model cards, so vfolder queries can surface the ModelCardV2Connection for cards backed by that folder. This extends the existing model-card/vfolder linkage through the repository, service, adapter, DataLoader, and GraphQL layers.

Changes:

  • Added batch_load_by_vfolder_ids plumbing across model-card repository/service/action/adapter layers.
  • Added model_cards on VFolderGQL, backed by a new model_cards_by_vfolder_loader.
  • Added repository-level tests for grouping model cards by vfolder and preserving input order.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/unit/manager/repositories/model_card/test_batch_load_by_vfolder_ids.py Adds repository tests for vfolder-grouped model-card batch loading.
src/ai/backend/manager/services/model_card/service.py Adds service method delegating batch loads by vfolder IDs.
src/ai/backend/manager/services/model_card/processors.py Registers the new model-card batch-load action processor.
src/ai/backend/manager/services/model_card/actions/batch_load_by_vfolder_ids.py Defines the new action/result pair for vfolder-based model-card loading.
src/ai/backend/manager/repositories/model_card/repository.py Exposes repository batch loading by vfolder IDs.
src/ai/backend/manager/repositories/model_card/db_source/db_source.py Implements the DB query that groups model cards by backing vfolder.
src/ai/backend/manager/api/gql/vfolder_v2/types/node.py Adds the new model_cards GraphQL field on VFolderGQL.
src/ai/backend/manager/api/gql/data_loader/data_loaders.py Adds a DataLoader for batched model-card lookup by vfolder ID.
src/ai/backend/manager/api/adapters/model_card/adapter.py Adds adapter support for the new batched vfolder lookup flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ai/backend/manager/api/gql/vfolder_v2/types/node.py Outdated
Comment thread src/ai/backend/manager/repositories/model_card/db_source/db_source.py Outdated
Comment thread tests/unit/manager/repositories/model_card/test_batch_load_by_vfolder_ids.py Outdated
Comment thread src/ai/backend/manager/api/gql/vfolder_v2/types/node.py Outdated
fregataa added a commit that referenced this pull request May 4, 2026
@github-actions github-actions Bot added size:L 100~500 LoC and removed size:XL 500~ LoC labels May 4, 2026
@fregataa fregataa requested a review from a team May 4, 2026 12:53
Comment thread src/ai/backend/manager/api/gql/vfolder_v2/types/node.py Outdated
fregataa and others added 10 commits May 8, 2026 23:24
Mirror ModelCardV2.vfolder with a reverse-direction model_cards field on
VFolderGQL, returning a ModelCardV2Connection. A vfolder may back multiple
model cards (the (name, domain, project) unique constraint does not extend
to vfolder), so the field is plural. Resolved via a new DataLoader keyed by
VFolderUUID to avoid N+1 fetches.

The full layered wiring was added: ModelCardDBSource.batch_load_by_vfolder_ids,
ModelCardRepository, BatchLoadModelCardsByVFolderIdsAction/Result,
ModelCardService.batch_load_by_vfolder_ids, the processor, and the adapter
method. No RBAC filtering happens at this loader -- visibility is gated by
the parent vfolder, matching the existing forward-direction resolver.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: octodog <mu001@lablup.com>
Add ``ModelCardRow.id`` as a deterministic secondary key on the
batch_load_by_vfolder_ids query so siblings sharing a ``created_at``
(possible when ``bulk_upsert_scan`` writes them in one statement) keep
a stable per-vfolder order across requests, matching the tiebreaker on
the existing model-card pagination spec.

Also clarify the rationale for the test's brief ``asyncio.sleep`` so
future readers don't mistake the prior comment about second-precision
timestamps for fact -- Postgres ``now()`` is microsecond-precise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… deterministic test

- Trim the GQL field description down to the one-line summary; the rest
  belonged in the implementation rather than the public schema.
- Rename the ``ModelCardProcessors`` attribute to
  ``batch_load_model_cards_by_vfolder_ids`` to match the entity-prefixed
  convention used by the vfolder processor.
- Drop the ``asyncio.sleep`` in the repository test and pin
  ``created_at`` explicitly so the most-recent-first assertion is
  deterministic without relying on wall-clock timing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: octodog <mu001@lablup.com>
…ction

Replace the bespoke batch_load_by_vfolder_ids action/service/processor/repo
chain with the same shape used by deployment.batch_load_revisions_by_ids:
the adapter constructs a ``BatchQuerier`` (``NoPagination`` +
``ModelCardConditions.by_vfolder_ids`` + most-recent/id ordering) and
delegates to the existing ``SearchModelCardsAction``. The grouping by
``vfolder_id`` happens once in the adapter where the GQL connection is
also assembled.

This removes the standalone batch_load_by_vfolder_ids action file, the
service method, the processor attribute, and the repository/db_source
helpers. The ``test_batch_load_by_vfolder_ids`` repo test is dropped
together with the db_source method it pinned; the search path is
already covered by the broader model_card search tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GraphQL propagates resolver errors up to the nearest nullable ancestor,
so a non-null ``model_cards`` field would null the parent ``VFolder``
on any failure (DB hiccup, RBAC denial, etc.). When the resolver is
called from a vfolder list query, that propagation can wipe out an
entire ``VFolder`` edge for a side-channel lookup that the caller did
not specifically request. Declaring ``ModelCardV2Connection | None``
contains the failure to this field; ``errors`` still carries the
diagnostic and the surrounding ``VFolder`` data survives.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: octodog <mu001@lablup.com>
…r-scoped search

Replaces the DataLoader-backed batch lookup with a per-call adapter
search method `search_in_vfolder(scope, input)`, mirroring the
deployment pattern (`search_revisions(scope=RevisionSearchScope, …)`).
The nested resolver now accepts the full Relay argument set (filter,
order_by, before/after, first/last, limit/offset) and delegates scoping
to a typed `VFolderModelCardSearchScope`, leaving the public
`ModelCardFilter` DTO untouched.
@fregataa fregataa marked this pull request as draft May 8, 2026 15:02
@fregataa fregataa force-pushed the BA-5947-vfolder-model-cards-resolver branch 2 times, most recently from aee1824 to 0cb050e Compare May 8, 2026 16:15
@fregataa fregataa force-pushed the BA-5947-vfolder-model-cards-resolver branch from 0cb050e to 3ee4a31 Compare May 8, 2026 17:13
Adds a thin façade so the VFolder field resolver reads naturally as
`adapters.vfolder.search_model_cards(scope, input)` instead of reaching
into the model_card adapter. The implementation still lives in
`ModelCardAdapter.search_in_vfolder`; VFolderAdapter delegates via a
constructor-injected reference, mirroring how the deployment adapter
exposes `search_revisions` from the parent entity.
@fregataa fregataa force-pushed the BA-5947-vfolder-model-cards-resolver branch from 3ee4a31 to 55ffcbe Compare May 8, 2026 17:37
@fregataa fregataa marked this pull request as ready for review May 8, 2026 17:49
@fregataa fregataa requested a review from a team May 8, 2026 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:docs Documentations comp:manager Related to Manager component size:L 100~500 LoC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants