Skip to content

feat(BA-6553): add app_config_fragments repository layer#12307

Merged
fregataa merged 16 commits into
mainfrom
feat/BA-6553-app-config-fragments-repository
Jun 23, 2026
Merged

feat(BA-6553): add app_config_fragments repository layer#12307
fregataa merged 16 commits into
mainfrom
feat/BA-6553-app-config-fragments-repository

Conversation

@jopemachine

@jopemachine jopemachine commented Jun 18, 2026

Copy link
Copy Markdown
Member

📚 Stacked PRs

Part of the AppConfigFragment / AppConfig stack under BEP-1052 (epic BA-5781). Merge in order:

  1. feat(BA-6552): add app_config_fragments DB model and Alembic migration #12306feat(BA-6552): app_config_fragments DB model and Alembic migration
  2. 👉 feat(BA-6553): add app_config_fragments repository layer #12307feat(BA-6553): repository layer ← you are here
  3. feat(BA-6554): add app_config_fragment service layer #12358feat(BA-6554): service layer (admin/self write paths, allow-list write-gate)
  4. feat(BA-6555): add app_config service layer #12359feat(BA-6555): merge engine (deep-merge across applicable fragments)

Summary

  • Add AppConfigFragmentRepository: create / get_by_id / update / purge / admin_search / scoped_search, over a dedicated AppConfigFragmentDBSource + DBOpsProvider.
  • Rank assignment: create assigns the next rank within a config_name race-free via create_with_next_value (locking the parent app_config_definitions row; RANK_GAP=100 leaves room to re-order). update may set rank explicitly for admin re-ordering, matching BEP-1052.
  • Search: admin_search (superadmin/internal, unscoped) and scoped_search (restricted to ConfigNameSearchScope, whose existence check rejects an unregistered config_name).
  • Query conditions/orders (config_name, scope_type, scope_id, created_at/updated_at, id-cursor) and the AppConfigFragmentNotFound error.
  • Real-DB with_tables tests cover create/get, update (+missing), purge (+missing), search/pagination, scope_type/scope_id filters, rank ordering, the unique (config_name, scope_type, scope_id) violation, rank auto-assignment, and scoped_search.

Notes

  • The global repository aggregator wiring is deferred to the REST PR (BA-6556), mirroring AppConfigDefinition/AppConfigAllowList.
  • Update/purge are id-based (the db_source builds the Updater/Purger internally), consistent with the id-based purge established in the AppConfigAllowList stack.

Resolves BA-6553.

@github-actions github-actions Bot added size:XL 500~ LoC comp:manager Related to Manager component labels Jun 18, 2026
@jopemachine jopemachine force-pushed the feat/BA-6552-app-config-fragments-model branch from ee2522e to e5fdd83 Compare June 19, 2026 01:01
@jopemachine jopemachine force-pushed the feat/BA-6553-app-config-fragments-repository branch from 3096cd0 to 2894d9c Compare June 19, 2026 01:01
@jopemachine jopemachine force-pushed the feat/BA-6552-app-config-fragments-model branch from e5fdd83 to 7fa8339 Compare June 22, 2026 07:52
@jopemachine jopemachine force-pushed the feat/BA-6553-app-config-fragments-repository branch from 2894d9c to 8675751 Compare June 22, 2026 08:06
Base automatically changed from feat/BA-6552-app-config-fragments-model to main June 22, 2026 08:11
@jopemachine jopemachine force-pushed the feat/BA-6553-app-config-fragments-repository branch from 8675751 to 792f33d Compare June 22, 2026 08:13
jopemachine and others added 3 commits June 22, 2026 17:20
Add the AppConfigFragmentRepository (create / get / update / search / purge)
over a dedicated db_source and DBOpsProvider. Fragments support update
(unlike definition/allow-list) and carry a rank: create assigns the next
rank within a config_name race-free via create_with_next_value (locking the
parent app_config_definitions row), and update may set rank for re-ordering.
Adds an applicable_fragments query (public + the user's domain + user
fragments, ordered by rank) for the upcoming merge engine, plus query
conditions/orders and the AppConfigFragmentNotFound error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mainID/UserID

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jopemachine jopemachine force-pushed the feat/BA-6553-app-config-fragments-repository branch from 792f33d to 520d4e5 Compare June 22, 2026 08:20
Comment thread src/ai/backend/manager/repositories/app_config_fragment/repository.py Outdated
- Introduce typed next-value dependency (AppConfigFragmentCreateDependency /
  DeploymentRevisionPresetCreateDependency) instead of a bare int passed to
  build_row; execute_next_value_creator now takes a build_dependency factory so
  each domain owns an extensible dependency type.
