feat(settings): register API config in SettingsService with 2-phase init#518
feat(settings): register API config in SettingsService with 2-phase init#518
Conversation
Register 10 API settings (server, CORS, rate limiting, auth) in the settings registry so they appear in the Settings UI. Four are runtime- editable via ConfigResolver.get_api_config(); six are bootstrap-only (restart_required) since Litestar bakes middleware/CORS at construction. Document the 2-phase init pattern in app.py: Phase 1 reads RootConfig at construction, Phase 2 uses SettingsService after persistence connects.
Pre-reviewed by 13 agents, 6 findings addressed: - CLAUDE.md + operations.md: update namespace count 8→9, add api - test_resolver: use RateLimitTimeUnit in fake model + assertions - test_resolver: move RateLimitTimeUnit import to module level - test_settings_integration: fix AsyncGenerator annotation - resolver.py + app.py: enumerate all 6 bootstrap-only setting keys
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a new "api" settings namespace with definitions and enum, implements ConfigResolver.get_api_config(), extends create_app() to accept injectable services for a two‑phase init, updates docs, and adds unit and integration tests exercising API settings resolution and overrides. Changes
Sequence Diagram(s)sequenceDiagram
participant App as App (construct)
participant Litestar as Litestar Server
participant Persistence as Persistence Backend
participant Settings as SettingsService
participant Resolver as ConfigResolver
App->>Litestar: create_app(phase1 minimal config, injectable services)
Note right of Litestar: Server starts with bootstrap-only config
Litestar->>Persistence: connect (on_startup)
Persistence-->>Litestar: connected
Litestar->>Settings: initialize SettingsService (uses Persistence)
Settings-->>Litestar: ready
Litestar->>Resolver: resolve API config via get_api_config()
Resolver->>Settings: parallel get(setting) tasks
Settings-->>Resolver: resolved values / exceptions
Resolver-->>Litestar: composed ApiConfig
Litestar->>App: apply runtime-config (CORS, auth, rate-limit) — Phase 2
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
✨ Simplify code
📝 Coding Plan
Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the API's configuration management by integrating API-specific settings into the existing robust settings system. It introduces a dedicated API settings namespace, allowing for dynamic adjustments of certain parameters while clearly defining and documenting the lifecycle of immutable bootstrap settings. This change improves configurability, maintainability, and clarity regarding how API settings are managed and applied within the application. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request effectively integrates API configuration into the settings service, introducing a new 'api' namespace and a get_api_config method in the ConfigResolver. The implementation correctly uses a two-phase initialization pattern, distinguishing between bootstrap and runtime settings, and leverages asyncio.TaskGroup for efficient parallel fetching of runtime-editable values. The changes are well-tested with both unit and integration tests. My main feedback concerns a few missing yaml_path properties in the new setting definitions, which prevents them from being configured via the primary YAML file.
| SettingDefinition( | ||
| namespace=SettingNamespace.API, | ||
| key="cors_allowed_origins", | ||
| type=SettingType.JSON, | ||
| default='["http://localhost:5173"]', | ||
| description="Origins permitted to make cross-origin requests", | ||
| group="CORS", | ||
| restart_required=True, | ||
| ) |
There was a problem hiding this comment.
This setting is missing the yaml_path property. Without it, this setting cannot be configured from the main YAML file and will fall back to an environment variable or the hardcoded default. This seems like an oversight for an important security configuration.
SettingDefinition(
namespace=SettingNamespace.API,
key="cors_allowed_origins",
type=SettingType.JSON,
default='["http://localhost:5173"]',
description="Origins permitted to make cross-origin requests",
group="CORS",
restart_required=True,
yaml_path="api.cors.allowed_origins",
)| SettingDefinition( | ||
| namespace=SettingNamespace.API, | ||
| key="rate_limit_exclude_paths", | ||
| type=SettingType.JSON, | ||
| default='["/api/v1/health"]', | ||
| description="Paths excluded from rate limiting", | ||
| group="Rate Limiting", | ||
| level=SettingLevel.ADVANCED, | ||
| restart_required=True, | ||
| ) |
There was a problem hiding this comment.
This setting is missing the yaml_path property. Without it, this setting cannot be configured from the main YAML file and will fall back to an environment variable or the hardcoded default.
SettingDefinition(
namespace=SettingNamespace.API,
key="rate_limit_exclude_paths",
type=SettingType.JSON,
default='["/api/v1/health"]',
description="Paths excluded from rate limiting",
group="Rate Limiting",
level=SettingLevel.ADVANCED,
restart_required=True,
yaml_path="api.rate_limit.exclude_paths",
)| SettingDefinition( | ||
| namespace=SettingNamespace.API, | ||
| key="auth_exclude_paths", | ||
| type=SettingType.JSON, | ||
| default="[]", | ||
| description="Paths excluded from authentication middleware", | ||
| group="Authentication", | ||
| level=SettingLevel.ADVANCED, | ||
| restart_required=True, | ||
| ) |
There was a problem hiding this comment.
This setting is missing the yaml_path property. Without it, this setting cannot be configured from the main YAML file and will fall back to an environment variable or the hardcoded default. This seems like an oversight for an important security configuration.
SettingDefinition(
namespace=SettingNamespace.API,
key="auth_exclude_paths",
type=SettingType.JSON,
default="[]",
description="Paths excluded from authentication middleware",
group="Authentication",
level=SettingLevel.ADVANCED,
restart_required=True,
yaml_path="api.auth.exclude_paths",
)There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/synthorg/settings/definitions/api.py`:
- Around line 144-155: The SettingDefinition registered via _r.register for
namespace SettingNamespace.API with key "auth_exclude_paths" is missing its
yaml_path and should be added so YAML-based config resolution works; update the
SettingDefinition instantiation (the call that sets type=SettingType.JSON,
default="[]", description="Paths excluded from authentication middleware",
group="Authentication", level=SettingLevel.ADVANCED, restart_required=True) to
include yaml_path="api.auth.exclude_paths".
- Around line 61-71: The SettingDefinition for the setting key
"cors_allowed_origins" is missing a yaml_path, so YAML config is skipped during
resolution; update the SettingDefinition (namespace SettingNamespace.API, key
"cors_allowed_origins") to include yaml_path="api.cors.allowed_origins" so the
resolver will read base YAML under api.cors.allowed_origins before falling back
to env or default, keeping the rest of the SettingDefinition (type, default,
description, group, restart_required) unchanged.
- Around line 101-112: The SettingDefinition for the API setting with key
"rate_limit_exclude_paths" is missing a yaml_path; update the SettingDefinition
(where SettingNamespace.API and key="rate_limit_exclude_paths" are used) to
include yaml_path="api.rate_limit.exclude_paths" so YAML-based configuration
matches other rate limit settings and remains consistent with the existing rate
limit group/namespace.
In `@tests/integration/settings/test_settings_integration.py`:
- Around line 24-102: Update the docstrings in this module to Google-style for
all public fixtures, the TestApiSettingsIntegration class, and its test methods:
replace the current summary-only triple-quoted strings for db_path, backend,
config, settings_service, resolver, TestApiSettingsIntegration,
test_db_override_flows_through_resolver, and test_defaults_without_db_overrides
with Google-style docstrings that include a short summary and parameter/returns
sections where applicable (e.g., Args: tmp_path: Path for db_path; Returns: str
for db_path; for async fixtures note Returns and yield behavior; for the class
include a short description and omit Args; for test methods include Args only if
they accept fixtures), ensuring the formatting matches Google-style (summary
line, blank line, sections like Args/Returns) so ruff D rules pass.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 5a3c9c0b-e019-464f-b592-07a3953a8e18
📒 Files selected for processing (10)
CLAUDE.mddocs/design/operations.mdsrc/synthorg/api/app.pysrc/synthorg/settings/definitions/__init__.pysrc/synthorg/settings/definitions/api.pysrc/synthorg/settings/enums.pysrc/synthorg/settings/resolver.pytests/integration/settings/__init__.pytests/integration/settings/test_settings_integration.pytests/unit/settings/test_resolver.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Deploy Preview
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Backend
- GitHub Check: Build Sandbox
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Do not usefrom __future__ import annotations— Python 3.14 has PEP 649 native lazy annotations.
Useexcept A, B:syntax (no parentheses) — PEP 758 except syntax enforced by ruff on Python 3.14.
Add type hints to all public functions; enforce mypy strict mode compliance.
Use Google-style docstrings on all public classes and functions; enforce via ruff D rules.
Keep functions under 50 lines and files under 800 lines.
Handle errors explicitly and never silently swallow exceptions.
Validate at system boundaries (user input, external APIs, config files).
Set line length to 88 characters (ruff enforces).
Useuvfor Python dependency management. Install withuv sync, run tests with-n autofor parallelism, lint withruff check, format withruff format, type-check withmypy.
Scripts inscripts/have relaxed ruff rules:
Files:
src/synthorg/settings/definitions/__init__.pysrc/synthorg/settings/enums.pysrc/synthorg/settings/resolver.pysrc/synthorg/api/app.pytests/integration/settings/test_settings_integration.pytests/unit/settings/test_resolver.pysrc/synthorg/settings/definitions/api.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
src/synthorg/**/*.py: Create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries,BaseTool), usecopy.deepcopy()at construction +MappingProxyTypewrapping. Fordict/listfields in frozen Pydantic models, rely onfrozen=Trueandcopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization).
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (withmodel_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Adopt Pydantic v2 conventions: use@computed_fieldfor derived values instead of storing redundant fields; useNotBlankStrfromcore.typesfor all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_task.
Every module with business logic must have:from synthorg.observability import get_loggerthenlogger = get_logger(__name__). Never useimport logging,logging.getLogger(), orprint()in application code.
Always useloggeras the variable name (not_logger, notlog). Use event name constants from domain-specific modules undersynthorg.observability.events(e.g.,PROVIDER_CALL_STARTfromevents.provider). Import directly:from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Always use structured kwargs for logging:logger.info(EVENT, key=value)— never use string interpolation likelogger.info('msg %s', val).
Log all error paths at WARNING or ERROR with context before raising. Log all state transitions at INFO. Log object creation, internal flow, and entry/exit of key functions at DEBUG.
Do NOT useimport loggingorlogging.getLogger(). Pure data models, ...
Files:
src/synthorg/settings/definitions/__init__.pysrc/synthorg/settings/enums.pysrc/synthorg/settings/resolver.pysrc/synthorg/api/app.pysrc/synthorg/settings/definitions/api.py
**/*.{md,py,ts,tsx,vue,go,yml,yaml,json,toml}
📄 CodeRabbit inference engine (CLAUDE.md)
Use conventional commits:
<type>: <description>where types are feat, fix, refactor, docs, test, chore, perf, ci. Commits must be GPG/SSH signed on main branch.
Files:
src/synthorg/settings/definitions/__init__.pysrc/synthorg/settings/enums.pyCLAUDE.mdsrc/synthorg/settings/resolver.pydocs/design/operations.mdsrc/synthorg/api/app.pytests/integration/settings/test_settings_integration.pytests/unit/settings/test_resolver.pysrc/synthorg/settings/definitions/api.py
src/synthorg/settings/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Runtime-editable settings persistence with DB > env > YAML > code defaults priority. 8 namespaces via
definitions/. Fernet encryption for sensitive values. ConfigResolver for typed composed reads. Change notifications via message bus. Validation and registry.
Files:
src/synthorg/settings/definitions/__init__.pysrc/synthorg/settings/enums.pysrc/synthorg/settings/resolver.pysrc/synthorg/settings/definitions/api.py
**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Read relevant
docs/design/page before implementing features or planning issues. Design spec is the starting point for architecture, data models, and behavior.
Files:
CLAUDE.mddocs/design/operations.md
docs/**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Documentation in Markdown built with Zensical. Design spec: 7 pages under
docs/design/(index, agents, organization, communication, engine, memory, operations). Architecture:docs/architecture/. Roadmap:docs/roadmap/. Security:docs/security.md. Licensing:docs/licensing.md. Reference:docs/reference/. REST API:docs/rest-api.mdwith generated Scalar UI. Library reference:docs/api/(auto-generated from docstrings via mkdocstrings + Griffe).
Files:
docs/design/operations.md
src/synthorg/api/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Litestar REST + WebSocket API with JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. Use RFC 9457 structured errors:
ErrorCategory,ErrorCode,ErrorDetail,ProblemDetail,CATEGORY_TITLES,category_title,category_type_uri, content negotiation.
Files:
src/synthorg/api/app.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
tests/**/*.py: Mark tests with@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e, or@pytest.mark.slow. Maintain 80% minimum code coverage.
Useasyncio_mode = 'auto'for async tests — no manual@pytest.mark.asyncioneeded. Set test timeout to 30 seconds per test. Always include-n autofor parallelism via pytest-xdist.
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned test code, docstrings, or config examples. Use generic names:example-provider,example-large-001,example-medium-001,example-small-001,test-provider,test-small-001, etc. Vendor names may only appear in Operations design page, .claude/ files, or third-party import paths.
Use Hypothesis for property-based testing with@given+@settings. Profiles:ci(200 examples, default) anddev(1000 examples) viaHYPOTHESIS_PROFILEenv var. Never skip, dismiss, or ignore flaky tests — fix them fully. Mocktime.monotonic()andasyncio.sleep()for deterministic timing-sensitive tests instead of widening margins.
Files:
tests/integration/settings/test_settings_integration.pytests/unit/settings/test_resolver.py
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/settings/**/*.py : Runtime-editable settings persistence with DB > env > YAML > code defaults priority. 8 namespaces via `definitions/`. Fernet encryption for sensitive values. ConfigResolver for typed composed reads. Change notifications via message bus. Validation and registry.
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/settings/**/*.py : Runtime-editable settings persistence with DB > env > YAML > code defaults priority. 8 namespaces via `definitions/`. Fernet encryption for sensitive values. ConfigResolver for typed composed reads. Change notifications via message bus. Validation and registry.
Applied to files:
src/synthorg/settings/definitions/__init__.pyCLAUDE.mdsrc/synthorg/settings/resolver.pydocs/design/operations.mdtests/integration/settings/test_settings_integration.pytests/unit/settings/test_resolver.pysrc/synthorg/settings/definitions/api.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/persistence/**/*.py : Pluggable PersistenceBackend protocol with SQLite initial backend. SettingsRepository for namespaced settings CRUD. See Memory & Persistence design page.
Applied to files:
CLAUDE.mdtests/integration/settings/test_settings_integration.pysrc/synthorg/settings/definitions/api.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/security/**/*.py : SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies: disabled/weighted/per-category/milestone), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume).
Applied to files:
CLAUDE.mddocs/design/operations.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to docs/**/*.md : Documentation in Markdown built with Zensical. Design spec: 7 pages under `docs/design/` (index, agents, organization, communication, engine, memory, operations). Architecture: `docs/architecture/`. Roadmap: `docs/roadmap/`. Security: `docs/security.md`. Licensing: `docs/licensing.md`. Reference: `docs/reference/`. REST API: `docs/rest-api.md` with generated Scalar UI. Library reference: `docs/api/` (auto-generated from docstrings via mkdocstrings + Griffe).
Applied to files:
CLAUDE.mddocs/design/operations.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/providers/**/*.py : RetryConfig and RateLimiterConfig are set per-provider in ProviderConfig.
Applied to files:
src/synthorg/settings/resolver.pytests/unit/settings/test_resolver.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/engine/**/*.py : Agent orchestration with TaskEngine (centralized single-writer task state), task lifecycle, recovery, shutdown, workspace isolation. Coordination: multi-agent pipeline via TopologyDispatcher protocol (4 dispatchers: SAS/centralized/decentralized/context-dependent), wave execution, workspace lifecycle, CoordinationSectionConfig bridge, build_coordinator factory. Approval gate: escalation detection, context parking/resume, EscalationInfo/ResumePayload. Stagnation detection: StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection. Checkpoint recovery: per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy. AgentRuntimeState: lightweight per-agent execution status for dashboard + recovery.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/hr/**/*.py : HR engine: hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration sampling, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping).
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/api/**/*.py : Litestar REST + WebSocket API with JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. Use RFC 9457 structured errors: `ErrorCategory`, `ErrorCode`, `ErrorDetail`, `ProblemDetail`, `CATEGORY_TITLES`, `category_title`, `category_type_uri`, content negotiation.
Applied to files:
src/synthorg/settings/definitions/api.py
🧬 Code graph analysis (3)
tests/integration/settings/test_settings_integration.py (3)
src/synthorg/settings/registry.py (1)
get_registry(111-113)src/synthorg/settings/resolver.py (1)
ConfigResolver(33-463)src/synthorg/settings/service.py (1)
SettingsService(152-637)
tests/unit/settings/test_resolver.py (5)
src/synthorg/settings/models.py (1)
SettingValue(212-232)src/synthorg/settings/service.py (1)
get(189-273)src/synthorg/settings/errors.py (1)
SettingNotFoundError(8-9)src/synthorg/settings/enums.py (1)
SettingNamespace(6-21)src/synthorg/api/state.py (1)
settings_service(237-239)
src/synthorg/settings/definitions/api.py (3)
src/synthorg/settings/enums.py (3)
SettingLevel(39-47)SettingNamespace(6-21)SettingType(24-36)src/synthorg/settings/models.py (1)
SettingDefinition(34-140)src/synthorg/settings/registry.py (2)
get_registry(111-113)register(30-50)
🔇 Additional comments (11)
docs/design/operations.md (1)
1044-1044: LGTM!The documentation correctly reflects the addition of the API namespace, updating the namespace count from 8 to 9 and listing all namespaces in order. The description of
ConfigResolverusingasyncio.TaskGroupfor parallel resolution aligns with the implementation inresolver.py.src/synthorg/settings/enums.py (1)
13-13: LGTM!The
APIenum member is correctly added toSettingNamespace. The alphabetical ordering (API first) is appropriate and consistent with the enum's purpose of categorizing runtime-editable settings by subsystem.src/synthorg/settings/definitions/__init__.py (1)
7-29: LGTM!The
apimodule is correctly imported and exported, following the established pattern for namespace definition modules. Alphabetical ordering is maintained in both the import block and__all__list.CLAUDE.md (1)
131-132: LGTM!The CLAUDE.md documentation correctly reflects the expansion from 8 to 9 namespaces and includes
apias the first namespace in the definitions list, matching the enum ordering and actual implementation.src/synthorg/settings/resolver.py (1)
332-395: LGTM!The
get_api_config()implementation is well-structured and follows the established patterns fromget_budget_config()andget_coordination_config():
- Uses
asyncio.TaskGroupfor parallel resolution of the 4 runtime-editable settings- Correctly handles
ExceptionGroupby logging and re-raising the first exception- Preserves bootstrap-only fields (CORS, server, exclude_paths, api_prefix) via
model_copy- Docstring clearly documents which settings are resolved vs. preserved
- The deferred import of
RateLimitTimeUnitavoids circular importstests/unit/settings/test_resolver.py (2)
74-119: LGTM!The fake config models for API testing are well-structured and mirror the actual
ApiConfighierarchy. The_FakeRootConfigis correctly extended with theapifield, enabling composed-read testing for the newget_api_config()method.
638-750: LGTM!The
TestGetApiConfigtest class provides comprehensive coverage:
- Defaults: Verifies all 4 runtime-editable settings resolve correctly
- Overrides: Confirms DB values take precedence over defaults
- Bootstrap preservation: Validates that CORS, server, exclude_paths, and api_prefix are preserved from YAML config
- Error propagation: Tests both
SettingNotFoundErrorandValueErrorare properly unwrapped fromExceptionGroup- Enum resolution: Confirms
RateLimitTimeUnitenum members resolve correctlyThe test structure follows the established patterns from
TestGetBudgetConfigandTestGetCoordinationConfig.src/synthorg/api/app.py (2)
475-490: LGTM!The 2-phase initialization comment block is a valuable architectural documentation addition. It clearly explains:
- Phase 1 (construct): Bootstrap-only settings read from
RootConfigat construction time (immutable after Litestar builds)- Phase 2 (on_startup): Runtime-editable settings resolved through
SettingsServiceafter persistence connectsThis distinction is critical for understanding why certain API settings require restart while others can be changed at runtime.
492-507: LGTM!The
settings_serviceparameter is correctly integrated intocreate_app:
- Added to signature with
Nonedefault for backward compatibility- Included in the None-check warning (Line 567) alongside other required services
- Documented in the docstring
- Passed through to
AppStateconstruction (Line 602)tests/integration/settings/test_settings_integration.py (2)
24-68: Good end-to-end fixture composition.This setup correctly exercises real SQLite persistence with
SettingsServiceandConfigResolver, which is the right integration depth for this feature.
76-102: Strong coverage of override vs default resolution paths.These tests validate both DB override flow-through and fallback defaults for API settings in a focused way.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #518 +/- ##
==========================================
+ Coverage 93.12% 93.15% +0.03%
==========================================
Files 504 505 +1
Lines 24452 24480 +28
Branches 2333 2333
==========================================
+ Hits 22770 22805 +35
+ Misses 1335 1328 -7
Partials 347 347 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Settings definitions (api.py):
- Add yaml_path for cors_allowed_origins, rate_limit_exclude_paths,
auth_exclude_paths (Gemini, CodeRabbit, code-reviewer)
- Add max_value=10000 on rate_limit_max_requests (security-reviewer)
- Raise min_password_length min_value 8→12 (security-reviewer)
- Reduce jwt_expiry_minutes max_value 43200→10080 (security-reviewer)
- Annotate section comments for mixed bootstrap/runtime groups
Documentation:
- Clarify resolver docstring: bootstrap settings "require restart"
- Add rate-limit middleware note to 2-phase init comment (app.py)
Tests:
- Add partial failure test (1 failing + 3 succeeding settings)
- Add invalid enum value test ("weekly" → ValueError)
- Parametrize enum resolution over all RateLimitTimeUnit members
- Fix _FakeAuthConfig.jwt_algorithm to Literal type
- Fix _FakeApiConfig.api_prefix to NotBlankStr type
- Fix test_preserves_unregistered_fields docstring (add api_prefix)
- Update integration test docstrings to Google style
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/synthorg/api/app.py`:
- Around line 484-489: The AuthService is being constructed in
_init_persistence() using static app_state.config.api.auth so runtime-editable
settings like jwt_expiry_minutes and min_password_length from
SettingsService/ConfigResolver never take effect; modify the startup flow so
AuthService is created (or re-initialized) using the resolved runtime config
from ConfigResolver.get_api_config() after persistence/migrations complete
(Phase 2), or add a post-startup refresh step that calls
ConfigResolver.get_api_config() and updates/replaces the AuthService instance
with values from that result; ensure references to app_state.config.api.auth are
replaced or synchronized with the ConfigResolver.get_api_config() output so
AuthService uses the active runtime settings.
In `@src/synthorg/settings/definitions/api.py`:
- Around line 76-100: The two SettingDefinition entries for keys
"rate_limit_max_requests" and "rate_limit_time_unit" must be marked restart-only
because Litestar captures max_requests/time_unit at app construction and won't
re-read ConfigResolver; update the SettingDefinition for namespace
SettingNamespace.API with key "rate_limit_max_requests" and the one with key
"rate_limit_time_unit" to include restart_required=True so changes require an
application restart (i.e., add restart_required=True to those SettingDefinition
constructors).
- Around line 45-56: The registered API settings (SettingDefinition entries
under SettingNamespace.API such as "api_prefix", "cors_allowed_origins",
"rate_limit_exclude_paths", and "auth_exclude_paths") are never read during
startup because create_app() still constructs router/CORS/auth/rate-limit from
RootConfig.api; update the startup flow to load these values from the
SettingsService before building the app. Concretely: add a pre-construction step
in create_app() (or its caller) to query SettingsService for the keys registered
in api settings and merge/override RootConfig.api (or pass a resolved config
object) so that functions that build the router, CORS config, and middleware
consume the resolved values; ensure the code path that builds routes in
src/synthorg/api/app.py uses the resolved settings rather than RootConfig.api to
honor DB changes to api_prefix, cors_allowed_origins, rate_limit_exclude_paths,
and auth_exclude_paths.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c92d7151-60c4-4a77-a1a3-970c760793aa
📒 Files selected for processing (5)
src/synthorg/api/app.pysrc/synthorg/settings/definitions/api.pysrc/synthorg/settings/resolver.pytests/integration/settings/test_settings_integration.pytests/unit/settings/test_resolver.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Deploy Preview
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Sandbox
- GitHub Check: Build Web
- GitHub Check: Build Backend
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Do not usefrom __future__ import annotations— Python 3.14 has PEP 649 native lazy annotations.
Useexcept A, B:syntax (no parentheses) — PEP 758 except syntax enforced by ruff on Python 3.14.
Add type hints to all public functions; enforce mypy strict mode compliance.
Use Google-style docstrings on all public classes and functions; enforce via ruff D rules.
Keep functions under 50 lines and files under 800 lines.
Handle errors explicitly and never silently swallow exceptions.
Validate at system boundaries (user input, external APIs, config files).
Set line length to 88 characters (ruff enforces).
Useuvfor Python dependency management. Install withuv sync, run tests with-n autofor parallelism, lint withruff check, format withruff format, type-check withmypy.
Scripts inscripts/have relaxed ruff rules:
Files:
src/synthorg/settings/definitions/api.pytests/unit/settings/test_resolver.pysrc/synthorg/settings/resolver.pysrc/synthorg/api/app.pytests/integration/settings/test_settings_integration.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
src/synthorg/**/*.py: Create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries,BaseTool), usecopy.deepcopy()at construction +MappingProxyTypewrapping. Fordict/listfields in frozen Pydantic models, rely onfrozen=Trueandcopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization).
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (withmodel_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Adopt Pydantic v2 conventions: use@computed_fieldfor derived values instead of storing redundant fields; useNotBlankStrfromcore.typesfor all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_task.
Every module with business logic must have:from synthorg.observability import get_loggerthenlogger = get_logger(__name__). Never useimport logging,logging.getLogger(), orprint()in application code.
Always useloggeras the variable name (not_logger, notlog). Use event name constants from domain-specific modules undersynthorg.observability.events(e.g.,PROVIDER_CALL_STARTfromevents.provider). Import directly:from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Always use structured kwargs for logging:logger.info(EVENT, key=value)— never use string interpolation likelogger.info('msg %s', val).
Log all error paths at WARNING or ERROR with context before raising. Log all state transitions at INFO. Log object creation, internal flow, and entry/exit of key functions at DEBUG.
Do NOT useimport loggingorlogging.getLogger(). Pure data models, ...
Files:
src/synthorg/settings/definitions/api.pysrc/synthorg/settings/resolver.pysrc/synthorg/api/app.py
**/*.{md,py,ts,tsx,vue,go,yml,yaml,json,toml}
📄 CodeRabbit inference engine (CLAUDE.md)
Use conventional commits:
<type>: <description>where types are feat, fix, refactor, docs, test, chore, perf, ci. Commits must be GPG/SSH signed on main branch.
Files:
src/synthorg/settings/definitions/api.pytests/unit/settings/test_resolver.pysrc/synthorg/settings/resolver.pysrc/synthorg/api/app.pytests/integration/settings/test_settings_integration.py
src/synthorg/settings/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Runtime-editable settings persistence with DB > env > YAML > code defaults priority. 8 namespaces via
definitions/. Fernet encryption for sensitive values. ConfigResolver for typed composed reads. Change notifications via message bus. Validation and registry.
Files:
src/synthorg/settings/definitions/api.pysrc/synthorg/settings/resolver.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
tests/**/*.py: Mark tests with@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e, or@pytest.mark.slow. Maintain 80% minimum code coverage.
Useasyncio_mode = 'auto'for async tests — no manual@pytest.mark.asyncioneeded. Set test timeout to 30 seconds per test. Always include-n autofor parallelism via pytest-xdist.
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned test code, docstrings, or config examples. Use generic names:example-provider,example-large-001,example-medium-001,example-small-001,test-provider,test-small-001, etc. Vendor names may only appear in Operations design page, .claude/ files, or third-party import paths.
Use Hypothesis for property-based testing with@given+@settings. Profiles:ci(200 examples, default) anddev(1000 examples) viaHYPOTHESIS_PROFILEenv var. Never skip, dismiss, or ignore flaky tests — fix them fully. Mocktime.monotonic()andasyncio.sleep()for deterministic timing-sensitive tests instead of widening margins.
Files:
tests/unit/settings/test_resolver.pytests/integration/settings/test_settings_integration.py
src/synthorg/api/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Litestar REST + WebSocket API with JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. Use RFC 9457 structured errors:
ErrorCategory,ErrorCode,ErrorDetail,ProblemDetail,CATEGORY_TITLES,category_title,category_type_uri, content negotiation.
Files:
src/synthorg/api/app.py
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/settings/**/*.py : Runtime-editable settings persistence with DB > env > YAML > code defaults priority. 8 namespaces via `definitions/`. Fernet encryption for sensitive values. ConfigResolver for typed composed reads. Change notifications via message bus. Validation and registry.
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/settings/**/*.py : Runtime-editable settings persistence with DB > env > YAML > code defaults priority. 8 namespaces via `definitions/`. Fernet encryption for sensitive values. ConfigResolver for typed composed reads. Change notifications via message bus. Validation and registry.
Applied to files:
src/synthorg/settings/definitions/api.pytests/unit/settings/test_resolver.pysrc/synthorg/settings/resolver.pytests/integration/settings/test_settings_integration.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/persistence/**/*.py : Pluggable PersistenceBackend protocol with SQLite initial backend. SettingsRepository for namespaced settings CRUD. See Memory & Persistence design page.
Applied to files:
src/synthorg/settings/definitions/api.pytests/integration/settings/test_settings_integration.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/api/**/*.py : Litestar REST + WebSocket API with JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. Use RFC 9457 structured errors: `ErrorCategory`, `ErrorCode`, `ErrorDetail`, `ProblemDetail`, `CATEGORY_TITLES`, `category_title`, `category_type_uri`, content negotiation.
Applied to files:
src/synthorg/settings/definitions/api.py
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/providers/**/*.py : RetryConfig and RateLimiterConfig are set per-provider in ProviderConfig.
Applied to files:
src/synthorg/settings/resolver.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to **/*.py : Use Google-style docstrings on all public classes and functions; enforce via ruff D rules.
Applied to files:
tests/integration/settings/test_settings_integration.py
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to **/*.py : Docstrings: Google style, required on public classes and functions (enforced by ruff D rules).
Applied to files:
tests/integration/settings/test_settings_integration.py
🧬 Code graph analysis (3)
src/synthorg/settings/definitions/api.py (3)
src/synthorg/settings/enums.py (3)
SettingLevel(39-47)SettingNamespace(6-21)SettingType(24-36)src/synthorg/settings/models.py (1)
SettingDefinition(34-140)src/synthorg/settings/registry.py (2)
get_registry(111-113)register(30-50)
tests/unit/settings/test_resolver.py (4)
src/synthorg/settings/models.py (1)
SettingValue(212-232)src/synthorg/settings/service.py (1)
get(189-273)src/synthorg/settings/errors.py (1)
SettingNotFoundError(8-9)src/synthorg/settings/resolver.py (1)
ConfigResolver(33-463)
tests/integration/settings/test_settings_integration.py (5)
src/synthorg/config/schema.py (1)
RootConfig(387-651)src/synthorg/settings/registry.py (1)
get_registry(111-113)tests/unit/settings/test_resolver.py (1)
resolver(138-142)src/synthorg/settings/resolver.py (1)
ConfigResolver(33-463)tests/unit/settings/test_service.py (1)
service(106-113)
🔇 Additional comments (3)
src/synthorg/settings/resolver.py (1)
360-395: Nice copy-on-write composition here.The
TaskGroupfan-out plus nestedmodel_copy(update=...)calls keep the read parallel without mutating the frozen API config tree.tests/unit/settings/test_resolver.py (1)
640-805: Good coverage for the new composed read.These cases hit defaults, overrides, enum coercion, and partial
TaskGroupfailure behavior, which are the brittle edges inget_api_config().tests/integration/settings/test_settings_integration.py (1)
75-114: Useful end-to-end coverage here.Using real SQLite +
SettingsServicealongside the resolver closes the gap that AsyncMock-based unit tests can’t.
| # Phase 2 (on_startup): After persistence connects and migrations | ||
| # run, SettingsService + ConfigResolver become available. Runtime- | ||
| # editable settings (rate_limit_max_requests, rate_limit_time_unit, | ||
| # jwt_expiry_minutes, min_password_length) are resolved through | ||
| # ConfigResolver.get_api_config() by consumers that need current | ||
| # values post-startup. |
There was a problem hiding this comment.
The auth settings called “runtime-editable” never reach the active AuthService.
This note says jwt_expiry_minutes and min_password_length resolve post-startup, but _init_persistence() still constructs AuthService directly from app_state.config.api.auth. With the current flow, pre-existing DB overrides for those fields are ignored unless the auth service is built from ConfigResolver.get_api_config() (or otherwise refreshed from settings after startup).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/app.py` around lines 484 - 489, The AuthService is being
constructed in _init_persistence() using static app_state.config.api.auth so
runtime-editable settings like jwt_expiry_minutes and min_password_length from
SettingsService/ConfigResolver never take effect; modify the startup flow so
AuthService is created (or re-initialized) using the resolved runtime config
from ConfigResolver.get_api_config() after persistence/migrations complete
(Phase 2), or add a post-startup refresh step that calls
ConfigResolver.get_api_config() and updates/replaces the AuthService instance
with values from that result; ensure references to app_state.config.api.auth are
replaced or synchronized with the ConfigResolver.get_api_config() output so
AuthService uses the active runtime settings.
| _r.register( | ||
| SettingDefinition( | ||
| namespace=SettingNamespace.API, | ||
| key="api_prefix", | ||
| type=SettingType.STRING, | ||
| default="/api/v1", | ||
| description="URL prefix for all API routes", | ||
| group="Server", | ||
| level=SettingLevel.ADVANCED, | ||
| restart_required=True, | ||
| yaml_path="api.api_prefix", | ||
| ) |
There was a problem hiding this comment.
These bootstrap keys are registered in the settings DB chain, but the current startup path never reads them from settings.
create_app() still builds the router, CORS config, and auth/rate-limit middleware from RootConfig.api, and the new note in src/synthorg/api/app.py explicitly says api_prefix, cors_allowed_origins, rate_limit_exclude_paths, and auth_exclude_paths are not resolved through SettingsService. With the current flow, DB edits to these keys will show up in the Settings UI but still won’t affect the next app start unless you add a pre-construction bridge from the registry back into startup config.
Also applies to: 61-71, 103-114, 147-158
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/settings/definitions/api.py` around lines 45 - 56, The
registered API settings (SettingDefinition entries under SettingNamespace.API
such as "api_prefix", "cors_allowed_origins", "rate_limit_exclude_paths", and
"auth_exclude_paths") are never read during startup because create_app() still
constructs router/CORS/auth/rate-limit from RootConfig.api; update the startup
flow to load these values from the SettingsService before building the app.
Concretely: add a pre-construction step in create_app() (or its caller) to query
SettingsService for the keys registered in api settings and merge/override
RootConfig.api (or pass a resolved config object) so that functions that build
the router, CORS config, and middleware consume the resolved values; ensure the
code path that builds routes in src/synthorg/api/app.py uses the resolved
settings rather than RootConfig.api to honor DB changes to api_prefix,
cors_allowed_origins, rate_limit_exclude_paths, and auth_exclude_paths.
| _r.register( | ||
| SettingDefinition( | ||
| namespace=SettingNamespace.API, | ||
| key="rate_limit_max_requests", | ||
| type=SettingType.INTEGER, | ||
| default="100", | ||
| description="Maximum requests per time window", | ||
| group="Rate Limiting", | ||
| min_value=1, | ||
| max_value=10000, | ||
| yaml_path="api.rate_limit.max_requests", | ||
| ) | ||
| ) | ||
|
|
||
| _r.register( | ||
| SettingDefinition( | ||
| namespace=SettingNamespace.API, | ||
| key="rate_limit_time_unit", | ||
| type=SettingType.ENUM, | ||
| default="minute", | ||
| description="Rate limit time window", | ||
| group="Rate Limiting", | ||
| enum_values=("second", "minute", "hour", "day"), | ||
| yaml_path="api.rate_limit.time_unit", | ||
| ) |
There was a problem hiding this comment.
These two settings are still restart-only in practice.
The new note in src/synthorg/api/app.py says Litestar captures max_requests and time_unit at construction and never rereads ConfigResolver.get_api_config(). So, even after the broader bootstrap-resolution gap is fixed, these definitions need restart_required=True unless the middleware is rebuilt on change.
🔧 Minimal metadata fix
_r.register(
SettingDefinition(
namespace=SettingNamespace.API,
key="rate_limit_max_requests",
type=SettingType.INTEGER,
default="100",
description="Maximum requests per time window",
group="Rate Limiting",
+ restart_required=True,
min_value=1,
max_value=10000,
yaml_path="api.rate_limit.max_requests",
)
)
@@
_r.register(
SettingDefinition(
namespace=SettingNamespace.API,
key="rate_limit_time_unit",
type=SettingType.ENUM,
default="minute",
description="Rate limit time window",
group="Rate Limiting",
+ restart_required=True,
enum_values=("second", "minute", "hour", "day"),
yaml_path="api.rate_limit.time_unit",
)
)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/settings/definitions/api.py` around lines 76 - 100, The two
SettingDefinition entries for keys "rate_limit_max_requests" and
"rate_limit_time_unit" must be marked restart-only because Litestar captures
max_requests/time_unit at app construction and won't re-read ConfigResolver;
update the SettingDefinition for namespace SettingNamespace.API with key
"rate_limit_max_requests" and the one with key "rate_limit_time_unit" to include
restart_required=True so changes require an application restart (i.e., add
restart_required=True to those SettingDefinition constructors).
🤖 I have created a release *beep* *boop* --- ## [0.3.1](v0.3.0...v0.3.1) (2026-03-17) ### Features * **api:** RFC 9457 Phase 2 — ProblemDetail and content negotiation ([#496](#496)) ([30f7c49](30f7c49)) * **cli:** verify container image signatures and SLSA provenance on pull ([#492](#492)) ([bef272d](bef272d)), closes [#491](#491) * **engine:** implement context budget management in execution loops ([#520](#520)) ([181eb8a](181eb8a)), closes [#416](#416) * implement settings persistence layer (DB-backed config) ([#495](#495)) ([4bd99f7](4bd99f7)), closes [#450](#450) * **memory:** implement dual-mode archival in memory consolidation ([#524](#524)) ([4603c9e](4603c9e)), closes [#418](#418) * migrate config consumers to read through SettingsService ([#510](#510)) ([32f553d](32f553d)) * **settings:** implement settings change subscriptions for service hot-reload ([#526](#526)) ([53f908e](53f908e)), closes [#503](#503) * **settings:** register API config in SettingsService with 2-phase init ([#518](#518)) ([29f7481](29f7481)) * **tools:** add SSRF prevention for git clone URLs ([#505](#505)) ([492dd0d](492dd0d)) * **tools:** wire RootConfig.git_clone to GitCloneTool instantiation ([#519](#519)) ([b7d8172](b7d8172)) ### Bug Fixes * **api:** replace JWT query parameter with one-time ticket for WebSocket auth ([#493](#493)) ([22a25f6](22a25f6)), closes [#343](#343) ### Documentation * add uv cache lock contention handling to worktree skill ([#500](#500)) ([bd85a8d](bd85a8d)) * document RFC 9457 dual response formats in OpenAPI schema ([#506](#506)) ([8dd2524](8dd2524)) ### Maintenance * upgrade jsdom from 28 to 29 ([#499](#499)) ([1ea2249](1ea2249)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
get_api_config()composed-read method toConfigResolver— resolves 4 runtime-editable settings in parallel viaasyncio.TaskGroup, merges onto base config viamodel_copy(update=...)app.py: Phase 1 readsRootConfigat construction (immutable), Phase 2 usesSettingsServiceafter persistence connectsrestart_required=True(Litestar bakes middleware/CORS at construction)docs/design/operations.mdnamespace count 8→9Settings registered (10 total)
Runtime-editable (4):
rate_limit_max_requests,rate_limit_time_unit,jwt_expiry_minutes,min_password_lengthBootstrap-only (6):
server_host,server_port,api_prefix,cors_allowed_origins,rate_limit_exclude_paths,auth_exclude_pathsCloses #504
Test plan
TestGetApiConfig(defaults, DB overrides, bootstrap preservation, error propagation, enum resolution)test_all_namespaces_have_definitionsauto-validates new API namespaceReview coverage
Pre-reviewed by 13 agents, 6 findings addressed:
_FakeRateLimitConfig.time_unittyped asRateLimitTimeUnitfor type fidelityRateLimitTimeUnitimport moved to module levelAsyncGeneratorannotation fixed