refactor(settings): collapse precedence to three categories; drop YAML tier (closes #1890)#1910
Conversation
…urce.YAML removed
…preserving fields
- CLI: rename SYNTHORG_WORKER_COUNT to SYNTHORG_WORKERS in worker start command to match the Python backend rename. - web/types/settings: drop yaml_path from SettingDefinition and 10 test/story/mock fixtures; derive SettingSource from a const tuple so the SourceBadge exhaustive-coverage test stays in lockstep. - settings/models: drop "env / YAML" wording from the read_only_post_init docstring and field description. - docs/reference/environment-variables: drop two stale "YAML layer" references in the override precedence wording. - docs/reference/configuration-precedence: replace stale service.py line citations with a code-shape reference. - mirrors / conftest / workers test: drop three RFC #1890 in-code back-references. - api/app: switch _resolve_api_int, _resolve_api_str_tuple, _resolve_rate_limiter_enabled, and the inline a2a_client_timeout resolve_init_value site to the typed parsers in settings.mirrors (parse_int, parse_float, parse_bool, parse_str_tuple_json) so a bad env value falls through to the registered default instead of crashing app construction with ValueError. - api/app: drop the duplicate _parse_str_tuple_json and _parse_bool_token helpers; reuse the canonical helpers from settings.mirrors. - auth/config, coordination/section_config, workflow/ceremony_policy: drop redundant only_if_env_set=True inline comments now that MirrorField docstring covers the three sentinel meanings. - New tests: TestRateLimitConfigMirrors (6 cases) for the RateLimitConfig._apply_mirrors path, and a dedicated test_app_bootstrap_resolvers module (11 cases) covering env-set / env-unset / env-invalid for each api.* resolver. Pre-reviewed by 20 agents; 16/16 findings addressed.
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughRemoves YAML from the settings precedence chain, formalizing DB > env > default. Introduces a bootstrap resolver and a mirrors mechanism, then applies mirrors across many configuration models. Rewires API/server/middleware and provider management to resolve settings at boot via the resolver. Updates observability setup to use the resolver. Adjusts tooling to use setting_key instead of yaml_path. Renames the workers env var to SYNTHORG_WORKERS. Updates docs, types, stories, and extensive unit/integration tests to the new contracts. Suggested labels
|
There was a problem hiding this comment.
Code Review
This pull request refactors the configuration system to a three-tier precedence model (DB > env > code default), removing the YAML layer and introducing centralized bootstrap_resolver and mirroring utilities. The review feedback identifies several opportunities to improve consistency and safety by replacing local parsing logic and direct environment reads with the new shared helpers, as well as flagging an unsafe integer cast that could lead to application crashes during startup.
| return tuple(item for item in parsed if isinstance(item, str)) | ||
|
|
||
| host = str(resolve_init_value(SettingNamespace.API, "server_host").value) | ||
| port = int(resolve_init_value(SettingNamespace.API, "server_port", parse=int).value) |
There was a problem hiding this comment.
Using the bare int constructor as a parser is unsafe here. If the environment variable SYNTHORG_API_SERVER_PORT contains an invalid integer (e.g., a typo), int() will raise a ValueError and crash the application during startup. You should use parse_int from synthorg.settings.mirrors, which catches the error and allows the resolver to gracefully fall back to the registered default.
| port = int(resolve_init_value(SettingNamespace.API, "server_port", parse=int).value) | |
| port = int(resolve_init_value(SettingNamespace.API, "server_port", parse=parse_int).value) |
| default = _extract_string(kwargs.get("default")) | ||
| read_only = _extract_bool(kwargs.get("read_only_post_init")) is True | ||
| yaml_path = _extract_string(kwargs.get("yaml_path")) or f"{namespace}.{key}" | ||
| setting_key = _extract_string(kwargs.get("setting_key")) or f"{namespace}.{key}" |
There was a problem hiding this comment.
The attempt to extract setting_key from kwargs appears to be a logic error or leftover from the yaml_path refactoring. setting_key is not a valid field on the SettingDefinition model in src/synthorg/settings/models.py, so it will never be present in the registration calls. Since the system now uses the dotted namespace.key as the unique identifier, this can be simplified to always use the default.
| setting_key = _extract_string(kwargs.get("setting_key")) or f"{namespace}.{key}" | |
| setting_key = f"{namespace}.{key}" |
| def _parse_telemetry_enabled_token(raw: str) -> bool | None: | ||
| """Parse a telemetry-enabled env token. Returns ``None`` on unknown values.""" | ||
| token = normalize_ascii_lowercase(raw) | ||
| if token in _TELEMETRY_ENV_TRUE: | ||
| return True | ||
| if token in _TELEMETRY_ENV_FALSE: | ||
| return False | ||
| return None |
| def _parse_str_tuple_json(raw: str) -> tuple[str, ...] | None: | ||
| """Parse a JSON-encoded list of strings into a tuple.""" | ||
| import json # noqa: PLC0415 | ||
|
|
||
| try: | ||
| parsed = json.loads(raw) | ||
| except json.JSONDecodeError: | ||
| return None | ||
| if not isinstance(parsed, list): | ||
| return None | ||
| if not all(isinstance(item, str) for item in parsed): | ||
| return None | ||
| return tuple(parsed) |
| def _str_tuple(key: str) -> tuple[str, ...]: | ||
| import json # noqa: PLC0415 | ||
|
|
||
| resolved = resolve_init_value(SettingNamespace.API, key) | ||
| if resolved.source == SettingSource.DEFAULT and not str(resolved.value): | ||
| return () | ||
| try: | ||
| parsed = json.loads(str(resolved.value)) | ||
| except json.JSONDecodeError: | ||
| return () | ||
| if not isinstance(parsed, list): | ||
| return () | ||
| return tuple(item for item in parsed if isinstance(item, str)) |
There was a problem hiding this comment.
This helper duplicates logic that is now centralized in synthorg.settings.mirrors.parse_str_tuple_json. Additionally, its filtering behavior (item for item in parsed if isinstance(item, str)) differs from the canonical parser which rejects the entire input if it contains non-string elements. It is better to use the shared helper for consistency.
| return explicit | ||
| env_value = os.environ.get("SYNTHORG_WORKER_COUNT") | ||
| env_value = os.environ.get("SYNTHORG_WORKERS") | ||
| if env_value is None: |
There was a problem hiding this comment.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1910 +/- ##
==========================================
+ Coverage 85.01% 85.06% +0.05%
==========================================
Files 1833 1834 +1
Lines 106984 107087 +103
Branches 9253 9237 -16
==========================================
+ Hits 90951 91098 +147
+ Misses 13799 13758 -41
+ Partials 2234 2231 -3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/synthorg/api/config.py (2)
255-280:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate
ServerConfigattribute docs to match the actual model.The docstring still lists
host,port, TLS, andtrusted_proxies, but those fields are no longer defined onServerConfig. This creates operator-facing drift and misleading generated documentation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/synthorg/api/config.py` around lines 255 - 280, The ServerConfig docstring lists attributes (host, port, ssl_certfile, ssl_keyfile, ssl_ca_certs, trusted_proxies, etc.) that no longer exist on the ServerConfig model; update the docstring in src/synthorg/api/config.py for the ServerConfig class to reflect the actual attributes defined on ServerConfig (remove obsolete host/port/TLS/trusted_proxies entries and add any current fields such as compression_minimum_size_bytes and request_max_body_size_bytes), ensuring the attribute names and brief descriptions match the model properties used by the code and generated docs.
316-321:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winRemove YAML-tier wording from
rate_limiter_enableddocs.The current text describes fallback to a “YAML field,” which reads like a precedence tier and conflicts with the three-category model introduced in this PR. Please reword to “configured/default value” language to avoid reintroducing four-tier semantics.
As per coding guidelines, “Configuration precedence: DB > env > code default via SettingsService/ConfigResolver (Cat-1) or env > code default (Cat-2, read_only_post_init); Cat-3 bootstrap secrets are pure env.”
Also applies to: 363-367
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/synthorg/api/config.py` around lines 316 - 321, Update the docstring for the rate_limiter_enabled registry entry in src/synthorg/api/config.py (the docblocks around the rate_limiter_enabled description at the current sections ~316 and ~363) to remove any mention of a “YAML field” and instead refer to a “configured/default value” or similar wording; ensure the text states the configuration precedence using the three-category model (DB > env > code default via SettingsService/ConfigResolver for Cat-1, or env > code default for Cat-2 read_only_post_init; Cat-3 bootstrap secrets are pure env) so the docs no longer imply a four-tier YAML precedence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/synthorg/settings/bootstrap_resolver.py`:
- Around line 108-117: The current code can return the raw string `default` when
a `parse` function was provided but parsing failed; instead, when `parse` is not
None and `parsed_default` is None, return a BootstrapResolvedValue with
`value=None` (or the appropriate sentinel for "no valid value") rather than the
raw `default` string so callers expecting T don't receive an invalid str; update
the branch in the resolver that handles `parse`/`parsed_default` to return
BootstrapResolvedValue(value=None, source=SettingSource.DEFAULT) (using the
existing BootstrapResolvedValue and SettingSource symbols) instead of falling
through to return the raw `default`.
In `@tests/unit/api/test_app_bootstrap_resolvers.py`:
- Around line 96-109: The test test_invalid_int_falls_through_to_default is too
loose (assert > 0); update it to assert the exact fallback value returned by
_resolve_api_int when SYNTHORG_API_COMPRESSION_MINIMUM_SIZE_BYTES is invalid by
comparing to the module's canonical default (e.g.,
DEFAULT_COMPRESSION_MINIMUM_SIZE_BYTES) instead of > 0; import that constant
from the same module that defines _resolve_api_int and replace the assertion
with equality to that constant so the test fails if the fallback default drifts.
---
Outside diff comments:
In `@src/synthorg/api/config.py`:
- Around line 255-280: The ServerConfig docstring lists attributes (host, port,
ssl_certfile, ssl_keyfile, ssl_ca_certs, trusted_proxies, etc.) that no longer
exist on the ServerConfig model; update the docstring in
src/synthorg/api/config.py for the ServerConfig class to reflect the actual
attributes defined on ServerConfig (remove obsolete
host/port/TLS/trusted_proxies entries and add any current fields such as
compression_minimum_size_bytes and request_max_body_size_bytes), ensuring the
attribute names and brief descriptions match the model properties used by the
code and generated docs.
- Around line 316-321: Update the docstring for the rate_limiter_enabled
registry entry in src/synthorg/api/config.py (the docblocks around the
rate_limiter_enabled description at the current sections ~316 and ~363) to
remove any mention of a “YAML field” and instead refer to a “configured/default
value” or similar wording; ensure the text states the configuration precedence
using the three-category model (DB > env > code default via
SettingsService/ConfigResolver for Cat-1, or env > code default for Cat-2
read_only_post_init; Cat-3 bootstrap secrets are pure env) so the docs no longer
imply a four-tier YAML precedence.
🪄 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: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1c3891f1-a350-4f54-94d9-594180bbf9dd
📒 Files selected for processing (127)
CLAUDE.mdcli/cmd/worker_start.godocs/design/providers.mddocs/guides/deployment.mddocs/guides/human-interaction.mddocs/reference/claude-reference.mddocs/reference/configuration-precedence.mddocs/reference/environment-variables.mdscripts/_setting_to_startup_trace_ghosts.pyscripts/_setting_to_startup_trace_loader.pyscripts/_setting_to_startup_trace_models.pyscripts/_setting_to_startup_trace_violations.pyscripts/check_setting_to_startup_trace.pysrc/synthorg/a2a/config.pysrc/synthorg/api/app.pysrc/synthorg/api/app_builders.pysrc/synthorg/api/auto_wire.pysrc/synthorg/api/config.pysrc/synthorg/api/middleware_factory.pysrc/synthorg/api/server.pysrc/synthorg/budget/config.pysrc/synthorg/communication/config.pysrc/synthorg/config/rate_limits.pysrc/synthorg/config/schema.pysrc/synthorg/core/auth/config.pysrc/synthorg/engine/coordination/section_config.pysrc/synthorg/engine/evolution/config.pysrc/synthorg/engine/workflow/ceremony_policy.pysrc/synthorg/integrations/config.pysrc/synthorg/memory/config.pysrc/synthorg/memory/consolidation/config.pysrc/synthorg/observability/events/settings.pysrc/synthorg/observability/setup.pysrc/synthorg/providers/management/service.pysrc/synthorg/security/autonomy/models.pysrc/synthorg/security/config.pysrc/synthorg/settings/bootstrap_resolver.pysrc/synthorg/settings/config_bridge.pysrc/synthorg/settings/definitions/a2a.pysrc/synthorg/settings/definitions/api.pysrc/synthorg/settings/definitions/budget.pysrc/synthorg/settings/definitions/client.pysrc/synthorg/settings/definitions/communication.pysrc/synthorg/settings/definitions/company.pysrc/synthorg/settings/definitions/coordination.pysrc/synthorg/settings/definitions/engine.pysrc/synthorg/settings/definitions/hr.pysrc/synthorg/settings/definitions/integrations.pysrc/synthorg/settings/definitions/memory.pysrc/synthorg/settings/definitions/meta.pysrc/synthorg/settings/definitions/notifications.pysrc/synthorg/settings/definitions/observability.pysrc/synthorg/settings/definitions/providers.pysrc/synthorg/settings/definitions/security.pysrc/synthorg/settings/definitions/settings_ns.pysrc/synthorg/settings/definitions/simulations.pysrc/synthorg/settings/definitions/telemetry.pysrc/synthorg/settings/definitions/tools.pysrc/synthorg/settings/definitions/workers.pysrc/synthorg/settings/enums.pysrc/synthorg/settings/mirrors.pysrc/synthorg/settings/models.pysrc/synthorg/settings/service.pysrc/synthorg/workers/__main__.pytests/integration/api/controllers/test_providers.pytests/integration/api/test_first_run_flow.pytests/integration/api/test_per_op_rate_limit_concurrent.pytests/integration/engine/test_coordination_wiring.pytests/integration/settings/test_settings_integration.pytests/unit/a2a/test_client.pytests/unit/api/conftest.pytests/unit/api/controllers/test_activities.pytests/unit/api/controllers/test_agents.pytests/unit/api/controllers/test_analytics.pytests/unit/api/controllers/test_company.pytests/unit/api/controllers/test_coordination.pytests/unit/api/controllers/test_departments.pytests/unit/api/controllers/test_departments_health.pytests/unit/api/controllers/test_provider_health.pytests/unit/api/services/test_org_mutations.pytests/unit/api/services/test_org_mutations_atomic.pytests/unit/api/services/test_org_mutations_toctou.pytests/unit/api/test_app.pytests/unit/api/test_app_bootstrap_resolvers.pytests/unit/api/test_config.pytests/unit/api/test_server.pytests/unit/memory/test_config.pytests/unit/providers/management/conftest.pytests/unit/providers/management/test_service_discovery.pytests/unit/scripts/_setting_to_startup_trace_helpers.pytests/unit/scripts/test_check_setting_to_startup_trace.pytests/unit/scripts/test_check_setting_to_startup_trace_baseline.pytests/unit/scripts/test_check_setting_to_startup_trace_ghosts.pytests/unit/scripts/test_check_setting_to_startup_trace_pattern_a.pytests/unit/settings/test_bootstrap_only_api_entries.pytests/unit/settings/test_bootstrap_resolver.pytests/unit/settings/test_ceremony_settings.pytests/unit/settings/test_config_bridge.pytests/unit/settings/test_definitions_config_bridge.pytests/unit/settings/test_engine_settings.pytests/unit/settings/test_mirrors.pytests/unit/settings/test_models.pytests/unit/settings/test_new_registry_entries.pytests/unit/settings/test_precedence_chain.pytests/unit/settings/test_readonly_init_settings.pytests/unit/settings/test_resolver.pytests/unit/settings/test_service.pytests/unit/settings/test_service_set_many.pytests/unit/settings/test_service_versioned_pipeline.pytests/unit/settings/test_source_resolution_log.pytests/unit/settings/test_subsystem_timeout_entries.pytests/unit/settings/test_url_port_entries.pytests/unit/workers/test_main.pyweb/src/__tests__/hooks/useSettingsData.test.tsweb/src/__tests__/pages/SettingsPage.test.tsxweb/src/__tests__/pages/settings/CodeEditorPanel.test.tsxweb/src/__tests__/pages/settings/SettingRow.test.tsxweb/src/__tests__/pages/settings/SourceBadge.test.tsxweb/src/__tests__/pages/settings/code-editor-utils.test.tsweb/src/__tests__/pages/settings/editor-autocomplete.test.tsweb/src/__tests__/pages/settings/editor-linter.test.tsweb/src/api/types/settings.tsweb/src/mocks/handlers/settings.tsweb/src/pages/settings/CodeEditorPanel.stories.tsxweb/src/pages/settings/SettingRow.stories.tsxweb/src/pages/settings/SourceBadge.stories.tsxweb/src/pages/settings/SourceBadge.tsx
💤 Files with no reviewable changes (62)
- tests/unit/settings/test_config_bridge.py
- web/src/tests/pages/settings/code-editor-utils.test.ts
- tests/unit/settings/test_models.py
- web/src/tests/pages/settings/CodeEditorPanel.test.tsx
- tests/unit/providers/management/conftest.py
- src/synthorg/settings/definitions/telemetry.py
- tests/unit/settings/test_subsystem_timeout_entries.py
- tests/integration/api/test_per_op_rate_limit_concurrent.py
- src/synthorg/settings/definitions/workers.py
- tests/unit/api/controllers/test_provider_health.py
- web/src/tests/pages/settings/editor-linter.test.ts
- src/synthorg/observability/events/settings.py
- tests/unit/settings/test_service_set_many.py
- src/synthorg/settings/definitions/company.py
- src/synthorg/settings/definitions/simulations.py
- tests/integration/api/controllers/test_providers.py
- web/src/tests/pages/settings/editor-autocomplete.test.ts
- tests/unit/settings/test_new_registry_entries.py
- src/synthorg/settings/config_bridge.py
- tests/unit/api/controllers/test_company.py
- tests/unit/settings/test_definitions_config_bridge.py
- tests/unit/api/controllers/test_agents.py
- tests/integration/engine/test_coordination_wiring.py
- src/synthorg/settings/definitions/providers.py
- tests/unit/api/controllers/test_analytics.py
- tests/unit/settings/test_url_port_entries.py
- web/src/mocks/handlers/settings.ts
- src/synthorg/settings/definitions/client.py
- tests/unit/settings/test_bootstrap_only_api_entries.py
- web/src/pages/settings/SourceBadge.tsx
- tests/unit/api/services/test_org_mutations_toctou.py
- tests/unit/settings/test_resolver.py
- tests/unit/api/controllers/test_departments_health.py
- src/synthorg/settings/definitions/a2a.py
- web/src/pages/settings/CodeEditorPanel.stories.tsx
- src/synthorg/settings/definitions/integrations.py
- tests/integration/settings/test_settings_integration.py
- src/synthorg/settings/definitions/meta.py
- tests/integration/api/test_first_run_flow.py
- tests/unit/settings/test_engine_settings.py
- tests/unit/api/services/test_org_mutations_atomic.py
- src/synthorg/a2a/config.py
- tests/unit/api/services/test_org_mutations.py
- tests/unit/api/controllers/test_coordination.py
- tests/unit/settings/test_readonly_init_settings.py
- tests/unit/api/controllers/test_activities.py
- tests/unit/settings/test_ceremony_settings.py
- src/synthorg/settings/definitions/hr.py
- tests/unit/settings/test_service_versioned_pipeline.py
- tests/unit/api/test_app.py
- src/synthorg/settings/definitions/budget.py
- src/synthorg/settings/definitions/tools.py
- src/synthorg/settings/definitions/security.py
- src/synthorg/settings/definitions/notifications.py
- src/synthorg/settings/definitions/observability.py
- src/synthorg/settings/definitions/settings_ns.py
- src/synthorg/settings/definitions/communication.py
- src/synthorg/settings/definitions/memory.py
- tests/unit/api/controllers/test_departments.py
- src/synthorg/settings/definitions/api.py
- src/synthorg/settings/definitions/engine.py
- src/synthorg/api/auto_wire.py
👮 Files not reviewed due to content moderation or server errors (8)
- src/synthorg/settings/service.py
- src/synthorg/api/app_builders.py
- src/synthorg/api/app.py
- docs/reference/configuration-precedence.md
- tests/unit/api/test_config.py
- tests/unit/settings/test_precedence_chain.py
- tests/unit/settings/test_source_resolution_log.py
- tests/unit/settings/test_service.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (13)
docs/**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
D2 for architecture/nested containers (theme 200 Dark Mauve, CLI v0.7.1 pinned in CI); mermaid for flowcharts/sequence/pipelines; markdown tables for tabular data
Files:
docs/guides/deployment.mddocs/design/providers.mddocs/guides/human-interaction.mddocs/reference/environment-variables.mddocs/reference/claude-reference.mddocs/reference/configuration-precedence.md
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Test markers: use
@pytest.mark.{unit,integration,e2e,slow}. Async auto. Timeout 30s global. Coverage 80% minWindows unit tests: use WindowsSelectorEventLoopPolicy (Python 3.14 IOCP teardown race); subprocess tests override back
Test doubles: use FakeClock for Clock seam, mock_ofT for typed-boundary substitutions, SimpleNamespace for attribute-bags. Bare MagicMock at typed boundaries is blocked by scripts/check_mock_spec.py (zero-tolerance). FakeClock and mock_of import from tests._shared
Hypothesis: 10 deterministic CI examples; failures are real bugs (fix + add
@example(...))Flaky tests: NEVER skip/xfail; fix fundamentally. Use asyncio.Event().wait() instead of sleep(large)
Files:
tests/unit/settings/test_mirrors.pytests/unit/scripts/test_check_setting_to_startup_trace_pattern_a.pytests/unit/scripts/test_check_setting_to_startup_trace_ghosts.pytests/unit/api/test_server.pytests/unit/workers/test_main.pytests/unit/memory/test_config.pytests/unit/api/conftest.pytests/unit/scripts/test_check_setting_to_startup_trace.pytests/unit/settings/test_bootstrap_resolver.pytests/unit/scripts/_setting_to_startup_trace_helpers.pytests/unit/a2a/test_client.pytests/unit/scripts/test_check_setting_to_startup_trace_baseline.pytests/unit/api/test_app_bootstrap_resolvers.pytests/unit/providers/management/test_service_discovery.pytests/unit/api/test_config.pytests/unit/settings/test_precedence_chain.pytests/unit/settings/test_source_resolution_log.pytests/unit/settings/test_service.py
⚙️ CodeRabbit configuration file
Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare
@settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which@given() honors automatically.
Files:
tests/unit/settings/test_mirrors.pytests/unit/scripts/test_check_setting_to_startup_trace_pattern_a.pytests/unit/scripts/test_check_setting_to_startup_trace_ghosts.pytests/unit/api/test_server.pytests/unit/workers/test_main.pytests/unit/memory/test_config.pytests/unit/api/conftest.pytests/unit/scripts/test_check_setting_to_startup_trace.pytests/unit/settings/test_bootstrap_resolver.pytests/unit/scripts/_setting_to_startup_trace_helpers.pytests/unit/a2a/test_client.pytests/unit/scripts/test_check_setting_to_startup_trace_baseline.pytests/unit/api/test_app_bootstrap_resolvers.pytests/unit/providers/management/test_service_discovery.pytests/unit/api/test_config.pytests/unit/settings/test_precedence_chain.pytests/unit/settings/test_source_resolution_log.pytests/unit/settings/test_service.py
cli/**/*.go
📄 CodeRabbit inference engine (cli/CLAUDE.md)
Use the appropriate hint tier based on intent:
HintErrorfor error recovery (always visible unless quiet),HintNextStepfor natural next action or destructive-action feedback,HintTipfor config automation suggestions (deduplicates within session), andHintGuidancefor flag/feature discovery (invisible in default auto mode)
Files:
cli/cmd/worker_start.go
cli/cmd/**/*.go
📄 CodeRabbit inference engine (cli/CLAUDE.md)
Exit codes: 0 = success, 1 = runtime error, 2 = usage error, 3 = unhealthy (backend/containers), 4 = unreachable (Docker), 10 = updates available (
--check)
Files:
cli/cmd/worker_start.go
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/CLAUDE.md)
web/src/**/*.{ts,tsx}: Always usecreateLoggerfrom@/lib/logger; never bareconsole.warn/console.error/console.debugin application code
Use variable namelogfor logger instances (e.g.const log = createLogger('module-name'))
Use log levels:log.debug()(DEV-only, stripped in production),log.warn(),log.error()
Pass dynamic/untrusted values as separate args to logger methods (not interpolated into the message string) so they go throughsanitizeArg
Wrap attacker-controlled fields inside structured objects withsanitizeForLog()before embedding in logs
Callers MUST NOT wrap store mutation calls intry/catch; the store owns the error UX
Use display counts fromdata.length; the wire envelope no longer carriestotal
Any new caller of health/readiness endpoints must handle the 503 path explicitly
UsesanitizeWsString()andsanitizeWsEnum()fromweb/src/utils/ws-sanitize.ts(pure helpers, re-exported from@/stores/notifications) for all WebSocket payload handling
sanitizeWsString()clamps every WS-supplied string (strips C0 controls + bidi-overrides + caps length);sanitizeWsEnum<T>(value, allowlist, fallback, { field })validates enum values and emitsws.enum.unknownwarning on unknown values
Any new WS payload handler must route throughsanitizeWsString()orsanitizeWsEnum(); raw(sanitizeWsString(x, n) ?? '') as EnumTypecasts are forbidden
Write-path features (chat, settings actions) surface aConnection limitedtoast and direct operator to reload after fixing proxy; only read surfaces are covered by SSE fallback
ImportErrorCodeandErrorCategoryfrom@/api/types/errors(re-exported from generatedweb/src/api/types/error-codes.gen.ts); discriminate onErrorCode.<NAME>, never on raw integer literals
NEVER hardcode hex colors, font-family declarations, pixel spacing, Motion transition durations, BCP 47 locale literals ('en-US'), or currency symbols / codes; use design tokens,@/lib/motionpresets...
Files:
web/src/__tests__/pages/settings/SourceBadge.test.tsxweb/src/pages/settings/SourceBadge.stories.tsxweb/src/__tests__/pages/settings/SettingRow.test.tsxweb/src/__tests__/hooks/useSettingsData.test.tsweb/src/api/types/settings.tsweb/src/__tests__/pages/SettingsPage.test.tsxweb/src/pages/settings/SettingRow.stories.tsx
web/src/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (web/CLAUDE.md)
web/src/**/*.{test,spec}.{ts,tsx}:test-setup.tsxboots withonUnhandledRequest: 'error'; tests override per-case viaserver.use(...), nevervi.mock('@/api/endpoints/*')
Every unit test runs underweb/test-infra/active-handle-tracker.ts, which fails any test that leaks an event-loop-holding resource attributable to aweb/src/frame; zero tolerance, no ceiling, no buffer
Files:
web/src/__tests__/pages/settings/SourceBadge.test.tsxweb/src/__tests__/pages/settings/SettingRow.test.tsxweb/src/__tests__/hooks/useSettingsData.test.tsweb/src/__tests__/pages/SettingsPage.test.tsx
web/src/**/*.tsx
📄 CodeRabbit inference engine (web/CLAUDE.md)
web/src/**/*.tsx: UseuseViewportSize()from@/hooks/useViewportSize(useSyncExternalStoreoverwindowresize) for viewport-size reads; never readwindow.innerWidth/window.innerHeightdirectly inside render oruseMemo
Enable@eslint-react/no-leaked-conditional-renderingto catch the{count && <Foo />}bug where0renders verbatim; forReactNode | undefinedprops use{value != null && value !== false && <jsx>}; for compound truthiness useBoolean(...)
Enable@eslint-react/globalsto restrictwindow/document/localStorage/ etc. inside render; hoist offenders into auseCallbackevent handler, auseEffect, or auseSyncExternalStore-backed hook
Files:
web/src/__tests__/pages/settings/SourceBadge.test.tsxweb/src/pages/settings/SourceBadge.stories.tsxweb/src/__tests__/pages/settings/SettingRow.test.tsxweb/src/__tests__/pages/SettingsPage.test.tsxweb/src/pages/settings/SettingRow.stories.tsx
web/**/*.{ts,tsx,jsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
Reuse Web Dashboard Design System components from
web/src/components/ui/with design tokens only (see web/CLAUDE.md)Web: reference web/CLAUDE.md for Design System details
Files:
web/src/__tests__/pages/settings/SourceBadge.test.tsxweb/src/pages/settings/SourceBadge.stories.tsxweb/src/__tests__/pages/settings/SettingRow.test.tsxweb/src/__tests__/hooks/useSettingsData.test.tsweb/src/api/types/settings.tsweb/src/__tests__/pages/SettingsPage.test.tsxweb/src/pages/settings/SettingRow.stories.tsx
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Only
src/synthorg/persistence/may import sqlite/psycopg or emit raw SQL (see docs/reference/persistence-boundary.md)Configuration precedence: DB > env > code default via SettingsService/ConfigResolver (Cat-1) or env > code default (Cat-2, read_only_post_init); Cat-3 bootstrap secrets are pure env. No os.environ.get outside startup; pre-init Cat-2 reads use settings.bootstrap_resolver.resolve_init_value (see docs/reference/configuration-precedence.md)
No hardcoded numeric values; numerics live in
settings/definitions/. Allowlist only: 0, 1, -1, HTTP codes, hex masks, powers-of-2, and module-level annotated named constants (NAME: int|float|Final|Final[int]|Final[float] = literal). Enforced by scripts/check_no_magic_numbers.pyUse Comments for WHY only; never include reviewer citations, issue back-references, or migration framing. Enforced by check_no_review_origin_in_code.py + check_no_migration_framing.py
Do not use
from __future__ import annotations(Python 3.14 has PEP 649). Use PEP 758 except:except A, B:syntax must use parentheses when bindingType hints required on public functions; strict mypy; Google-style docstrings; line length 88; functions <50 lines; files <800 lines
Error classes: use
<Domain><Condition>Errorpattern inheriting fromDomainError; never inherit directly from Exception/RuntimeError/etc. Enforced by check_domain_error_hierarchy.pyPydantic v2: use frozen + extra='forbid' on API DTOs (Request/Response/Snapshot/Result/Envelope/Status/Info/Summary suffixes); use
@computed_fieldfor derived; use NotBlankStr for identifiersArgs models required at every system boundary; use parse_typed() for every external dict ingestion. Enforced by check_boundary_typed.py
Immutability: use model_copy(update=...) or copy.deepcopy(); deepcopy at system boundaries
Async patterns: use asyncio.TaskGroup for fan-out/fan-in; helpers catch Exception and re-raise MemoryError/RecursionError
Clock seam: inject clock: Clock | None = None parameter...
Files:
src/synthorg/workers/__main__.pysrc/synthorg/api/server.pysrc/synthorg/settings/mirrors.pysrc/synthorg/security/config.pysrc/synthorg/config/schema.pysrc/synthorg/communication/config.pysrc/synthorg/settings/models.pysrc/synthorg/settings/bootstrap_resolver.pysrc/synthorg/memory/config.pysrc/synthorg/providers/management/service.pysrc/synthorg/engine/coordination/section_config.pysrc/synthorg/observability/setup.pysrc/synthorg/settings/enums.pysrc/synthorg/engine/evolution/config.pysrc/synthorg/integrations/config.pysrc/synthorg/core/auth/config.pysrc/synthorg/config/rate_limits.pysrc/synthorg/engine/workflow/ceremony_policy.pysrc/synthorg/budget/config.pysrc/synthorg/security/autonomy/models.pysrc/synthorg/settings/definitions/coordination.pysrc/synthorg/api/middleware_factory.pysrc/synthorg/memory/consolidation/config.pysrc/synthorg/settings/service.pysrc/synthorg/api/app_builders.pysrc/synthorg/api/app.pysrc/synthorg/api/config.py
src/**/*.py
⚙️ CodeRabbit configuration file
This project uses Python 3.14+ with PEP 758 except syntax: "except A, B:" (comma-separated, no parentheses) is correct and mandatory -- do NOT flag it as a typo or suggest parenthesized form. The "except builtins.MemoryError, RecursionError: raise" pattern is intentional project convention for system-error propagation. When evaluating the 50-line function limit, count only the function body excluding the signature lines, decorators, and docstring. Functions 1-5 lines over due to docstrings or multi-line signatures should not be flagged. Do not suggest extracting single-use helper functions called exactly once -- this reduces readability without improving maintainability.
Files:
src/synthorg/workers/__main__.pysrc/synthorg/api/server.pysrc/synthorg/settings/mirrors.pysrc/synthorg/security/config.pysrc/synthorg/config/schema.pysrc/synthorg/communication/config.pysrc/synthorg/settings/models.pysrc/synthorg/settings/bootstrap_resolver.pysrc/synthorg/memory/config.pysrc/synthorg/providers/management/service.pysrc/synthorg/engine/coordination/section_config.pysrc/synthorg/observability/setup.pysrc/synthorg/settings/enums.pysrc/synthorg/engine/evolution/config.pysrc/synthorg/integrations/config.pysrc/synthorg/core/auth/config.pysrc/synthorg/config/rate_limits.pysrc/synthorg/engine/workflow/ceremony_policy.pysrc/synthorg/budget/config.pysrc/synthorg/security/autonomy/models.pysrc/synthorg/settings/definitions/coordination.pysrc/synthorg/api/middleware_factory.pysrc/synthorg/memory/consolidation/config.pysrc/synthorg/settings/service.pysrc/synthorg/api/app_builders.pysrc/synthorg/api/app.pysrc/synthorg/api/config.py
web/src/pages/**/*.tsx
📄 CodeRabbit inference engine (web/CLAUDE.md)
web/src/pages/**/*.tsx: List-page primitives must use<ListHeader>/<SearchFilterSort>/<Pagination>/<BulkActionBar>/<MetadataGrid>/<Breadcrumbs>/<Collapsible>
Page root container should usespace-y-section-gap(flex flex-col gap-section-gap is equivalent but discouraged);<ErrorBanner>lands immediately after<ListHeader>, before any filter / pagination row
Pages with a one-line mission statement should pass it via<ListHeader description="..." />
Use Kanban grouping for status-flow domains where each row's column conveys lifecycle phase (Tasks, Requests); use flat scrollable list for queues without explicit phase semantics (Escalations, Approvals)
Aim for 2 or 3 breadcrumb levels max in visible trails; the dashboard's information architecture is flat (every primary domain is one sidebar click away); a 4+ level trail reflects a routing mistake
UseuseEmptyStateProps({ filteredCount, totalCount, filterActive, empty, filtered })from@/hooks/use-empty-state-propsto returnEmptyStateProps | nullinstead of duplicating "no data ever" / "no data after filter" discriminators
Files:
web/src/pages/settings/SourceBadge.stories.tsxweb/src/pages/settings/SettingRow.stories.tsx
web/src/**/*.stories.tsx
📄 CodeRabbit inference engine (web/CLAUDE.md)
Storybook 10 gotchas: ESM-only; essentials are built into core, but
@storybook/addon-docsis now separate; imports moved tostorybook/testandstorybook/actions
Files:
web/src/pages/settings/SourceBadge.stories.tsxweb/src/pages/settings/SettingRow.stories.tsx
web/src/**/*.ts
📄 CodeRabbit inference engine (web/CLAUDE.md)
Bump the WS protocol version on both client and server together for breaking payload changes; drift is enforced at pre-commit / pre-push by
scripts/check_ws_protocol_version_in_sync.py
Files:
web/src/__tests__/hooks/useSettingsData.test.tsweb/src/api/types/settings.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: Read design specification from `docs/design/` before implementing; deviations require approval (see DESIGN_SPEC.md)
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: Present every plan for accept/deny before coding
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: No region/locale privileged; use metric units and British English (see docs/reference/regional-defaults.md)
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: Every convention PR must ship its enforcement gate (see docs/reference/convention-gates.md)
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: After issue completion: branch + commit + push (no auto-PR); use `/pre-pr-review` command. After PR: use `/aurelio-review-pr` for external feedback. Fix ALL valid issues; no deferring
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: Git commits: <type>: <description> format (feat/fix/refactor/docs/test/chore/perf/ci); commitizen-enforced
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: Signed commits required on protected refs (GPG/SSH or GitHub App via synthorg-repo-bot)
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: Branches: <type>/<slug> naming from main
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: Squash merge with PR body as commit; trailers (Release-As, Closes `#N`) must be in PR body
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: GitHub queries: use 'gh issue list' via Bash, NOT MCP list_issues
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: After every squash merge: run /post-merge-cleanup
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: CLI is Docker-only (init/start/stop/status); features go in dashboard + REST API
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:14:36.839Z
Learning: CLI: reference cli/CLAUDE.md; use 'go -C cli' (never 'cd cli')
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.
Applied to files:
tests/unit/settings/test_mirrors.pysrc/synthorg/workers/__main__.pyscripts/check_setting_to_startup_trace.pysrc/synthorg/api/server.pysrc/synthorg/settings/mirrors.pytests/unit/scripts/test_check_setting_to_startup_trace_pattern_a.pysrc/synthorg/security/config.pysrc/synthorg/config/schema.pytests/unit/scripts/test_check_setting_to_startup_trace_ghosts.pytests/unit/api/test_server.pysrc/synthorg/communication/config.pytests/unit/workers/test_main.pysrc/synthorg/settings/models.pysrc/synthorg/settings/bootstrap_resolver.pysrc/synthorg/memory/config.pysrc/synthorg/providers/management/service.pysrc/synthorg/engine/coordination/section_config.pyscripts/_setting_to_startup_trace_loader.pytests/unit/memory/test_config.pytests/unit/api/conftest.pytests/unit/scripts/test_check_setting_to_startup_trace.pysrc/synthorg/observability/setup.pytests/unit/settings/test_bootstrap_resolver.pyscripts/_setting_to_startup_trace_ghosts.pytests/unit/scripts/_setting_to_startup_trace_helpers.pysrc/synthorg/settings/enums.pysrc/synthorg/engine/evolution/config.pysrc/synthorg/integrations/config.pysrc/synthorg/core/auth/config.pysrc/synthorg/config/rate_limits.pytests/unit/a2a/test_client.pysrc/synthorg/engine/workflow/ceremony_policy.pytests/unit/scripts/test_check_setting_to_startup_trace_baseline.pysrc/synthorg/budget/config.pytests/unit/api/test_app_bootstrap_resolvers.pysrc/synthorg/security/autonomy/models.pyscripts/_setting_to_startup_trace_violations.pysrc/synthorg/settings/definitions/coordination.pyscripts/_setting_to_startup_trace_models.pytests/unit/providers/management/test_service_discovery.pysrc/synthorg/api/middleware_factory.pysrc/synthorg/memory/consolidation/config.pysrc/synthorg/settings/service.pysrc/synthorg/api/app_builders.pysrc/synthorg/api/app.pytests/unit/api/test_config.pytests/unit/settings/test_precedence_chain.pytests/unit/settings/test_source_resolution_log.pytests/unit/settings/test_service.pysrc/synthorg/api/config.py
🔇 Additional comments (56)
docs/guides/deployment.md (1)
102-102: LGTM!docs/design/providers.md (1)
123-123: LGTM!tests/unit/settings/test_mirrors.py (1)
1-101: LGTM!cli/cmd/worker_start.go (1)
133-133: LGTM!Also applies to: 141-141
docs/guides/human-interaction.md (1)
212-212: LGTM!web/src/__tests__/pages/settings/SourceBadge.test.tsx (1)
2-2: LGTM!Also applies to: 40-43
docs/reference/environment-variables.md (1)
6-7: LGTM!Also applies to: 82-82, 113-115
CLAUDE.md (1)
15-15: LGTM!src/synthorg/workers/__main__.py (1)
64-65: LGTM!Also applies to: 83-84, 90-90, 107-107
scripts/check_setting_to_startup_trace.py (1)
147-148: LGTM!docs/reference/claude-reference.md (1)
59-59: LGTM!src/synthorg/api/server.py (1)
19-21: LGTM!Also applies to: 42-67, 70-72, 83-87, 90-90, 94-96, 114-115
src/synthorg/settings/mirrors.py (1)
1-152: LGTM!tests/unit/scripts/test_check_setting_to_startup_trace_pattern_a.py (1)
121-123: LGTM!Also applies to: 167-170, 262-263
src/synthorg/security/config.py (1)
9-9: LGTM!Also applies to: 22-29, 318-360, 423-427
src/synthorg/config/schema.py (1)
49-51: LGTM!Also applies to: 139-145, 160-163
tests/unit/scripts/test_check_setting_to_startup_trace_ghosts.py (1)
228-228: LGTM!Also applies to: 283-283, 336-336
tests/unit/api/test_server.py (1)
55-60: LGTM!Also applies to: 66-70, 80-87
src/synthorg/communication/config.py (1)
23-28: LGTM!Also applies to: 349-367
tests/unit/workers/test_main.py (1)
1-55: LGTM!src/synthorg/settings/models.py (1)
52-58: LGTM!Also applies to: 91-93
web/src/pages/settings/SourceBadge.stories.tsx (1)
15-25: LGTM!src/synthorg/memory/config.py (1)
225-237: LGTM!Also applies to: 285-288
src/synthorg/providers/management/service.py (1)
230-249: LGTM!Also applies to: 719-720
web/src/__tests__/pages/settings/SettingRow.test.tsx (1)
13-13: LGTM!src/synthorg/engine/coordination/section_config.py (1)
7-21: LGTM!Also applies to: 40-65, 93-97
scripts/_setting_to_startup_trace_loader.py (1)
119-119: LGTM!Also applies to: 127-127
tests/unit/memory/test_config.py (1)
230-232: LGTM!web/src/__tests__/hooks/useSettingsData.test.ts (1)
8-9: LGTM!web/src/api/types/settings.ts (1)
34-35: LGTM!tests/unit/api/conftest.py (1)
96-103: LGTM!Also applies to: 106-119, 424-427
tests/unit/scripts/test_check_setting_to_startup_trace.py (1)
60-61: LGTM!Also applies to: 89-90, 98-99, 106-106, 189-189
src/synthorg/observability/setup.py (1)
313-315: LGTM!Also applies to: 323-340
tests/unit/settings/test_bootstrap_resolver.py (1)
1-201: LGTM!scripts/_setting_to_startup_trace_ghosts.py (1)
597-597: LGTM!tests/unit/scripts/_setting_to_startup_trace_helpers.py (1)
99-100: LGTM!Also applies to: 115-116
src/synthorg/settings/enums.py (1)
66-69: LGTM!src/synthorg/engine/evolution/config.py (1)
8-8: LGTM!Also applies to: 26-29, 245-252, 265-268
src/synthorg/integrations/config.py (1)
7-7: LGTM!Also applies to: 12-17, 135-143, 151-154, 170-178, 185-188
src/synthorg/core/auth/config.py (1)
3-14: LGTM!Also applies to: 73-93, 222-225
src/synthorg/config/rate_limits.py (1)
10-22: LGTM!Also applies to: 74-91, 171-193
tests/unit/a2a/test_client.py (1)
12-14: LGTM!Also applies to: 428-430
src/synthorg/engine/workflow/ceremony_policy.py (1)
11-12: LGTM!Also applies to: 21-27, 112-139, 164-167
tests/unit/scripts/test_check_setting_to_startup_trace_baseline.py (1)
128-128: LGTM!Also applies to: 208-209, 340-345, 357-357
web/src/__tests__/pages/SettingsPage.test.tsx (1)
81-82: LGTM!src/synthorg/budget/config.py (1)
9-23: LGTM!Also applies to: 40-87, 120-155, 228-259, 314-317
tests/unit/api/test_app_bootstrap_resolvers.py (1)
1-95: LGTM!Also applies to: 111-126
src/synthorg/security/autonomy/models.py (1)
4-4: LGTM!Also applies to: 10-11, 140-147, 163-167
web/src/pages/settings/SettingRow.stories.tsx (1)
16-16: LGTM!scripts/_setting_to_startup_trace_violations.py (1)
209-209: LGTM!Also applies to: 258-258, 306-306, 391-391, 419-419, 448-448
src/synthorg/settings/definitions/coordination.py (1)
162-162: LGTM!scripts/_setting_to_startup_trace_models.py (1)
34-35: LGTM!Also applies to: 58-58, 112-113, 121-121, 130-132, 139-139
tests/unit/providers/management/test_service_discovery.py (1)
18-19: LGTM!src/synthorg/api/middleware_factory.py (1)
27-29: LGTM!Also applies to: 261-274, 276-286, 448-457
src/synthorg/memory/consolidation/config.py (1)
9-9: LGTM!Also applies to: 18-23, 323-331, 365-369
src/synthorg/api/config.py (1)
9-25: LGTM!Also applies to: 125-155, 234-238, 334-347, 395-398
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/synthorg/api/server.py`:
- Around line 43-46: The helper _str_or_none currently calls str(resolved.value)
which converts None to the string "None" and returns a truthy value; update
_str_or_none to check resolved.value for None first and return None if so,
otherwise convert to str and strip; reference the function _str_or_none and the
value resolved.value (from resolve_init_value(SettingNamespace.API, key)) so
TLS-related kwargs only become truthy when an actual non-None, non-empty string
path is present.
🪄 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: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: fc92508b-8400-42f6-b3b3-dcd483a30371
📒 Files selected for processing (5)
scripts/_setting_to_startup_trace_loader.pysrc/synthorg/api/app_builders.pysrc/synthorg/api/middleware_factory.pysrc/synthorg/api/server.pysrc/synthorg/workers/__main__.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). (1)
- GitHub Check: Test (Python 3.14)
🧰 Additional context used
📓 Path-based instructions (2)
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Only
src/synthorg/persistence/may import sqlite/psycopg or emit raw SQL; see docs/reference/persistence-boundary.mdConfiguration precedence: DB > env > code default via
SettingsService/ConfigResolver(Cat-1) or env > code default (Cat-2,read_only_post_init); Cat-3 bootstrap secrets pure env. Usesettings.bootstrap_resolver.resolve_init_valuefor pre-init Cat-2 reads. Noos.environ.getoutside startup. YAML is template ingestion format only; see docs/reference/configuration-precedence.mdNo hardcoded numeric values; numerics must live in
settings/definitions/. Allowlist: 0/1/-1, HTTP codes, hex masks, powers-of-2, module-level annotated constants (NAME: int|float|Final|Final[int]|Final[float] = literal). Enforced byscripts/check_no_magic_numbers.pyComments should explain WHY only; no reviewer citations / issue back-refs / migration framing. Enforced by
check_no_review_origin_in_code.py+check_no_migration_framing.pyNo
from __future__ import annotations(Python 3.14+ has PEP 649). PEP 758 except:except A, B:no parens unless bindingType hints required on public functions; mypy strict. Google-style docstrings. Line length 88; functions <50 lines; files <800 lines
Errors must follow
<Domain><Condition>Errorpattern and inherit fromDomainError, never directly fromException/RuntimeError/etc. Enforced bycheck_domain_error_hierarchy.pyPydantic v2: use frozen +
extra="forbid"on API DTOs (Request/Response/Snapshot/Result/Envelope/Status/Info/Summary suffixes);@computed_fieldfor derived;NotBlankStrfor identifiersArgs models required at every system boundary; use
parse_typed()for every external dict ingestion. Enforced bycheck_boundary_typed.pyImmutability: use
model_copy(update=...)orcopy.deepcopy(); deepcopy at system boundariesAsync: use
asyncio.TaskGroupfor fan-out/fan-in; helpers catchException(re-raiseMemoryError/RecursionError)Clock seam: inject
clock: Clock | None = None; ...
Files:
src/synthorg/api/middleware_factory.pysrc/synthorg/api/server.pysrc/synthorg/workers/__main__.pysrc/synthorg/api/app_builders.py
src/**/*.py
⚙️ CodeRabbit configuration file
This project uses Python 3.14+ with PEP 758 except syntax: "except A, B:" (comma-separated, no parentheses) is correct and mandatory -- do NOT flag it as a typo or suggest parenthesized form. The "except builtins.MemoryError, RecursionError: raise" pattern is intentional project convention for system-error propagation. When evaluating the 50-line function limit, count only the function body excluding the signature lines, decorators, and docstring. Functions 1-5 lines over due to docstrings or multi-line signatures should not be flagged. Do not suggest extracting single-use helper functions called exactly once -- this reduces readability without improving maintainability.
Files:
src/synthorg/api/middleware_factory.pysrc/synthorg/api/server.pysrc/synthorg/workers/__main__.pysrc/synthorg/api/app_builders.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Read `docs/design/` page before implementing; deviations need approval per DESIGN_SPEC.md
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Present every plan for accept/deny before coding
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: No region/currency/locale privileged; use metric units and British English; see docs/reference/regional-defaults.md
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Every convention PR must ship its enforcement gate; see docs/reference/convention-gates.md
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Never edit `tests/baselines/unit_timing.json` or any `scripts/*_baseline.{txt,json}` / `scripts/_*_baseline.py`; timeout/slow failures indicate source-code regression. PreToolUse-blocked. Per-invocation bypass: `ALLOW_BASELINE_GROWTH=1 git commit ...` requires explicit user approval
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: After issue: branch + commit + push (no auto-PR); use `/pre-pr-review`. After PR: use `/aurelio-review-pr` for external feedback. Fix everything valid; no deferring
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: xdist: apply `-n 8 --dist=loadfile` auto via pyproject addopts (`loadfile` prevents 3.14+Windows ProactorEventLoop leak)
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Git commits: `<type>: <description>` format (feat/fix/refactor/docs/test/chore/perf/ci); commitizen-enforced
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Signed commits required on protected refs (GPG/SSH or GitHub App via `synthorg-repo-bot`)
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Branches: `<type>/<slug>` from main
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Pre-commit/pre-push hooks: use `.pre-commit-config.yaml`. Hookify rules: `.claude/hookify.*.md`
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Squash merge. PR body becomes squash commit; trailers (`Release-As`, `Closes `#N``) must be in PR body
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: GitHub queries: use `gh issue list` via Bash, NOT MCP `list_issues`
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: After every squash merge → run `/post-merge-cleanup`
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: CLI is Docker-only (init/start/stop/status); features go in dashboard + REST API
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:36:39.050Z
Learning: Web: see `web/CLAUDE.md`. CLI: see `cli/CLAUDE.md` (use `go -C cli`, never `cd cli`). Shell: see `~/.claude/rules/common/bash.md`
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.
Applied to files:
scripts/_setting_to_startup_trace_loader.pysrc/synthorg/api/middleware_factory.pysrc/synthorg/api/server.pysrc/synthorg/workers/__main__.pysrc/synthorg/api/app_builders.py
🔇 Additional comments (4)
src/synthorg/workers/__main__.py (1)
27-29: LGTM!Also applies to: 52-57, 71-71, 90-107, 118-118
src/synthorg/api/middleware_factory.py (1)
27-30: LGTM!Also applies to: 262-265, 271-272, 434-443
scripts/_setting_to_startup_trace_loader.py (1)
119-120: LGTM!Also applies to: 127-127
src/synthorg/api/app_builders.py (1)
20-23: LGTM!Also applies to: 56-59, 63-67, 280-287, 293-327
| def _str_or_none(key: str) -> str | None: | ||
| resolved = resolve_init_value(SettingNamespace.API, key) | ||
| raw = str(resolved.value).strip() | ||
| return raw or None |
There was a problem hiding this comment.
Handle None in _str_or_none before string conversion.
On Line 45, str(resolved.value) turns None into "None", which is truthy and can incorrectly enable TLS kwargs with invalid paths.
Proposed fix
def _str_or_none(key: str) -> str | None:
resolved = resolve_init_value(SettingNamespace.API, key)
- raw = str(resolved.value).strip()
+ if resolved.value is None:
+ return None
+ raw = str(resolved.value).strip()
return raw or None🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/synthorg/api/server.py` around lines 43 - 46, The helper _str_or_none
currently calls str(resolved.value) which converts None to the string "None" and
returns a truthy value; update _str_or_none to check resolved.value for None
first and return None if so, otherwise convert to str and strip; reference the
function _str_or_none and the value resolved.value (from
resolve_init_value(SettingNamespace.API, key)) so TLS-related kwargs only become
truthy when an actual non-None, non-empty string path is present.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/synthorg/settings/bootstrap_resolver.py`:
- Around line 83-85: The code raises SettingNotFoundError (in the block checking
"if definition is None") and other bootstrap exceptions later (lines 111-122)
without logging; before each raise, call the module's logger (e.g.
logger.warning or logger.error) to emit a structured message that includes the
namespace and key (and any relevant registry/default info) and include exception
context (e.g. exc_info=True or the error details) so startup diagnostics are
preserved; update the code paths that raise SettingNotFoundError and the other
bootstrap exception raises in this module to log with appropriate level and
context immediately before raising.
🪄 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: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1a9a7337-91be-483f-b66d-6fa1d83a3fbf
📒 Files selected for processing (3)
src/synthorg/api/config.pysrc/synthorg/settings/bootstrap_resolver.pytests/unit/api/test_app_bootstrap_resolvers.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). (9)
- GitHub Check: Build Backend
- GitHub Check: CLI Bench Regression
- GitHub Check: CLI Test (windows-latest)
- GitHub Check: Dashboard Test
- GitHub Check: Test (Python 3.14)
- GitHub Check: Lighthouse Dashboard
- GitHub Check: Lighthouse Site
- GitHub Check: Build Web Assets (melange)
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
src/synthorg/!(persistence)/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Only
src/synthorg/persistence/may import sqlite/psycopg or emit raw SQL; all other modules must use abstraction boundary
Files:
src/synthorg/settings/bootstrap_resolver.pysrc/synthorg/api/config.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use configuration precedence: DB > env > code default via
SettingsService/ConfigResolver(Cat-1), or env > code default (Cat-2 withread_only_post_init); Cat-3 bootstrap secrets use pure env at boot site. YAML is company-template ingestion only, not a precedence tier. Never useos.environ.getoutside startup; pre-init Cat-2 reads usesettings.bootstrap_resolver.resolve_init_valueNo hardcoded numeric values; store numerics in
settings/definitions/. Allow only: 0, 1, -1, HTTP codes, hex masks, powers-of-2, and module-level annotated named constants (NAME: int|float|Final|Final[int]|Final[float] = literal). Enforced byscripts/check_no_magic_numbers.pyCode comments must explain WHY only; never include reviewer citations, issue back-references, or migration framing. Enforced by
check_no_review_origin_in_code.pyandcheck_no_migration_framing.pyDo not use
from __future__ import annotations(Python 3.14 has PEP 649). Use PEP 758 except:except A, B:without parens unless bindingAdd type hints to all public functions; use mypy strict mode. Use Google-style docstrings. Maximum line length 88; functions <50 lines; files <800 lines
Define errors as
<Domain><Condition>Errorinheriting fromDomainError, never directly fromException/RuntimeError/etc. Enforced bycheck_domain_error_hierarchy.pyUse Pydantic v2 with frozen=True and extra='forbid' on API DTOs (Request/Response/Snapshot/Result/Envelope/Status/Info/Summary suffixes); use
@computed_fieldfor derived values; use NotBlankStr for identifiersUse args models at every system boundary; apply
parse_typed()for every external dict ingestion. Enforced bycheck_boundary_typed.pyEnforce immutability: use
model_copy(update=...)orcopy.deepcopy(); apply deepcopy at system boundariesUse
asyncio.TaskGroupfor async fan-out/fan-in operations; helper functions must catchExceptionand re-raiseMemoryError/RecursionErrorImplement Clock seam as `clock: Clock | None = N...
Files:
src/synthorg/settings/bootstrap_resolver.pysrc/synthorg/api/config.py
src/**/*.py
⚙️ CodeRabbit configuration file
This project uses Python 3.14+ with PEP 758 except syntax: "except A, B:" (comma-separated, no parentheses) is correct and mandatory -- do NOT flag it as a typo or suggest parenthesized form. The "except builtins.MemoryError, RecursionError: raise" pattern is intentional project convention for system-error propagation. When evaluating the 50-line function limit, count only the function body excluding the signature lines, decorators, and docstring. Functions 1-5 lines over due to docstrings or multi-line signatures should not be flagged. Do not suggest extracting single-use helper functions called exactly once -- this reduces readability without improving maintainability.
Files:
src/synthorg/settings/bootstrap_resolver.pysrc/synthorg/api/config.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Mark tests with
@pytest.mark.{unit,integration,e2e,slow}. Use async auto. Global timeout 30s. Coverage minimum 80%. xdist applies-n 8 --dist=loadfilevia pyproject addopts (loadfile prevents 3.14+ Windows ProactorEventLoop leak)Windows test policy: unit tests use
WindowsSelectorEventLoopPolicy(3.14 IOCP teardown race); subprocess tests override backTest doubles ladder (in order): FakeClock for Clock seam,
mock_of[T](**overrides)for typed-boundary substitutions,SimpleNamespacefor attribute-bags. Never bareMagicMockat typed boundaries (constructor/fn arg/annotated local/typed fixture return). Blocked byscripts/check_mock_spec.pywith zero tolerance. Import FakeClock andmock_offromtests._sharedHypothesis: 10 deterministic CI examples; failures are real bugs (fix + add
@example(...))Never skip or xfail flaky tests; fix fundamentally. Use
asyncio.Event().wait()instead ofsleep(large)
Files:
tests/unit/api/test_app_bootstrap_resolvers.py
⚙️ CodeRabbit configuration file
Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare
@settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which@given() honors automatically.
Files:
tests/unit/api/test_app_bootstrap_resolvers.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: Read design specification from `docs/design/` page before implementing; deviations require approval. See DESIGN_SPEC.md
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: Present every plan for accept/deny before coding
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: No region/currency/locale privileged; use metric units; use British English in documentation and code comments
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: Every convention PR must ship its enforcement gate
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: Timeout/slow test failures indicate source-code regression; never edit `tests/baselines/unit_timing.json`, `scripts/*_baseline.{txt,json}`, or `scripts/_*_baseline.py`. Both families are PreToolUse-blocked. Per-invocation bypass requires `ALLOW_BASELINE_GROWTH=1 git commit ...` with explicit user approval
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: After issue completion: create branch, commit, and push (no auto-PR); use `/pre-pr-review` command. After PR creation: use `/aurelio-review-pr` for external feedback. Fix everything valid from reviews; do not defer
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: Git commits use format `<type>: <description>` (feat/fix/refactor/docs/test/chore/perf/ci); enforced by commitizen. Branches use format `<type>/<slug>` from main. Signed commits required on protected refs. Squash merge with PR body as squash commit message; trailers (`Release-As`, `Closes `#N``) must be in PR body
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: Pre-commit/pre-push hooks defined in `.pre-commit-config.yaml`. Hookify rules in `.claude/hookify.*.md`
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: After every squash merge, run `/post-merge-cleanup`
Learnt from: CR
Repo: Aureliolo/synthorg
Timestamp: 2026-05-14T20:54:12.670Z
Learning: CLI features are Docker-only (init/start/stop/status); new features go in dashboard and REST API, not CLI
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.
Applied to files:
src/synthorg/settings/bootstrap_resolver.pytests/unit/api/test_app_bootstrap_resolvers.pysrc/synthorg/api/config.py
🔇 Additional comments (5)
src/synthorg/api/config.py (4)
9-9: LGTM!Also applies to: 18-25
125-155: LGTM!Also applies to: 234-238
255-260: LGTM!
307-308: LGTM!Also applies to: 321-334, 353-354, 382-385
tests/unit/api/test_app_bootstrap_resolvers.py (1)
20-132: LGTM!
<!-- HIGHLIGHTS_START --> ## Highlights > _AI-generated summary (model: `openai/gpt-4.1-mini` via GitHub Models). Commit-based changelog below._ ### What you'll notice - Frontend WP-6 update with UX polish improves user interface and workflow. - Dashboard and training endpoint improvements enhance observability and dispatch behavior. - Web storybook now supports change detection for more responsive UI interactions. - Git hooks now isolated per worktree for cleaner repository management. - Providers automatically detect native streaming support in Litellm models. ### What's new - Added a new pipeline to convert Pydantic DTOs to TypeScript for better front-end compatibility. ### Under the hood - Refactored settings to three precedence categories, removing YAML tier for simpler configuration. - Completed RootConfig mirror coverage for enhanced configuration consistency. - Adopted API conventions with better query performance and forbidden extra fields for stricter validation. - Improved persistence, layer discipline, and restart safety in core work packages. - CI updated with split test jobs and tightened coverage gates for better test quality. - Switched to direct Trivy binary for security scans, removing previous Trivy action dependency. - Enhanced memory management with per-call processing options and better observability during speech-to-text encoding. - Various dependency updates for Python, infrastructure, and lock files maintain security and stability. - Removed TypeScript DTO type-tightening overlays to simplify type management. - Codebase audit tightened skill sets to prevent false positivity in class detection by 2026. <!-- HIGHLIGHTS_END --> :robot: I have created a release *beep* *boop* --- ## [0.8.5](v0.8.4...v0.8.5) (2026-05-17) ### Features * **codegen:** pydantic-to-typescript DTO pipeline + parity gate (closes [#1889](#1889)) ([#1909](#1909)) ([0265ef5](0265ef5)) * **storybook:** enable changeDetection + trim web/CLAUDE.md ([#1939](#1939)) ([3b1f4c0](3b1f4c0)) * **web,setup:** WP-6 frontend + UX polish ([#1941](#1941)) ([d9ca76d](d9ca76d)) ### Bug Fixes * correct invalid git for-each-ref syntax in post-merge-cleanup skill ([#1946](#1946)) ([69a1649](69a1649)) * dashboard polish, training endpoint dispatch, and observability cleanup ([#1911](#1911)) ([b61e9e8](b61e9e8)) * per-worktree git-hook isolation + hookify gate migration + MSW drift fix ([#1949](#1949)) ([e3f8495](e3f8495)) * **providers:** read supports_native_streaming from litellm model info ([#1942](#1942)) ([60364ca](60364ca)) * security and audit coverage (closes [#1883](#1883)) ([#1904](#1904)) ([d8ebf55](d8ebf55)) ### Performance * **ci:** mypy --num-workers=4 + enable ruff TID255 ([#1944](#1944)) ([484c1d3](484c1d3)) ### Refactoring * **ci:** drop aquasecurity/trivy-action, use direct trivy binary ([#1940](#1940)) ([df1f946](df1f946)) * **memory:** per-call processing_kwargs + observability for ST encode ([#1943](#1943)) ([3aa9d20](3aa9d20)) * Phase 7 follow-up — complete RootConfig mirror coverage (closes [#1907](#1907)) ([#1914](#1914)) ([605500b](605500b)) * **settings:** collapse precedence to three categories; drop YAML tier (closes [#1890](#1890)) ([#1910](#1910)) ([efd54c9](efd54c9)) * WP-3 API conventions + query performance + project-wide extra=forbid ([#1953](#1953)) ([504d579](504d579)), closes [#1918](#1918) * WP-4 settings + cross-cutting (clock seam, contextvars, dispatch, plugin surfaces) ([#1954](#1954)) ([7207d92](7207d92)) * **wp1:** persistence + layer discipline + restart safety ([#1945](#1945)) ([57586fb](57586fb)) ### Documentation * **wp5:** public-facing truth refresh ([#1924](#1924)) ([afb5cc5](afb5cc5)) ### CI/CD * split test job by marker with airtight aggregate coverage gate ([#1948](#1948)) ([0b818d5](0b818d5)), closes [#1938](#1938) [#1937](#1937) ### Maintenance * **codebase-audit:** tighten skill to prevent 2026-05-15 FP classes ([#1923](#1923)) ([9317ed1](9317ed1)) * Lock file maintenance ([#1913](#1913)) ([c08a355](c08a355)) * Lock file maintenance ([#1950](#1950)) ([8940ab1](8940ab1)) * remove TS DTO type-tightening overlays ([#1915](#1915)) ([d296214](d296214)), closes [#1906](#1906) * Update Infrastructure dependencies ([#1928](#1928)) ([d19fae5](d19fae5)) * Update Python dependencies ([#1929](#1929)) ([75cc2c8](75cc2c8)) * **wp7:** hygiene, stubs, test/CI/tooling, doc gaps, boundary patterns doc ([#1926](#1926)) ([c29eb32](c29eb32)) --- 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: synthorg-repo-bot[bot] <279117679+synthorg-repo-bot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Closes #1890.
Summary
Resolves the four-tier
DB > env > YAML > defaultlie that the docs had advertised for a long time. The codebase actually exhibits three categories:DB > env > defaultviaSettingsService/ConfigResolver.env > defaultonly; DB is bypassed (read_only_post_init=True). Examples:api.server_port,communication.nats_url,workers.count.SYNTHORG_DATABASE_URL,SYNTHORG_JWT_SECRET,SYNTHORG_CONFIG_PATH,SYNTHORG_DB_PATH.What changes
src/synthorg/settings/bootstrap_resolver.py(new): canonical pre-init resolver for Cat-2 reads. ReturnsBootstrapResolvedValue[T]withsource ∈ {ENVIRONMENT, DEFAULT}.src/synthorg/settings/mirrors.py(new):MirrorFielddataclass +apply_settings_mirrorsPydantic validator helper, plus typed parsers (parse_bool,parse_int,parse_float,parse_str_tuple_json). Applied across 15+ config families (ApiConfig, AuthConfig, RateLimitConfig, BudgetConfig, AutonomyConfig, CoordinationSectionConfig, CeremonyPolicyConfig, ConsolidationConfig, MeetingsConfig, OAuthConfig, WebhooksConfig, etc.) to eliminate duplicate env reads while keeping Pydantic-tier defaults in sync with the registry.SettingSource.YAMLremoved;SettingDefinition.yaml_pathremoved (221 call sites cleaned). YAML is now a company-template ingestion format, not a precedence tier.ServerConfig/CorsConfigmirror fields stripped; values flow throughbootstrap_resolver.resolve_init_valueat boot.SYNTHORG_WORKER_COUNTrenamed toSYNTHORG_WORKERS(Python + Go CLI).docs/reference/configuration-precedence.mdrewritten to document the three categories with examples and rationale.CLAUDE.mdMANDATORY one-liner updated.scripts/check_setting_to_startup_trace.py(ghost-wiring detector, mirrors the persistence-boundary gate pattern).Test plan
uv run ruff check src/ tests/clean.uv run mypy src/ tests/clean (3791 files).test_heartbeat_repository[sqlite]which passes in isolation; no code overlap with this PR).tests/unit/settings/(627 tests),tests/unit/api/test_app.py,tests/unit/api/test_app_bootstrap_resolvers.py(new),tests/unit/api/test_config.py(with newTestRateLimitConfigMirrors),tests/unit/workers/test_main.py.go -C cli vet ./...+go -C cli test ./cmd/...clean.Review coverage
Pre-reviewed by 20 local agents (full roster plus 5 mini-pass audit agents). Triage filed at
_audit/pre-pr-review/triage.md. All 16 actionable findings (3 CRITICAL / 9 MAJOR / 4 MEDIUM) addressed in this PR; security / persistence / async-concurrency / logging / conventions / mini-pass agents reported clean.Highlights of fixes applied during the pre-PR pass:
SYNTHORG_WORKER_COUNTrename was missed; now matches Python backend.web/src/api/types/settings.tsstill declaredyaml_pathafter the backend dropped it; stripped from the type and from 10 test/story/mock fixtures._resolve_api_int/a2a_client_timeout/_resolve_api_str_tuplepassed bareint/float/_parse_str_tuple_jsontoresolve_init_value; bad env input would have crashed app construction withValueError. Switched to the typed parsers insettings.mirrorsso invalid env values fall through to the registered default._parse_bool_token/_parse_str_tuple_jsonhelpers fromapi/app.pyin favour of the canonical helpers insettings.mirrors.RFC #1890in-code back-references (mirrors module docstring + two test docstrings).settings/models.pydocstring,docs/reference/environment-variables.md, anddocs/reference/configuration-precedence.md.TestRateLimitConfigMirrors(6 cases) +test_app_bootstrap_resolvers.py(11 cases) covering env-set / env-unset / env-invalid for each resolver.Run
/aurelio-review-prafter external reviewers (CodeRabbit) provide feedback.