- Inject pre-created fragments via fixtures (existing_fragment / seeded_fragments)
  in repository tests instead of calling create inline in non-create tests.
- Drop applicable_fragments from the repository/db_source per review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jopemachine and others added 3 commits June 23, 2026 10:51
Match the repository convention used everywhere else (model_card, object_storage,
project_resource_policy, etc.): update() receives an `Updater[Row]` (bundling the
spec and pk_value), mirroring create()/purge() taking Creator/Purger — instead of
separate (fragment_id, spec) params.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror create()/update() and the convention used elsewhere (allow_list, etc.):
purge() receives a `Purger[Row]` instead of a bare fragment_id, so the caller
composes the spec/identifier object.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow the two-variant search convention: admin_search (superadmin/internal,
batch_query_in_global, no scope) and scoped_search (batch_query_with_scopes,
restricted to the given scopes). Add ConfigNameSearchScope (types.py) so a search
can be scoped to one config_name; its existence check rejects an unregistered
config_name up front.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/ai/backend/manager/repositories/app_config_fragment/db_source/db_source.py Outdated
jopemachine and others added 3 commits June 23, 2026 11:23
Drop the per-domain dependency wrapper types and the build_dependency factory;
keep the original convention where DependentCreatorSpec.build_row receives the
computed next rank as a bare int (next_rank: int). execute_next_value_creator /
create_with_next_value go back to DependentCreatorSpec[int, TRow].

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the non-conventional _to_search_result staticmethod helper; build the
AppConfigFragmentSearchResult inline in admin_search/scoped_search like every other
db_source (model_card, audit_log). Removes the awkward BatchQuerierResult[sa.Row[Any]]
typing and now-unused imports.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow the repository-test convention (model_card): each input is its own fixture
that inserts the row directly via db_sess.add (no repository.create for setup, no
inline spec list). Tests inject only the fixtures they need and derive expectations
from them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jopemachine and others added 3 commits June 23, 2026 11:47
Replace the per-input fixtures and _seed_*/_spec helpers with a few scenario
fixtures (theme_registered, existing_fragment, seeded_fragments) that inline the
direct db_sess.add seeding and are injected once per test. Tests derive their
expectations from the injected scenario.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename existing_fragment -> domain_scoped_fragment and seeded_fragments ->
fragments_across_scopes so each fixture reads as the test situation it sets up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap every repository method with the repository resilience policy (metrics +
fixed-backoff retry, BackendAIError treated as non-retryable), matching the
convention used across the repository layer. Add the APP_CONFIG_FRAGMENT_REPOSITORY
LayerType for the metric label.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the comp:common Related to Common component label Jun 23, 2026
Extend the repository resilience policy to the sibling ops-based app_config
repositories (allow_list, definition) so the whole family is consistent. Add the
APP_CONFIG_ALLOW_LIST_REPOSITORY / APP_CONFIG_DEFINITION_REPOSITORY LayerTypes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment on lines +424 to +426
APP_CONFIG_ALLOW_LIST_REPOSITORY = "app_config_allow_list_repository"
APP_CONFIG_DEFINITION_REPOSITORY = "app_config_definition_repository"
APP_CONFIG_FRAGMENT_REPOSITORY = "app_config_fragment_repository"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It was missed in the previous repository PR, so I'm including the fix in this PR as well.

Add db_source-level resilience to the app_config family (fragment, allow_list,
definition), mirroring the direct-db db_sources (audit_log etc.): DB_SOURCE-domain
metrics + fixed-backoff retry (max_retries=5, BackendAIError non-retryable). Add the
matching *_DB_SOURCE LayerTypes. db_ops does not wrap resilience internally, so this
was simply missing on the ops-based db_sources.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jopemachine jopemachine marked this pull request as ready for review June 23, 2026 03:40
@jopemachine jopemachine requested a review from a team as a code owner June 23, 2026 03:40
Copilot AI review requested due to automatic review settings June 23, 2026 03:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces the initial repository-layer implementation for app_config_fragments (part of the BEP-1052 AppConfig stack), including CRUD-style DB operations, search/scoping primitives, and real-DB unit tests. It also aligns related AppConfig repositories with the same resilience/metrics instrumentation pattern and registers new metric layer identifiers.

Changes:

  • Add AppConfigFragmentRepository backed by AppConfigFragmentDBSource, plus creator/updater specs and scoped-search support.
  • Add query condition/order helpers for AppConfigFragmentRow and a AppConfigFragmentSearchResult DTO.
  • Add real-DB with_tables unit tests and register new repository/db-source LayerType metric identifiers (and apply resilience decorators to app_config_definition/allow_list repos & db sources).

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/unit/manager/repositories/app_config_fragment/test_repository.py Real-DB repository tests for create/get/update/purge and search/scoped-search behavior
tests/unit/manager/repositories/app_config_fragment/BUILD Adds Pants target for the new test module
tests/unit/manager/repositories/app_config_fragment/init.py Package marker for the new test directory
src/ai/backend/manager/repositories/app_config_fragment/creators.py Creator spec for rank-assigned fragment creation
src/ai/backend/manager/repositories/app_config_fragment/updaters.py Updater spec for config replacement and optional rank update
src/ai/backend/manager/repositories/app_config_fragment/types.py Adds a ConfigNameSearchScope with existence checks
src/ai/backend/manager/repositories/app_config_fragment/db_source/db_source.py DBSource implementation for create/get/update/purge/admin_search/scoped_search + next-rank policy
src/ai/backend/manager/repositories/app_config_fragment/db_source/init.py Exposes AppConfigFragmentDBSource
src/ai/backend/manager/repositories/app_config_fragment/repository.py Repository facade with resilience wrapper methods
src/ai/backend/manager/repositories/app_config_fragment/repositories.py Repository bundle factory (local aggregator)
src/ai/backend/manager/models/app_config_fragment/conditions.py Condition helpers for filtering + cursor pagination
src/ai/backend/manager/models/app_config_fragment/orders.py Order helpers for sorting fragment queries
src/ai/backend/manager/errors/app_config.py Adds AppConfigFragmentNotFound error type
src/ai/backend/manager/data/app_config_fragment/types.py Adds AppConfigFragmentSearchResult DTO
src/ai/backend/common/metrics/metric.py Registers new LayerType entries for app_config repositories/db-sources
src/ai/backend/manager/repositories/app_config_definition/repository.py Applies resilience wrapper to existing repository methods
src/ai/backend/manager/repositories/app_config_definition/db_source/db_source.py Applies resilience wrapper to existing DBSource methods
src/ai/backend/manager/repositories/app_config_allow_list/repository.py Applies resilience wrapper to existing repository methods
src/ai/backend/manager/repositories/app_config_allow_list/db_source/db_source.py Applies resilience wrapper to existing DBSource methods
changes/12307.feature.md Towncrier news fragment for this feature

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

Comment thread changes/12307.feature.md Outdated
The applicable_fragments query was removed from this PR; the news fragment now
lists only what ships (create/get/update/admin_search/scoped_search/purge + rank).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:common Related to Common component comp:manager Related to Manager component size:XL 500~ LoC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants