feat: add control-plane API endpoints batch (#1118, #1119, #1120, #1121)#1138
feat: add control-plane API endpoints batch (#1118, #1119, #1120, #1121)#1138
Conversation
|
Caution Review failedPull request was closed or merged during review WalkthroughAdds control-plane query endpoints and supporting infrastructure: GET /api/v1/agents/{name}/health, GET /api/v1/security/audit, GET /api/v1/coordination/metrics, GET /api/v1/settings/security/export, and POST /api/v1/settings/security/import. Introduces AuditController and CoordinationMetricsController, new Pydantic request/response models and TypeScript types, a CoordinationMetricsRecord and in-memory CoordinationMetricsStore, new observability event constants, and extended AuditLog.query filtering. AppState and create_app accept/inject audit_log, trust_service, and coordination_metrics_store. Tests and documentation were added or updated to cover the new APIs and metrics. 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning Review ran into problems🔥 ProblemsTimed out fetching pipeline failures after 30000ms Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches. Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
There was a problem hiding this comment.
Code Review
This pull request implements several control-plane API endpoints to close existing design gaps, including a per-agent health endpoint, security audit log querying, coordination metrics access, and security configuration export/import. It introduces new controllers, data stores, and Pydantic models to support these features, along with corresponding unit tests and documentation updates. Feedback is provided regarding the increasing complexity of the application factory and the audit log query logic, suggesting refactoring into helper functions or predicate-based filtering to improve maintainability.
|
|
||
|
|
||
| def create_app( # noqa: PLR0913, PLR0915 | ||
| def create_app( # noqa: C901, PLR0913, PLR0915 |
There was a problem hiding this comment.
This function has grown quite complex, as indicated by the noqa: C901. To improve maintainability, consider refactoring it by extracting parts of the setup logic into smaller, dedicated helper functions. For example, you could have helpers for:
- Auto-wiring services (
_auto_wire_services) - Building the
AppState(_build_app_state)
The existing _build_middleware and _build_lifecycle helpers are a great example of this pattern.
src/synthorg/security/audit.py
Outdated
| return self._total_recorded | ||
|
|
||
| def query( # noqa: PLR0913 | ||
| def query( # noqa: C901, PLR0913 |
There was a problem hiding this comment.
The query method's complexity is increasing with each new filter, as noted by the noqa: C901. To make it more maintainable and easier to add new filters in the future, you could refactor the filtering logic. Instead of a chain of if statements, you could dynamically build a list of filter predicates.
Here's an example of how that might look:
predicates = []
if agent_id is not None:
predicates.append(lambda e: e.agent_id == agent_id)
if tool_name is not None:
predicates.append(lambda e: e.tool_name == tool_name)
# ... add other filters
results = []
for entry in reversed(self._entries):
if all(p(entry) for p in predicates):
results.append(entry)
if len(results) >= limit:
break
return tuple(results)This approach keeps the main loop clean and separates the filter conditions.
There was a problem hiding this comment.
Pull request overview
Adds a batch of “control-plane” API capabilities (agent health, security config export/import, coordination metrics query, and security audit log query) plus supporting state wiring, in-memory stores, event constants, frontend types, and test coverage.
Changes:
- Added new control-plane endpoints:
GET /agents/{name}/health,GET/POST /settings/security/export|import,GET /coordination/metrics,GET /security/audit. - Introduced in-memory
CoordinationMetricsStore, expandedAuditLogfiltering, and wired new services into API app state. - Added/updated unit tests, docs references, and frontend TypeScript API types for the new response models.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| web/src/api/types.ts | Adds TS types for new control-plane response models (health, audit, metrics, security export). |
| tests/unit/security/test_audit.py | Adds unit tests for new AuditLog query filters (until, action_type). |
| tests/unit/budget/test_coordination_store.py | Adds unit tests for CoordinationMetricsStore behavior (filtering, ordering, eviction). |
| tests/unit/api/controllers/test_settings.py | Adds controller tests for security config export/import endpoints. |
| tests/unit/api/controllers/test_coordination_metrics.py | Adds controller tests for coordination metrics query (filters, pagination, surfacing fields). |
| tests/unit/api/controllers/test_audit.py | Adds controller tests for audit query endpoint (filters, pagination). |
| tests/unit/api/controllers/test_agents.py | Adds tests for agent health endpoint and related helper/model validation. |
| tests/unit/api/conftest.py | Wires new fixtures/services into test app creation (audit log, trust service, metrics store). |
| src/synthorg/security/audit.py | Extends in-memory audit log querying with action_type and until filters. |
| src/synthorg/observability/events/api.py | Adds new API event constants for control-plane endpoints. |
| src/synthorg/engine/agent_engine.py | Allows injecting a shared AuditLog into AgentEngine. |
| src/synthorg/budget/coordination_store.py | Adds new in-memory ring-buffer store for coordination metrics with filtered query support. |
| src/synthorg/api/state.py | Adds new app-state properties for audit_log, trust_service, and coordination_metrics_store. |
| src/synthorg/api/controllers/settings.py | Adds security config export/import endpoints and request/response models. |
| src/synthorg/api/controllers/coordination_metrics.py | Adds new controller for querying coordination metrics with pagination. |
| src/synthorg/api/controllers/audit.py | Adds new controller for querying audit log entries with pagination. |
| src/synthorg/api/controllers/agents.py | Adds agent health endpoint and supporting models/helper for quality trend extraction. |
| src/synthorg/api/controllers/init.py | Registers the new audit and coordination metrics controllers. |
| src/synthorg/api/app.py | Wires new services into app creation and auto-wires some defaults. |
| docs/design/page-structure.md | Documents new endpoints in page structure docs. |
| docs/design/operations.md | Marks control-plane audit gaps G2–G5 as implemented. |
| CLAUDE.md | Updates logging/event-constant guidance with new API event constants. |
Comments suppressed due to low confidence (1)
src/synthorg/security/audit.py:116
- With the new
since/untilfilters,AuditLog.query()should validateuntil >= since(and raise a client-facing error) to match the persistence-backed audit repository behavior (sqlite/audit_repository.pyraises whenuntil < since). Currently,until < sincesilently returns an empty result set, which is inconsistent across backends and can hide input bugs.
action_type: str | None = None,
since: AwareDatetime | None = None,
until: AwareDatetime | None = None,
limit: int = 100,
) -> tuple[AuditEntry, ...]:
"""Query audit entries with optional filters.
Filters are AND-combined. Results are returned newest-first,
up to *limit* entries.
Args:
agent_id: Filter by agent ID.
tool_name: Filter by tool name.
verdict: Filter by verdict string.
risk_level: Filter by risk level.
action_type: Filter by action type string.
since: Entries before this datetime are excluded.
until: Entries after this datetime are excluded.
limit: Maximum results to return (must be >= 1).
Returns:
Tuple of matching entries, newest first.
Raises:
ValueError: If *limit* < 1.
"""
if limit < 1:
msg = f"limit must be >= 1, got {limit}"
logger.warning(
SECURITY_AUDIT_CONFIG_ERROR,
error=msg,
)
raise ValueError(msg)
results: list[AuditEntry] = []
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
web/src/api/types.ts
Outdated
| | 'file_operations' | ||
| | 'external_api' | ||
| | 'git_operations' | ||
| | 'code_execution' | ||
| | 'data_analysis' | ||
| | 'communication' | ||
| | 'research' | ||
| | 'admin' | ||
| | 'unknown' |
There was a problem hiding this comment.
ToolCategory here does not match the backend enum values returned by the API. The Python synthorg.core.enums.ToolCategory uses values like file_system, version_control, web, database, terminal, deployment, mcp, other, etc., while this TS union lists file_operations, git_operations, external_api, unknown, etc. This makes the generated AuditEntry.tool_category type incorrect and can break frontend type-checking/handling for real responses. Align this union with the backend enum values (or reuse an existing shared mapping if the frontend intentionally renames categories).
| | 'file_operations' | |
| | 'external_api' | |
| | 'git_operations' | |
| | 'code_execution' | |
| | 'data_analysis' | |
| | 'communication' | |
| | 'research' | |
| | 'admin' | |
| | 'unknown' | |
| | 'file_system' | |
| | 'version_control' | |
| | 'web' | |
| | 'database' | |
| | 'terminal' | |
| | 'deployment' | |
| | 'mcp' | |
| | 'other' |
| agent_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, | ||
| tool_name: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, | ||
| action_type: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | ||
| | None = None, | ||
| verdict: Annotated[str, Parameter(max_length=50)] | None = None, | ||
| since: datetime | None = None, | ||
| until: datetime | None = None, | ||
| offset: PaginationOffset = 0, | ||
| limit: PaginationLimit = 50, |
There was a problem hiding this comment.
since/until are typed as datetime (which allows naive timestamps). If a client passes a timestamp without timezone, Litestar will parse a naive datetime, and AuditLog.query() compares it against AuditEntry.timestamp (an AwareDatetime), which will raise TypeError: can't compare offset-naive and offset-aware datetimes. Consider using pydantic.AwareDatetime for these query params (or explicitly normalizing/rejecting naive datetimes) before calling the audit log.
| task_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, | ||
| agent_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, | ||
| since: datetime | None = None, | ||
| until: datetime | None = None, | ||
| offset: PaginationOffset = 0, | ||
| limit: PaginationLimit = 50, |
There was a problem hiding this comment.
Same timezone-awareness issue as the audit controller: since/until accept naive datetime values, but CoordinationMetricsStore.query() expects AwareDatetime and will compare against computed_at (aware). A naive query timestamp will trigger a runtime TypeError during comparison. Prefer pydantic.AwareDatetime for these query params (or validate/normalize to UTC) to prevent 500s on user input.
| # Auto-wire control-plane services when not injected. | ||
| if audit_log is None: | ||
| audit_log = AuditLog() | ||
| if coordination_metrics_store is None: | ||
| coordination_metrics_store = CoordinationMetricsStore() | ||
|
|
There was a problem hiding this comment.
create_app() auto-wires audit_log and coordination_metrics_store when not injected, but leaves trust_service as None. The new GET /agents/{name}/health endpoint unconditionally accesses app_state.trust_service, which will raise ServiceUnavailableError (503) if trust_service isn't provided. Either auto-wire a default TrustService here (e.g., disabled/no-op strategy) or ensure the health endpoint degrades gracefully when trust is not configured.
| trust_state = app_state.trust_service.get_trust_state( | ||
| agent_id, | ||
| ) | ||
| trust = ( | ||
| TrustSummary( | ||
| level=trust_state.global_level, | ||
| score=trust_state.trust_score, | ||
| last_evaluated_at=trust_state.last_evaluated_at, | ||
| ) | ||
| if trust_state is not None | ||
| else None | ||
| ) |
There was a problem hiding this comment.
get_agent_health() calls app_state.trust_service.get_trust_state(...) without checking whether the trust service is configured. Because AppState.trust_service raises 503 when unset, this endpoint will fail unless trust_service is always wired. If trust is optional, gate this with app_state.has_trust_service and return trust=None when unavailable (mirroring the docstring/test intent of returning None when not tracked).
| ) | ||
| team_size: int = Field(gt=0, description="Coordinating agents") | ||
| metrics: CoordinationMetrics = Field( | ||
| description="All nine Kim et al. metrics (None when skipped)", |
There was a problem hiding this comment.
The metrics field is typed as non-optional CoordinationMetrics, but the field description says it is "None when skipped". Either make the type optional (if None is a real state) or update the description to reflect the actual contract.
| description="All nine Kim et al. metrics (None when skipped)", | |
| description="All nine Kim et al. coordination metrics", |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1138 +/- ##
==========================================
+ Coverage 88.96% 88.98% +0.01%
==========================================
Files 848 851 +3
Lines 49388 49633 +245
Branches 4960 4977 +17
==========================================
+ Hits 43939 44164 +225
- Misses 4520 4533 +13
- Partials 929 936 +7 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 13
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/design/operations.md`:
- Line 1839: Update the G3 row wording to resolve the conflict between
"validate-only" and objective `#1119`: either change the `POST
/settings/security/import` description to state that imports perform atomic
persistence per `#1119`, or explicitly document the approved deviation and
rationale (including why validate-only was chosen and planned timeline for
persistence). Also ensure `GET /settings/security/export` remains accurate and
add a brief pointer to issue/PR `#1119` so readers can see the authoritative
objective and rationale.
In `@docs/design/page-structure.md`:
- Line 217: The Controller-to-Page Map must be updated to include the newly
added control-plane endpoints `/security/audit` and `/coordination/metrics`: add
corresponding controller entries (e.g., SecurityAuditController and
CoordinationMetricsController) into the map so each endpoint is mapped to its
documentation page, and ensure the “No orphans” claim remains true by either
linking those controllers to existing pages or adding new page placeholders and
references in the same section; also remove or adjust any stale statements if
mapping cannot be completed immediately.
In `@src/synthorg/api/app.py`:
- Around line 984-989: The code auto-wires AuditLog and CoordinationMetricsStore
but not trust_service, so ensure trust_service is instantiated when None before
constructing AppState: check if trust_service is None and assign a new
TrustService() (or the appropriate constructor used elsewhere), mirroring the
pattern used for audit_log and coordination_metrics_store so AppState receives a
non-None trust_service for agent-health trust aggregation.
In `@src/synthorg/api/controllers/agents.py`:
- Around line 146-155: AgentHealthResponse is missing the last_active_at
timestamp and get_agent_health() never reads the registry record; update the
Pydantic model AgentHealthResponse to include last_active_at: datetime | None
(or appropriate NotBlank/nullable type used elsewhere) and modify
get_agent_health() to call AgentRegistryService.get(agent_id) to obtain
lifecycle_status and last_active_at, populating those fields in the response;
ensure uses of AgentStatus, TrustSummary, and PerformanceSummary remain
unchanged and handle absent registry records by setting last_active_at to None
or returning an appropriate error as per existing patterns.
In `@src/synthorg/api/controllers/audit.py`:
- Around line 74-83: The code currently calls app_state.audit_log.query(...,
limit=_MAX_AUDIT_QUERY) then calls paginate(entries, offset, limit), which
misreports totals when the query is truncated; update the implementation so
pagination happens at the query layer: modify audit_log.query to accept offset
and limit (replace or augment the existing limit param/_MAX_AUDIT_QUERY usage)
and return either the page slice and total count (e.g., (entries_page, total))
or support offset/limit semantics so the controller can call
app_state.audit_log.query(agent_id=..., tool_name=..., action_type=...,
verdict=..., since=..., until=..., offset=offset, limit=limit) and then
construct correct pagination metadata from the returned total instead of calling
paginate(entries, ...).
In `@src/synthorg/api/controllers/coordination_metrics.py`:
- Around line 47-48: The endpoint accepting the since/until parameters must
reject inverted time windows instead of returning an empty page; add a small
Pydantic query model (with a model_validator) that validates that since <= until
when both provided and raise an HTTPException(400) on failure, or perform the
same check at the top of the controller handler that defines since/until; update
the controller function signature (the parameters currently shown as since:
datetime | None, until: datetime | None) to accept the new model and ensure
CoordinationMetricsStore.query() is only called after the validation passes.
In `@src/synthorg/api/controllers/settings.py`:
- Around line 556-603: The handler import_security_config currently only
validates and echoes the config then discards app_state, so it never persists or
activates the new security config; update import_security_config to call the
app-level persistence path on AppState (use the AppState methods that manage
settings) and perform the save/activate atomically before returning, ensure you
still validate via SecurityConfig.model_validate and return
SecurityConfigExportResponse, and change the logging to emit
API_SECURITY_CONFIG_IMPORTED only after a successful persistence (or
alternatively, if you choose to keep it as a validation-only endpoint, rename
the route/handler and response to indicate "validate-only" and remove/adjust the
201-style success log accordingly).
In `@src/synthorg/budget/coordination_store.py`:
- Around line 55-57: Before raising ValueError for invalid parameters, add a
logging call that records the bad value and context; specifically, before the
raise in the max_entries check (where max_entries is validated) and the limit
check (the similar block around lines 97-99), call the appropriate logger
(module-level logger or self.logger) with logger.warning or logger.error
including the parameter name ("max_entries" or "limit"), the received value, and
the function/method name, then raise the ValueError as before.
In `@tests/unit/api/controllers/test_agents.py`:
- Around line 579-590: In the test function
test_health_trust_none_when_not_tracked (and the similar test covering lines
599-610), assert the HTTP response succeeded before inspecting nested JSON
fields: add assert resp.status_code == 200 immediately after the
test_client.get(...) call and before calling resp.json() or accessing
body["data"]["trust"]; this ensures failures show the HTTP status instead of
KeyError/TypeError when reading deep payload fields.
- Around line 619-624: Replace the hardcoded trend literals with values derived
from the TrendDirection enum: import or reference TrendDirection, construct the
allowed set from its values (e.g., the enum's .value entries), and update the
assertion that checks perf["trend"] so it asserts perf["trend"] is None or in
that enum-derived set; this ensures the test follows the TrendDirection
definition (target the assertion around the perf variable in the test).
In `@tests/unit/api/controllers/test_coordination_metrics.py`:
- Around line 161-180: Update the test_message_overhead_is_quadratic_surfaced
test to assert the actual is_quadratic boolean rather than only checking key
presence: after fetching msg_oh from the response, replace the line asserting
key existence with an assertion like assert msg_oh["is_quadratic"] is True (or
equals the expected boolean for the given MessageOverhead input) so the test
verifies the computed flag value for the overhead instance created in the test.
In `@tests/unit/api/controllers/test_settings.py`:
- Around line 289-312: The round-trip test (test_round_trip) currently
re-imports the identical exported config so it can't catch
non-persistent/validate-only imports; modify the test to mutate one field on
config1 (for example toggle a boolean like "auth_enabled" or change a string
field) before POSTing to "/api/v1/settings/security/import", then fetch the
export again and assert that config2 reflects the changed value; update
assertions so the new value is verified rather than equality of unchanged
configs.
In `@web/src/api/types.ts`:
- Around line 1939-1945: CoordinationMetricsRecord currently uses a weak
metrics: Record<string, unknown>; replace this with a concrete typed DTO by
defining or importing a CoordinationMetrics (or similarly named) interface that
matches the backend DTO shape and update CoordinationMetricsRecord.metrics to
use that type; locate the CoordinationMetricsRecord interface and change the
metrics field to CoordinationMetrics (or the imported backend type) so consumers
regain compile-time safety when accessing metric properties.
🪄 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: a2836db4-d065-4a30-a20a-35662d083742
📒 Files selected for processing (22)
CLAUDE.mddocs/design/operations.mddocs/design/page-structure.mdsrc/synthorg/api/app.pysrc/synthorg/api/controllers/__init__.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/state.pysrc/synthorg/budget/coordination_store.pysrc/synthorg/engine/agent_engine.pysrc/synthorg/observability/events/api.pysrc/synthorg/security/audit.pytests/unit/api/conftest.pytests/unit/api/controllers/test_agents.pytests/unit/api/controllers/test_audit.pytests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/controllers/test_settings.pytests/unit/budget/test_coordination_store.pytests/unit/security/test_audit.pyweb/src/api/types.ts
📜 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: Dashboard Test
- GitHub Check: Test (Python 3.14)
- GitHub Check: Agent
- GitHub Check: Build Web
- GitHub Check: Build Backend
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{py,ts,tsx,go}
📄 CodeRabbit inference engine (CLAUDE.md)
Be critical at every phase of planning and implementation -- actively look for ways to improve the design in the spirit of what we're building (robustness, correctness, simplicity, future-proofing where it's free). Surface improvements as suggestions, not silent changes.
Files:
src/synthorg/api/controllers/__init__.pysrc/synthorg/engine/agent_engine.pysrc/synthorg/security/audit.pysrc/synthorg/api/app.pytests/unit/security/test_audit.pytests/unit/api/controllers/test_agents.pytests/unit/budget/test_coordination_store.pytests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/conftest.pytests/unit/api/controllers/test_audit.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/state.pyweb/src/api/types.tssrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/agents.pytests/unit/api/controllers/test_settings.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/budget/coordination_store.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotations-- Python 3.14 has PEP 649 native lazy annotations.Use
except A, B:syntax (no parentheses) for PEP 758 exception handling -- ruff enforces this on Python 3.14.Type hints: all public functions, mypy strict mode.
Docstrings: Google style, required on public classes/functions (enforced by ruff D rules).
Immutability: create new objects, never mutate existing ones. For non-Pydantic internal collections (registries,
BaseTool), usecopy.deepcopy()at construction +MappingProxyTypewrapping for read-only enforcement.For
dict/listfields in frozen Pydantic models, rely onfrozen=Truefor field reassignment prevention andcopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).Config vs runtime state: frozen Pydantic models for config/identity; separate mutable-via-copy models (using
model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.Models: Pydantic v2 (
BaseModel,model_validator,computed_field,ConfigDict). Useallow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/Infin numeric fields at validation time.Use
@computed_fieldfor derived values instead of storing + validating redundant fields (e.g.TokenUsage.total_tokens).Use
NotBlankStr(fromcore.types) for all identifier/name fields -- including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants -- instead of manual whitespace validators.Async concurrency: prefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_task.Line length: 88 characters (ruff).
Functions: < 50 lines, files < 800 lines.
Errors: handle explicitly, never silently swallow.
Validate at system boundaries (user input, external APIs, ...
Files:
src/synthorg/api/controllers/__init__.pysrc/synthorg/engine/agent_engine.pysrc/synthorg/security/audit.pysrc/synthorg/api/app.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/state.pysrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/budget/coordination_store.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/controllers/__init__.pysrc/synthorg/engine/agent_engine.pysrc/synthorg/security/audit.pysrc/synthorg/api/app.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/state.pysrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/budget/coordination_store.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Markers:
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slow.Coverage: 80% minimum (enforced in CI).
Async:
asyncio_mode = "auto"-- no manual@pytest.mark.asyncioneeded.Timeout: 30 seconds per test (global in
pyproject.toml-- do not add per-filepytest.mark.timeout(30)markers; non-default overrides liketimeout(60)are allowed).Parallelism:
pytest-xdistvia-n 8-- ALWAYS include-n 8when running pytest locally, never run tests sequentially.Parametrize: Prefer
@pytest.mark.parametrizefor testing similar cases.Vendor-agnostic everywhere: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in tests. Use generic names:
test-provider,test-small-001,test-medium-001,test-large-001.Property-based testing: Python uses Hypothesis (
@given+@settings). Hypothesis profiles configured intests/conftest.py:ci(deterministic,max_examples=10+derandomize=True),dev(1000 examples),fuzz(10,000 examples, no deadline),extreme(500,000 examples, no deadline). Controlled viaHYPOTHESIS_PROFILEenv var.CI runs 10 deterministic examples per property test (
derandomize=True-- same inputs every run, no flakes). Random fuzzing runs locally viaHYPOTHESIS_PROFILE=devorHYPOTHESIS_PROFILE=fuzz.When Hypothesis finds a failure, it is a real bug -- fix the underlying bug and add an explicit
@example(...)decorator to the test so the case is permanently covered in CI.Flaky tests: NEVER skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock
time.monotonic()andasyncio.sleep()to make them deterministic. For tasks that must block indefinitely, useasyncio.Event().wait()instead ofasyncio.sleep(large_number).
Files:
tests/unit/security/test_audit.pytests/unit/api/controllers/test_agents.pytests/unit/budget/test_coordination_store.pytests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/conftest.pytests/unit/api/controllers/test_audit.pytests/unit/api/controllers/test_settings.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/security/test_audit.pytests/unit/api/controllers/test_agents.pytests/unit/budget/test_coordination_store.pytests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/conftest.pytests/unit/api/controllers/test_audit.pytests/unit/api/controllers/test_settings.py
docs/design/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
ALWAYS read the relevant
docs/design/page before implementing any feature or planning any issue. The design spec is the starting point for architecture, data models, and behavior.
Files:
docs/design/page-structure.mddocs/design/operations.md
web/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (web/CLAUDE.md)
web/src/**/*.{ts,tsx,js,jsx}: Always usecreateLoggerfrom@/lib/logger-- never bareconsole.warn/console.error/console.debugin application code
Logger variable name must always beconst log(e.g.const log = createLogger('module-name'))
Pass dynamic/untrusted values as separate arguments to logger methods (not interpolated into the message string) so they go throughsanitizeArg
Attacker-controlled fields inside structured objects must be wrapped insanitizeForLog()before embedding in log calls
Files:
web/src/api/types.ts
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/CLAUDE.md)
web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground,bg-card,text-accent,text-success,bg-danger, etc.) or CSS variables (var(--so-*)) for colors; NEVER hardcode hex values in.tsx/.tsfiles
Usefont-sansorfont-mono(Geist tokens) for typography; NEVER setfontFamilydirectly in.tsx/.tsfiles
Use density-aware tokens (p-card,gap-section-gap,gap-grid-gap) or standard Tailwind spacing; NEVER hardcode pixel values for layout spacing in components
Use token variables (var(--so-shadow-card-hover),border-border,border-bright) for shadows and borders; NEVER hardcode values in.tsx/.tsfiles
Use@/lib/motionpresets for Framer Motion transition durations; NEVER hardcode transition durations
CSS side-effect imports in TypeScript 6 require type declarations -- add/// <reference types="vite/client" />at the top of files with CSS importsALWAYS reuse existing components from
web/src/components/ui/before creating new ones.NEVER hardcode hex colors, font-family, pixel spacing, or Framer Motion transitions -- use design tokens and
@/lib/motionpresets.
Files:
web/src/api/types.ts
🧠 Learnings (68)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Security: 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).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: If implementation deviates from the spec (better approach found, scope evolved, etc.), alert the user and explain why -- user decides whether to proceed or update the spec. Do NOT silently diverge.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: Every implementation plan must be presented to the user for accept/deny before coding starts.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: Prioritize issues by dependency order, not priority labels -- unblocked dependencies come first.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: A PostToolUse hook (`scripts/check_web_design_system.py`) enforces design system rules on every Edit/Write to `web/src/`.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: NEVER use Bash to write or modify files -- use the Write or Edit tools. Do not use `cat >`, `cat << EOF`, `echo >`, `echo >>`, `sed -i`, `python -c "open(...).write(...)",` or `tee` to create or modify files.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: Signed commits: required on `main` via branch protection -- all commits must be GPG/SSH signed.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: Branches: `<type>/<slug>` from main.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: Pre-push hooks: mypy type-check (affected modules only) + pytest unit tests (affected modules only) + golangci-lint + go vet + go test (CLI) + eslint-web (web dashboard). Foundational module changes (core, config, observability) or conftest changes trigger full runs.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: GitHub issue queries: use `gh issue list` via Bash (not MCP tools) -- MCP `list_issues` has unreliable field data.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: Merge strategy: squash merge -- PR body becomes the squash commit message on main. Trailers (e.g. `Release-As`, `Closes `#N``) must be in the PR body to land in the final commit.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: PR issue references: preserve existing `Closes `#NNN`` references -- never remove unless explicitly asked.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: After finishing an issue implementation: always create a feature branch (`<type>/<slug>`), commit, and push -- do NOT create a PR automatically. Do NOT leave work uncommitted on main.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: NEVER create a PR directly -- `gh pr create` is blocked by hookify. ALWAYS use `/pre-pr-review` to create PRs -- it runs automated checks + review agents + fixes before creating the PR.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: For trivial/docs-only changes: `/pre-pr-review quick` skips agents but still runs automated checks.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:10:02.639Z
Learning: Fix everything valid -- never skip: When review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes), fix them all. No deferring, no "out of scope" skipping.
📚 Learning: 2026-04-06T16:35:12.934Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T16:35:12.934Z
Learning: All project conventions, commands, and standards are defined in CLAUDE.md - refer to it for project structure, package layout, code conventions, quick commands, git workflow, testing standards, design specifications, logging, resilience, and security patterns
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-31T16:09:24.320Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T16:09:24.320Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from `synthorg.observability.events.<domain>` modules (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly and use in structured logging
Applied to files:
CLAUDE.mdsrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from the domain-specific module under `synthorg.observability.events` in logging calls
Applied to files:
CLAUDE.mdsrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)
Applied to files:
CLAUDE.mdsrc/synthorg/api/app.pysrc/synthorg/api/state.pysrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`, etc.); import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
Applied to files:
CLAUDE.mdsrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Use event constants from `synthorg.observability.events.<domain>` (e.g., `API_REQUEST_STARTED` from `events.api`); import directly and log with structured kwargs: `logger.info(EVENT, key=value)`, never interpolated strings
Applied to files:
CLAUDE.mdsrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use import logging / logging.getLogger() / print() in application code.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)`—never `logger.info("msg %s", val)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-02T12:07:44.443Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:07:44.443Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation, internal flow, entry/exit of key functions
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers
Applied to files:
src/synthorg/api/controllers/__init__.pysrc/synthorg/api/app.pydocs/design/page-structure.mdtests/unit/api/conftest.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/state.pysrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
src/synthorg/api/controllers/__init__.pysrc/synthorg/api/app.pytests/unit/api/conftest.pysrc/synthorg/api/state.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget package (budget/): cost tracking, budget enforcement (pre-flight/in-flight checks, auto-downgrade), billing periods, cost tiers, quota/subscription tracking, CFO cost optimization (anomaly detection, efficiency analysis, downgrade recommendations, approval decisions), spending reports, budget errors (BudgetExhaustedError, DailyLimitExceededError, QuotaExhaustedError)
Applied to files:
src/synthorg/api/app.pytests/unit/api/conftest.pysrc/synthorg/api/state.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/state.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/communication/**/*.py : Communication package (communication/): message bus, dispatcher, messenger, channels, delegation, loop prevention, conflict resolution; meeting/ subpackage for meeting protocol (round-robin, position papers, structured phases), scheduler (frequency, participant resolver), orchestrator
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/state.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/state.pysrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/backup/**/*.py : Backup package (backup/): scheduled/manual/lifecycle backups of persistence DB, agent memory, company config. BackupService orchestrator, BackupScheduler (periodic asyncio task), RetentionManager (count + age pruning), tar.gz compression, SHA-256 checksums, manifest tracking, validated restore with atomic rollback and safety backup. handlers/ subpackage: ComponentHandler protocol + concrete handlers (PersistenceComponentHandler, MemoryComponentHandler, ConfigComponentHandler)
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-18T21:23:23.586Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T21:23:23.586Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from the domain-specific module under synthorg.observability.events (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool). Import directly from synthorg.observability.events.<domain>.
Applied to files:
src/synthorg/api/app.pysrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget tracking includes pre-flight/in-flight checks, auto-downgrade, billing periods, cost tiers, quota/subscription. CFO includes anomaly detection, efficiency analysis, downgrade recommendations.
Applied to files:
src/synthorg/api/app.pytests/unit/api/conftest.pysrc/synthorg/api/state.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/providers/**/*.py : Providers: LLM provider abstraction (LiteLLM adapter), auth types (api_key/oauth/custom_header/none), presets (PROVIDER_PRESETS), runtime CRUD (ProviderManagementService with asyncio.Lock serialization), hot-reload via AppState swap.
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/state.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): 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), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)
Applied to files:
src/synthorg/api/app.pytests/unit/api/conftest.pysrc/synthorg/api/state.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/security/**/*.py : Security module includes SecOps agent, rule engine (soft-allow/hard-deny), audit log, output scanner, risk classifier, autonomy levels (4 strategies), timeout policies.
Applied to files:
src/synthorg/api/app.pytests/unit/api/conftest.pysrc/synthorg/api/state.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Set `RetryConfig` and `RateLimiterConfig` per-provider in `ProviderConfig`.
Applied to files:
src/synthorg/api/app.pytests/unit/api/conftest.pysrc/synthorg/api/state.py
📚 Learning: 2026-03-31T21:07:37.469Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T21:07:37.469Z
Learning: Applies to src/synthorg/providers/**/*.py : Set `RetryConfig` and `RateLimiterConfig` per-provider in `ProviderConfig`
Applied to files:
src/synthorg/api/app.pytests/unit/api/conftest.pysrc/synthorg/api/state.py
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/providers/**/*.py : `RetryConfig` and `RateLimiterConfig` are set per-provider in `ProviderConfig`
Applied to files:
src/synthorg/api/app.pytests/unit/api/conftest.py
📚 Learning: 2026-03-16T19:13:36.562Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:13:36.562Z
Learning: Applies to src/synthorg/providers/**/*.py : RetryConfig and RateLimiterConfig are set per-provider in ProviderConfig.
Applied to files:
src/synthorg/api/app.pytests/unit/api/conftest.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/**/*.py : `RetryConfig` and `RateLimiterConfig` are set per-provider in `ProviderConfig`. Retryable errors: `RateLimitError`, `ProviderTimeoutError`, `ProviderConnectionError`, `ProviderInternalError`. Non-retryable errors raise immediately.
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/synthorg/api/**/*.py : Litestar API must include setup wizard, auth/, auto-wiring, and lifecycle management
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/state.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
tests/unit/api/controllers/test_agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
Applied to files:
docs/design/page-structure.mddocs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...
Applied to files:
docs/design/page-structure.mdsrc/synthorg/api/state.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)
Applied to files:
docs/design/page-structure.mdtests/unit/api/conftest.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations
Applied to files:
docs/design/page-structure.mddocs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/settings/**/*.py : Settings package (settings/): runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge (JSON serialization for Pydantic/collections), ConfigResolver (typed accessors), validation, registry, change notifications via message bus, SettingsSubscriber protocol, SettingsChangeDispatcher (polls `#settings` channel, routes to subscribers, restart_required filtering)
Applied to files:
docs/design/page-structure.mdsrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Settings: Runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge, ConfigResolver (typed composed reads for controllers), validation, registry, change notifications via message bus. Per-namespace setting definitions in definitions/ submodule (api, company, providers, memory, budget, security, coordination, observability, backup).
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/settings/**/*.py : Settings use runtime-editable persistence with precedence: DB > env > YAML > code defaults. 8 namespaces with Fernet encryption for sensitive values.
Applied to files:
docs/design/page-structure.mdsrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to tests/**/*.py : Fix flaky tests completely and fundamentally; for timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/conftest.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to tests/**/*.py : Test markers: pytest.mark.unit, pytest.mark.integration, pytest.mark.e2e, pytest.mark.slow. Coverage: 80% minimum (enforced in CI).
Applied to files:
tests/unit/api/controllers/test_coordination_metrics.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/api/**/*.py : REST API: Litestar framework, controllers with guards, channels for WebSocket, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. RFC 9457 structured errors (ErrorCategory, ErrorCode, ErrorDetail, ProblemDetail, CATEGORY_TITLES, category_title, category_type_uri, content negotiation).
Applied to files:
tests/unit/api/conftest.pysrc/synthorg/api/state.pysrc/synthorg/observability/events/api.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/hr/**/*.py : HR engine must provide: hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, trend detection), promotion/demotion
Applied to files:
tests/unit/api/conftest.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import `from synthorg.observability import get_logger` and define `logger = get_logger(__name__)`
Applied to files:
src/synthorg/api/state.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/engine/**/*.py : Engine package (engine/): agent orchestration, parallel execution, task decomposition, routing, TaskEngine (centralized single-writer), task lifecycle/recovery/shutdown, workspace isolation, coordination (4 dispatchers: SAS/centralized/decentralized/context-dependent, wave execution), approval gates (escalation detection, context parking/resume), stagnation detection (ToolRepetitionDetector, corrective prompt injection), AgentRuntimeState (execution status), context budget management, conversation compaction (oldest-turns summarizer)
Applied to files:
src/synthorg/api/state.py
📚 Learning: 2026-04-06T06:45:22.965Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: web/CLAUDE.md:0-0
Timestamp: 2026-04-06T06:45:22.965Z
Learning: Applies to web/tsconfig.json : In TypeScript 6, explicitly list needed types in the `types` array (e.g. `"types": ["vitest/globals"]`) instead of relying on auto-discovery of `types/*`
Applied to files:
web/src/api/types.ts
📚 Learning: 2026-04-01T18:57:46.655Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T18:57:46.655Z
Learning: Applies to web/package.json : Web dashboard Node.js 22+, TypeScript 6.0+, dependencies in `web/package.json`
Applied to files:
web/src/api/types.ts
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Security: 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:
web/src/api/types.tsdocs/design/operations.md
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly from the domain module
Applied to files:
src/synthorg/observability/events/api.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/api.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly rather than using string literals
Applied to files:
src/synthorg/observability/events/api.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to src/ai_company/!(observability)/**/*.py : Use event name constants from domain-specific modules under `ai_company.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`). Import directly: `from ai_company.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/api.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/api/**/*.py : Use Litestar for REST + WebSocket API. Controllers, guards, channels, JWT + API key + WS ticket auth, RFC 9457 structured errors.
Applied to files:
src/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to src/**/*.py : Use event name constants from domain-specific modules under ai_company.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.) — import directly
Applied to files:
src/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 7 design pages (index, agents, organization, communication, engine, memory, operations).
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (via `model_copy(update=...)`) for runtime state that evolves
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state that evolves; never mix static config fields with mutable runtime fields in one model
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/api/**/*.py : Use Litestar for REST API and WebSocket API with JWT + API key + WS ticket authentication, RFC 9457 structured errors, and content negotiation.
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`); use `allow_inf_nan=False` in all `ConfigDict` declarations to reject `NaN`/`Inf` in numeric fields at validation time
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability includes structured logging via `get_logger(__name__)`, correlation tracking, and log sinks.
Applied to files:
src/synthorg/api/controllers/settings.py
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/design/operations.md`:
- Line 1840: The table row for G4 and the "Coordination Metrics Suite" section
disagree on how many Kim et al. metrics GET /coordination/metrics exposes;
reconcile them so the doc has one source of truth: either change the G4 row (the
"`GET /coordination/metrics` exposes the 9 Kim et al. metrics" text) to state "5
Kim et al. metrics" or expand the "Coordination Metrics Suite" section to list
all 9 metrics and update the documented collect values accordingly; ensure the
noun "`GET /coordination/metrics`" and the "Coordination Metrics Suite"
subsection, including the `collect` examples, are updated to match the chosen
count.
- Line 1838: Update the table row documenting the per-agent health endpoint to
explicitly call out that the implemented path is GET /agents/{name}/health (not
GET /agents/{id}/health as scoped in Issue `#1118`); add a short
approved-deviation note next to the row (or in a footnote) stating that the
identifier changed from {id} → {name} to align with existing agent routes and
include a one-line rationale (e.g., consistency with agent routes) and a
reference to Issue `#1118` so clients can decide whether to follow the implemented
contract or the original spec.
In `@src/synthorg/api/controllers/agents.py`:
- Around line 532-553: The parameter snapshot is currently typed as Any even
though _extract_quality_trend expects an object with a trends iterable
containing items with metric_name and direction; replace the Any with a concrete
type (preferably AgentPerformanceSnapshot) or define and use a small
typing.Protocol (e.g. has attribute trends: Iterable[ItemType]) that exposes
metric_name and direction, import or declare TrendDirection-compatible item type
if needed, and update the function signature and imports accordingly so the
IDE/typechecker recognizes snapshot.trends and its elements.
In `@src/synthorg/api/controllers/audit.py`:
- Around line 82-91: The current audit pagination uses
app_state.audit_log.query(...) and paginate(entries, ...) but doesn't signal
when results hit the _MAX_AUDIT_QUERY cap, which can mislead clients; update
AuditLog.query (or add an alternate method) to return both the result list and
the true matching total (e.g., (entries, true_total)), then call
paginate(entries, offset=offset, limit=limit, total=true_total) and add
is_truncated = (len(entries) >= _MAX_AUDIT_QUERY) and has_more = (offset +
len(page) < true_total or is_truncated) into the response metadata so clients
can detect truncation and whether to continue fetching.
In `@src/synthorg/api/controllers/settings.py`:
- Around line 589-592: The import currently calls _persist_security_settings
which issues independent svc.set() calls so partial failures can leave a
partially-applied policy while the handler returns validated.model_dump() as if
everything applied; change _persist_security_settings (or add a new batched
method) to apply the _SECURITY_SETTING_FIELDS in a single atomic
operation/transaction via app_state.settings_service (or collect all key→value
pairs and call a single bulk set/update API), and on failure return a clear
applied/ignored breakdown built from the effective configuration read back from
the service (do not return validated.model_dump() unconditionally);
alternatively, if atomic persistence isn’t possible, make
_persist_security_settings accumulate successes and failures and have the
controller return an explicit applied/ignored field map instead of the full
validated model.
- Around line 538-539: The export currently serializes app_state.config.security
directly; instead call the settings resolver/service used for runtime
persistence (the same SettingsService used by import_security_config) to obtain
the resolved/effective security settings and serialize that. Replace the use of
app_state.config.security in the export handler with the resolved object
returned from the settings resolver (e.g.,
SettingsService.get_effective_config("security") or
SettingsResolver.resolve("security") — whatever concrete method exists on
app_state.settings_service), then call model_dump on that resolved instance
before returning.
In `@src/synthorg/budget/coordination_store.py`:
- Around line 57-61: Replace the success metric constant used in error logging
with a dedicated error event: define a new constant (e.g.,
COORD_METRICS_CONFIG_ERROR) and use it in the logger.warning call instead of
COORD_METRICS_COLLECTION_COMPLETED where configuration/validation errors occur
in coordination_store.py; update the logger.warning invocation that currently
passes COORD_METRICS_COLLECTION_COMPLETED and error=msg to pass
COORD_METRICS_CONFIG_ERROR (keeping the error=msg) so log filtering/alerting can
distinguish config errors from successful collection, while leaving the
subsequent raise ValueError(msg) unchanged.
- Around line 77-121: The query method in CoordinationStore (function query)
currently allows an inverted time window and returns empty results; add a
validation that if both since and until are provided and since > until you raise
a ValueError (matching AuditLog.query behavior) with a clear message like "since
must be <= until, got since=... until=..."; perform this check near the start of
query (before iterating self._records) and, for consistency with the existing
limit check, optionally log a warning via the same logger before raising.
In `@tests/unit/api/controllers/test_coordination_metrics.py`:
- Around line 113-139: Add a new unit test function (e.g.,
test_rejects_inverted_time_window) that uses TestClient to call the controller
endpoint "/api/v1/coordination/metrics" with params where "since" is later than
"until" (create t1 = datetime(..., tzinfo=UTC) and t2 = t1 -
timedelta(hours=1)), include _HEADERS, and assert resp.status_code == 400 to
verify the controller rejects an inverted time window; place the test alongside
existing tests in tests/unit/api/controllers/test_coordination_metrics.py and
reference the same request pattern used in test_filter_by_time_range.
🪄 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: 64955c7e-a816-4242-8525-7cc941e2aae8
📒 Files selected for processing (12)
docs/design/operations.mddocs/design/page-structure.mdsrc/synthorg/api/app.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/budget/coordination_store.pysrc/synthorg/security/audit.pytests/unit/api/controllers/test_agents.pytests/unit/api/controllers/test_coordination_metrics.pyweb/src/api/types.ts
📜 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). (5)
- GitHub Check: Dashboard Test
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Web
- GitHub Check: Build Backend
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Do NOT use
from __future__ import annotationsin Python code; Python 3.14 has PEP 649 native lazy annotations.Use PEP 758 except syntax: use
except A, B:without parentheses; ruff enforces this on Python 3.14.Add type hints to all public functions in Python; use mypy strict mode.
Use Google-style docstrings on public Python classes and functions; required and enforced by ruff D rules.
Create new objects instead of mutating existing ones; use
copy.deepcopy()for non-Pydantic internal collections and wrap withMappingProxyTypefor read-only enforcement.Use frozen Pydantic models for config/identity; use separate mutable-via-copy models for runtime state that evolves using
model_copy(update=...).Use Pydantic v2 (
BaseModel,model_validator,computed_field,ConfigDict) withallow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/Infin numeric fields.Use
@computed_fieldfor derived values in Pydantic models instead of storing and validating redundant fields.Use
NotBlankStrfromcore.typesfor all identifier/name fields in Python (including optional variants likeNotBlankStr | Noneand tuples liketuple[NotBlankStr, ...]) instead of manual whitespace validators.Prefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new Python code (e.g., multiple tool invocations, parallel agent calls).Maintain 88-character line length in Python code; enforced by ruff.
Keep Python functions under 50 lines and files under 800 lines.
Handle errors explicitly in Python code; never silently swallow exceptions.
Validate data at system boundaries in Python (user input, external APIs, config files).
Every Python module with business logic MUST have:
from synthorg.observability import get_loggerthenlogger = get_logger(__name__)Never use
import logging,logging.getLogger(), orprint()in Python application code; exceptions areobservability/setup.py,observability/sinks.py, `observability/syslog_hand...
Files:
src/synthorg/security/audit.pytests/unit/api/controllers/test_agents.pytests/unit/api/controllers/test_coordination_metrics.pysrc/synthorg/api/app.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/budget/coordination_store.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/security/audit.pysrc/synthorg/api/app.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/budget/coordination_store.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Mark tests with
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e, or@pytest.mark.slowin Python test files.Maintain 80% minimum code coverage in Python tests; enforced in CI via
--covflag.Use
asyncio_mode = "auto"for Python async tests; no manual@pytest.mark.asyncioneeded.Set 30-second timeout per Python test globally in
pyproject.toml; non-default overrides liketimeout(60)are allowed but no per-file default markers.Always include
-n 8when running pytest locally for Python tests; never run tests sequentially. CI uses-n auto.Use
@pytest.mark.parametrizefor testing similar cases in Python tests.Use
test-provider,test-small-001in Python tests instead of real vendor names.Use Hypothesis property-based testing in Python with
@given+@settingsdecorators; configure profiles intests/conftest.py:ci(10 examples, deterministic),dev(1000 examples),fuzz(10,000 examples, no deadline),extreme(500,000 examples). Control viaHYPOTHESIS_PROFILEenv var.Add explicit
@example(...)decorator to Python property tests after fixing Hypothesis-found failures to permanently cover the case in CI.Never skip, dismiss, or ignore flaky Python tests; always fix them fully and fundamentally. Mock
time.monotonic()andasyncio.sleep()for timing-sensitive tests; useasyncio.Event().wait()for indefinite blocking.
Files:
tests/unit/api/controllers/test_agents.pytests/unit/api/controllers/test_coordination_metrics.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/controllers/test_agents.pytests/unit/api/controllers/test_coordination_metrics.py
web/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (web/CLAUDE.md)
web/src/**/*.{ts,tsx,js,jsx}: Always usecreateLoggerfrom@/lib/logger-- never bareconsole.warn/console.error/console.debugin application code
Logger variable name must always beconst log(e.g.const log = createLogger('module-name'))
Pass dynamic/untrusted values as separate arguments to logger methods (not interpolated into the message string) so they go throughsanitizeArg
Attacker-controlled fields inside structured objects must be wrapped insanitizeForLog()before embedding in log calls
Files:
web/src/api/types.ts
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/CLAUDE.md)
web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground,bg-card,text-accent,text-success,bg-danger, etc.) or CSS variables (var(--so-*)) for colors; NEVER hardcode hex values in.tsx/.tsfiles
Usefont-sansorfont-mono(Geist tokens) for typography; NEVER setfontFamilydirectly in.tsx/.tsfiles
Use density-aware tokens (p-card,gap-section-gap,gap-grid-gap) or standard Tailwind spacing; NEVER hardcode pixel values for layout spacing in components
Use token variables (var(--so-shadow-card-hover),border-border,border-bright) for shadows and borders; NEVER hardcode values in.tsx/.tsfiles
Use@/lib/motionpresets for Framer Motion transition durations; NEVER hardcode transition durations
CSS side-effect imports in TypeScript 6 require type declarations -- add/// <reference types="vite/client" />at the top of files with CSS importsReuse existing components from
web/src/components/ui/before creating new ones in the React web dashboard.Never hardcode hex colors, font-family, pixel spacing, or Framer Motion transitions in the React web dashboard; use design tokens and
@/lib/motionpresets.
Files:
web/src/api/types.ts
🧠 Learnings (63)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to 12 design pages.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Alert the user and explain why if implementation deviates from the design spec; do NOT silently diverge. Every deviation needs explicit user approval.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations occur.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Present every implementation plan to the user for accept/deny before coding starts.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Be critical at every phase of planning and implementation; actively look for ways to improve the design in the spirit of robustness, correctness, simplicity, and future-proofing.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Prioritize issues by dependency order, not priority labels; unblocked dependencies come first.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Use commit format `<type>: <description>` with types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: All commits to `main` must be GPG/SSH signed; enforced via branch protection.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Use branch format `<type>/<slug>` from main (e.g., `feat/agent-delegation`, `fix/timeout-handling`).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Never create a PR directly with `gh pr create` (blocked by hookify). ALWAYS use `/pre-pr-review` to create PRs; it runs automated checks + review agents + fixes before creating the PR. Use `/pre-pr-review quick` for trivial/docs-only changes.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Fix everything valid found by review agents in PR reviews; never skip or defer issues as out of scope.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: After finishing an issue implementation, create a feature branch (`<type>/<slug>`), commit, and push; do NOT create a PR automatically. Do NOT leave work uncommitted on main.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Use pre-commit hooks for trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile), golangci-lint + go vet (CLI), no-em-dashes, no-redundant-timeout, eslint-web (web, zero warnings).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Use pre-push hooks for mypy (affected modules only) + pytest unit tests (affected modules only) + golangci-lint + go vet + go test (CLI) + eslint-web (web dashboard). Foundational module changes trigger full runs. Skipped in pre-commit.ci.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Use `gh issue list` via Bash for GitHub issue queries (not MCP tools); MCP `list_issues` has unreliable field data.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Use squash merge strategy for PRs; PR body becomes the squash commit message on main. Preserve `Closes `#NNN`` issue references in the PR body.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Never use `cd` in Bash commands; use absolute paths or run commands directly. Exception: `bash -c "cd <dir> && <cmd>"` is safe (runs in child process). Use this for tools without a `-C` flag.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:18:41.223Z
Learning: Never use Bash to write or modify files; use Write or Edit tools. Do not use `cat >`, `cat << EOF`, `echo >`, `echo >>`, `sed -i`, `python -c "open(...).write(...)"`, or `tee` for file creation/modification.
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
Applied to files:
docs/design/page-structure.mddocs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations
Applied to files:
docs/design/page-structure.mddocs/design/operations.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-03-30T10:41:40.176Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-30T10:41:40.176Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations from spec occur
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to docs/design/**/*.md : When approved deviations from the design spec occur, update the relevant `docs/design/` page to reflect the new reality
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/settings/**/*.py : Settings package (settings/): runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge (JSON serialization for Pydantic/collections), ConfigResolver (typed accessors), validation, registry, change notifications via message bus, SettingsSubscriber protocol, SettingsChangeDispatcher (polls `#settings` channel, routes to subscribers, restart_required filtering)
Applied to files:
docs/design/page-structure.mdsrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Settings: Runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge, ConfigResolver (typed composed reads for controllers), validation, registry, change notifications via message bus. Per-namespace setting definitions in definitions/ submodule (api, company, providers, memory, budget, security, coordination, observability, backup).
Applied to files:
docs/design/page-structure.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers
Applied to files:
docs/design/page-structure.mdsrc/synthorg/api/app.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/settings/**/*.py : Settings use runtime-editable persistence with precedence: DB > env > YAML > code defaults. 8 namespaces with Fernet encryption for sensitive values.
Applied to files:
docs/design/page-structure.mdsrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
tests/unit/api/controllers/test_agents.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-21T11:08:01.542Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T11:08:01.542Z
Learning: When implementation deviates from the spec (better approach found, scope evolved, etc.), alert the user and explain why — user decides whether to proceed or update the spec. Do NOT silently diverge — every deviation needs explicit user approval.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Security: 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:
docs/design/operations.mdweb/src/api/types.ts
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/synthorg/api/**/*.py : Litestar API must include setup wizard, auth/, auto-wiring, and lifecycle management
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget package (budget/): cost tracking, budget enforcement (pre-flight/in-flight checks, auto-downgrade), billing periods, cost tiers, quota/subscription tracking, CFO cost optimization (anomaly detection, efficiency analysis, downgrade recommendations, approval decisions), spending reports, budget errors (BudgetExhaustedError, DailyLimitExceededError, QuotaExhaustedError)
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/communication/**/*.py : Communication package (communication/): message bus, dispatcher, messenger, channels, delegation, loop prevention, conflict resolution; meeting/ subpackage for meeting protocol (round-robin, position papers, structured phases), scheduler (frequency, participant resolver), orchestrator
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/backup/**/*.py : Backup package (backup/): scheduled/manual/lifecycle backups of persistence DB, agent memory, company config. BackupService orchestrator, BackupScheduler (periodic asyncio task), RetentionManager (count + age pruning), tar.gz compression, SHA-256 checksums, manifest tracking, validated restore with atomic rollback and safety backup. handlers/ subpackage: ComponentHandler protocol + concrete handlers (PersistenceComponentHandler, MemoryComponentHandler, ConfigComponentHandler)
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-18T21:23:23.586Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T21:23:23.586Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from the domain-specific module under synthorg.observability.events (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool). Import directly from synthorg.observability.events.<domain>.
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget tracking includes pre-flight/in-flight checks, auto-downgrade, billing periods, cost tiers, quota/subscription. CFO includes anomaly detection, efficiency analysis, downgrade recommendations.
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/providers/**/*.py : Providers: LLM provider abstraction (LiteLLM adapter), auth types (api_key/oauth/custom_header/none), presets (PROVIDER_PRESETS), runtime CRUD (ProviderManagementService with asyncio.Lock serialization), hot-reload via AppState swap.
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): 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), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/security/**/*.py : Security module includes SecOps agent, rule engine (soft-allow/hard-deny), audit log, output scanner, risk classifier, autonomy levels (4 strategies), timeout policies.
Applied to files:
src/synthorg/api/app.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Set `RetryConfig` and `RateLimiterConfig` per-provider in `ProviderConfig`.
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-31T21:07:37.469Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T21:07:37.469Z
Learning: Applies to src/synthorg/providers/**/*.py : Set `RetryConfig` and `RateLimiterConfig` per-provider in `ProviderConfig`
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/providers/**/*.py : `RetryConfig` and `RateLimiterConfig` are set per-provider in `ProviderConfig`
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-16T19:13:36.562Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:13:36.562Z
Learning: Applies to src/synthorg/providers/**/*.py : RetryConfig and RateLimiterConfig are set per-provider in ProviderConfig.
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/**/*.py : `RetryConfig` and `RateLimiterConfig` are set per-provider in `ProviderConfig`. Retryable errors: `RateLimitError`, `ProviderTimeoutError`, `ProviderConnectionError`, `ProviderInternalError`. Non-retryable errors raise immediately.
Applied to files:
src/synthorg/api/app.py
📚 Learning: 2026-04-06T06:45:22.965Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: web/CLAUDE.md:0-0
Timestamp: 2026-04-06T06:45:22.965Z
Learning: Applies to web/tsconfig.json : In TypeScript 6, explicitly list needed types in the `types` array (e.g. `"types": ["vitest/globals"]`) instead of relying on auto-discovery of `types/*`
Applied to files:
web/src/api/types.ts
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/**/*.py : Validate at system boundaries (user input, external APIs, config files)
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (via `model_copy(update=...)`) for runtime state that evolves
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state that evolves; never mix static config fields with mutable runtime fields in one model
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-04-01T09:37:49.451Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T09:37:49.451Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/api/**/*.py : REST API: Litestar framework, controllers with guards, channels for WebSocket, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. RFC 9457 structured errors (ErrorCategory, ErrorCode, ErrorDetail, ProblemDetail, CATEGORY_TITLES, category_title, category_type_uri, content negotiation).
Applied to files:
src/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/api/**/*.py : Use Litestar for REST API and WebSocket API with JWT + API key + WS ticket authentication, RFC 9457 structured errors, and content negotiation.
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`); use `allow_inf_nan=False` in all `ConfigDict` declarations to reject `NaN`/`Inf` in numeric fields at validation time
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/api/**/*.py : Use Litestar for REST + WebSocket API. Controllers, guards, channels, JWT + API key + WS ticket auth, RFC 9457 structured errors.
Applied to files:
src/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Use event constants from `synthorg.observability.events.<domain>` (e.g., `API_REQUEST_STARTED` from `events.api`); import directly and log with structured kwargs: `logger.info(EVENT, key=value)`, never interpolated strings
Applied to files:
src/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-31T16:09:24.320Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T16:09:24.320Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from `synthorg.observability.events.<domain>` modules (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly and use in structured logging
Applied to files:
src/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability includes structured logging via `get_logger(__name__)`, correlation tracking, and log sinks.
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly from the domain module
Applied to files:
src/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`, etc.); import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
Applied to files:
src/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from the domain-specific module under `synthorg.observability.events` in logging calls
Applied to files:
src/synthorg/api/controllers/settings.py
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to src/**/*.py : Use event name constants from domain-specific modules under ai_company.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.) — import directly
Applied to files:
src/synthorg/api/controllers/agents.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to src/ai_company/!(observability)/**/*.py : All error paths must log at WARNING or ERROR with context before raising.
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-15T16:55:07.730Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:55:07.730Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising.
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation, internal flow, entry/exit of key functions
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
src/synthorg/budget/coordination_store.py
🔇 Additional comments (14)
src/synthorg/security/audit.py (1)
76-142: LGTM!The
query()method extension is well-implemented:
- New
action_typeanduntilfilters are correctly AND-combined with existing filters- The
since > untilvalidation properly logs before raisingValueError- Filter logic at lines 133-138 correctly excludes non-matching entries
src/synthorg/budget/coordination_store.py (1)
22-38: LGTM on the model definition.
CoordinationMetricsRecordcorrectly usesfrozen=True,allow_inf_nan=False, andNotBlankStrfor identifier fields per coding guidelines.src/synthorg/api/app.py (3)
761-766: LGTM on the default trust service builder.
_build_default_trust_service()correctly constructs a no-opTrustServiceusingDisabledTrustStrategy, which safely handles trust queries when trust is not explicitly configured.
994-1000: LGTM on control-plane service auto-wiring.All three services (
audit_log,coordination_metrics_store,trust_service) are now auto-instantiated when not injected, addressing the previous review concern abouttrust_servicestayingNone.
1023-1025: LGTM on AppState wiring.The new services are correctly passed to
AppStateconstructor matching the signature instate.py.src/synthorg/api/controllers/coordination_metrics.py (1)
42-96: LGTM!The controller correctly:
- Validates
since <= untilbefore querying (addressing the previous review concern)- Applies a safety cap via
_MAX_METRICS_QUERY- Logs the query with structured kwargs
- Returns properly paginated results
tests/unit/api/controllers/test_coordination_metrics.py (1)
161-180: LGTM on the is_quadratic assertion.Line 180 now correctly asserts
msg_oh["is_quadratic"] is Truerather than just checking key presence, addressing the previous review feedback.src/synthorg/api/controllers/audit.py (1)
77-80: LGTM on time window validation.Properly rejects inverted time windows with a clear error message.
src/synthorg/api/controllers/agents.py (3)
107-125: LGTM on TrustSummary model.The cross-field validator correctly enforces that
scorerequireslast_evaluated_atto be set, preventing inconsistent trust state representations.
128-154: LGTM on PerformanceSummary model.The validator correctly prevents a
trendfrom being set when both scores areNone, which would be semantically meaningless.
508-515: LGTM on last_active_at derivation.The implementation correctly addresses the previous review concern by fetching the most recent lifecycle event to derive
last_active_at.docs/design/page-structure.md (3)
86-86: LGTM on Agent Detail endpoint list update.Correctly adds
GET /agents/{name}/healthto the documented API surface.
217-217: LGTM on Settings endpoint list update.Correctly documents the new security export/import, audit query, and coordination metrics endpoints.
496-497: LGTM on controller-to-page mapping.The new
CoordinationMetricsControllerandAuditControllerare now mapped to their respective Settings namespace pages, maintaining the "No orphans" claim.
| def _extract_quality_trend( | ||
| snapshot: Any, | ||
| ) -> TrendDirection | None: | ||
| """Extract the quality trend direction from a performance snapshot. | ||
|
|
||
| Args: | ||
| snapshot: Performance snapshot with a ``trends`` collection | ||
| (typically from ``PerformanceTracker.get_snapshot``). | ||
|
|
||
| Returns: | ||
| The ``TrendDirection`` for the "quality" metric, or ``None`` | ||
| if no quality trend is recorded in the snapshot. | ||
| """ | ||
| for t in snapshot.trends: | ||
| if t.metric_name == "quality": | ||
| direction: TrendDirection = t.direction | ||
| return direction | ||
| logger.debug( | ||
| API_AGENT_HEALTH_TREND_MISSING, | ||
| trend_count=len(snapshot.trends), | ||
| ) | ||
| return None |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider using a typed protocol or the concrete snapshot type instead of Any.
The snapshot parameter is typed as Any but is expected to have a trends attribute with metric_name and direction fields. Using the concrete AgentPerformanceSnapshot type (from the relevant code snippet) would provide better type safety and IDE support.
♻️ Suggested signature
+from synthorg.hr.performance.models import AgentPerformanceSnapshot
+
def _extract_quality_trend(
- snapshot: Any,
+ snapshot: AgentPerformanceSnapshot,
) -> TrendDirection | None:🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/controllers/agents.py` around lines 532 - 553, The parameter
snapshot is currently typed as Any even though _extract_quality_trend expects an
object with a trends iterable containing items with metric_name and direction;
replace the Any with a concrete type (preferably AgentPerformanceSnapshot) or
define and use a small typing.Protocol (e.g. has attribute trends:
Iterable[ItemType]) that exposes metric_name and direction, import or declare
TrendDirection-compatible item type if needed, and update the function signature
and imports accordingly so the IDE/typechecker recognizes snapshot.trends and
its elements.
| entries = app_state.audit_log.query( | ||
| agent_id=agent_id, | ||
| tool_name=tool_name, | ||
| action_type=action_type, | ||
| verdict=verdict, | ||
| since=since, | ||
| until=until, | ||
| limit=_MAX_AUDIT_QUERY, | ||
| ) | ||
| page, meta = paginate(entries, offset=offset, limit=limit) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
🧩 Analysis chain
🌐 Web query:
Best practices for API pagination when result sets are capped
💡 Result:
Best practices when an API paginates but the total results you can access are capped
1) Prefer cursor/keyset pagination over offset for large datasets
- Use an opaque cursor/continuation token (not page numbers) and require a deterministic sort (e.g.,
(created_at, id)), so paging stays stable as data changes. Cursor pagination is generally more consistent than offset pagination. [3][4] - If you provide a “next page” URL/token, instruct clients to use it verbatim (don’t reconstruct it). [1][2]
2) Make the cap explicit and machine-detectable
When a query matches more rows than you will return (ever), return signals so clients can react safely:
is_truncated: true(or similar) /result_window_exceeded: true- the effective cap (e.g.,
max_accessible_results: 10000) - a human-meaningful message: “Refine filters to access remaining results”
Some platforms hard-cap “deep paging” (for example, Jira’s search can error beyond a configuredmax_result_window, default 10,000). [6]
3) Provide an “escape hatch” for full exports
If users legitimately need all matching data, pagination alone shouldn’t be the only path:
- async export jobs (create job → poll → download)
- bulk download endpoints
- server-side snapshots (see
#5)
This avoids encouraging clients to hammer page-by-page until they hit a cap.
4) Design for “refine and resume” past the cap
If the cap is per-query (common in search):
- Document recommended partition strategies to retrieve everything via multiple narrower queries (e.g., date ranges, prefix partitions, ID ranges), so each partition stays under the cap. This is the typical workaround when an API will only return the first N matches. [7][8]
- Ensure your filters align with indexed fields so partitioning is efficient.
5) If consistency matters, offer snapshot semantics
For mutable datasets, cursor paging can still shift unless you support a snapshot:
- A “snapshot token” / PIT-style token / export job acts like a point-in-time view.
Elasticsearch’s scroll keeps a search context and returns results as-of the initial request (a snapshot), ignoring later changes. [5]
6) Enforce and communicate page-size limits
- Enforce
limitmax (server-side) and document it; if exceeded, either clamp to max or return a clear error. Microsoft Graph notes APIs may ignore, clamp, or error when$topexceeds the maximum. [1] - Consider returning
has_more(or equivalent) so clients don’t guess. Stripe useshas_moreplusstarting_afterfor manual pagination. [9]
7) Return navigation links, not arithmetic
- Provide
nextLink/Linkheaders (or alinks.next) that fully encode the continuation state and query params; omit it entirely on the last page (notnull). [2]
8) Document “cap-aware” client guidance
In your docs and SDK examples, show clients how to:
- stop when
nextLink/has_moreends (normal completion) - stop early when
is_truncatedis true (cap hit) and prompt the user to add filters / run an export job - retry responsibly (rate limits), and avoid parallel “deep page” walkers by default
Key rule: pagination should answer “how do I traverse results?”; caps require an additional contract: “what happens when there are more results than you will let me traverse, and how do I get the rest (filter/partition/export)?” [6][8]
🏁 Script executed:
# First, check the audit.py file to understand the pagination implementation
fd -t f "audit\.py" src/synthorg/api/controllers/ --exec wc -l {} \;Repository: Aureliolo/synthorg
Length of output: 103
🏁 Script executed:
# Get the full context of the file to examine lines mentioned in review
head -110 src/synthorg/api/controllers/audit.py | tail -75Repository: Aureliolo/synthorg
Length of output: 2696
🏁 Script executed:
# Find the paginate() function definition
fd -t f "\.py" src/ -exec grep -l "def paginate" {} \;Repository: Aureliolo/synthorg
Length of output: 268
🏁 Script executed:
# Check for AuditLog class and query method
fd -t f "\.py" src/ -exec grep -l "class AuditLog\|def query" {} \; | head -10Repository: Aureliolo/synthorg
Length of output: 281
🏁 Script executed:
# Find paginate function properly
rg "def paginate" src/ -A 5Repository: Aureliolo/synthorg
Length of output: 360
🏁 Script executed:
# Find PaginatedResponse definition
rg "class PaginatedResponse|PaginatedResponse\[" src/ -B 2 -A 10Repository: Aureliolo/synthorg
Length of output: 21721
🏁 Script executed:
# Check coordination_metrics controller mentioned in review for comparison
fd -name "coordination_metrics.py" src/synthorg/api/controllers/Repository: Aureliolo/synthorg
Length of output: 292
🏁 Script executed:
# Find coordination_metrics.py file
fd -name "coordination_metrics.py" src/synthorg/api/controllers/Repository: Aureliolo/synthorg
Length of output: 292
🏁 Script executed:
# Get the full paginate function implementation
cat src/synthorg/api/pagination.pyRepository: Aureliolo/synthorg
Length of output: 1631
🏁 Script executed:
# Check workflow_versions.py which uses a different pattern (count separately)
head -120 src/synthorg/api/controllers/workflow_versions.py | tail -50Repository: Aureliolo/synthorg
Length of output: 1600
🏁 Script executed:
# Check the AuditLog class and query method to see what it returns
rg "class AuditLog" src/ -A 30Repository: Aureliolo/synthorg
Length of output: 2038
🏁 Script executed:
# Also check if audit_log.query() returns a tuple with count or just entries
rg "def query" src/ -B 5 -A 15 | grep -A 15 "audit_log\|AuditLog"Repository: Aureliolo/synthorg
Length of output: 44
🏁 Script executed:
# Find the query method in AuditLog class
rg "def query" src/synthorg/security/audit.py -A 30Repository: Aureliolo/synthorg
Length of output: 1152
🏁 Script executed:
# Check the complete AuditLog class
wc -l src/synthorg/security/audit.pyRepository: Aureliolo/synthorg
Length of output: 96
🏁 Script executed:
# Read the audit.py file to see query method
cat src/synthorg/security/audit.py | head -200Repository: Aureliolo/synthorg
Length of output: 5169
Consider adding truncation signaling to audit pagination metadata.
When query results exceed the 10,000-entry cap, pagination.total will report the truncated count rather than the actual matching total. This is a documented tradeoff, but API consumers may misinterpret empty pages at high offsets as "no more data" when the true total is higher.
The paginate() function accepts an optional total parameter that can communicate the actual count. To improve this, you could:
- Add
is_truncatedflag to the response when_MAX_AUDIT_QUERYis reached - Return
has_morealongside pagination metadata to guide client iteration - Extend
AuditLog.query()to return both results and true total count, then passtotal=true_counttopaginate()
This pattern is consistent with coordination_metrics, so addressing it here would benefit both controllers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/controllers/audit.py` around lines 82 - 91, The current
audit pagination uses app_state.audit_log.query(...) and paginate(entries, ...)
but doesn't signal when results hit the _MAX_AUDIT_QUERY cap, which can mislead
clients; update AuditLog.query (or add an alternate method) to return both the
result list and the true matching total (e.g., (entries, true_total)), then call
paginate(entries, offset=offset, limit=limit, total=true_total) and add
is_truncated = (len(entries) >= _MAX_AUDIT_QUERY) and has_more = (offset +
len(page) < true_total or is_truncated) into the response metadata so clients
can detect truncation and whether to continue fetching.
| security_cfg = app_state.config.security | ||
| dumped = security_cfg.model_dump(mode="json") |
There was a problem hiding this comment.
Export should resolve the effective security config, not app_state.config.
import_security_config() persists through SettingsService, but this endpoint dumps app_state.config.security instead of the resolved settings view. That lets /settings/security/export diverge from the effective DB > env > YAML > code config after runtime overrides/imports. Resolve the current security config through the settings/config-resolver path before serializing it.
Based on learnings: "Settings package (settings/): runtime-editable settings persistence (DB > env > YAML > code defaults)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/controllers/settings.py` around lines 538 - 539, The export
currently serializes app_state.config.security directly; instead call the
settings resolver/service used for runtime persistence (the same SettingsService
used by import_security_config) to obtain the resolved/effective security
settings and serialize that. Replace the use of app_state.config.security in the
export handler with the resolved object returned from the settings resolver
(e.g., SettingsService.get_effective_config("security") or
SettingsResolver.resolve("security") — whatever concrete method exists on
app_state.settings_service), then call model_dump on that resolved instance
before returning.
| await _persist_security_settings( | ||
| app_state.settings_service, | ||
| validated, | ||
| ) |
There was a problem hiding this comment.
This import can partially apply a policy while reporting full success.
_persist_security_settings() does independent svc.set() calls, so a failure on a later field leaves earlier writes committed. A missing mapped key is only logged at DEBUG, and the handler then returns validated.model_dump() as if the whole document is active, even though only the _SECURITY_SETTING_FIELDS subset was attempted. Persist the import as one batch/transaction and build the response from the effective applied config, or return an explicit applied/ignored field breakdown.
Also applies to: 601-607, 613-647
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/controllers/settings.py` around lines 589 - 592, The import
currently calls _persist_security_settings which issues independent svc.set()
calls so partial failures can leave a partially-applied policy while the handler
returns validated.model_dump() as if everything applied; change
_persist_security_settings (or add a new batched method) to apply the
_SECURITY_SETTING_FIELDS in a single atomic operation/transaction via
app_state.settings_service (or collect all key→value pairs and call a single
bulk set/update API), and on failure return a clear applied/ignored breakdown
built from the effective configuration read back from the service (do not return
validated.model_dump() unconditionally); alternatively, if atomic persistence
isn’t possible, make _persist_security_settings accumulate successes and
failures and have the controller return an explicit applied/ignored field map
instead of the full validated model.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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/budget/coordination_store.py`:
- Around line 68-76: The state-transition log in record() is using logger.debug
but must be INFO-level; update the logging call in the record method (the one
that emits COORD_METRICS_COLLECTION_COMPLETED with task_id, agent_id, team_size)
to use logger.info instead of logger.debug so appends/evictions are visible as
state transitions while keeping the same message and context fields.
- Around line 78-129: The query method short-circuits when it hits the limit so
callers cannot determine the true total-match count; change
CoordinationStore.query to compute the full total of matching
CoordinationMetricsRecord entries while still returning only up to `limit`
newest records: iterate through self._records (currently
reversed(self._records)), apply the same filters (task_id, agent_id, since,
until) and maintain two counters/collections — one for accumulating results up
to `limit` and another (an integer `total_matches`) incremented for every
matching record — then return the result tuple and ensure the calling controller
(coordination_metrics.py) receives and uses `total_matches` (pass
`total=total_matches` into paginate(...)) so pagination.total is accurate.
In `@tests/unit/api/controllers/test_audit.py`:
- Around line 81-88: For every test in tests/unit/api/controllers/test_audit.py
that calls resp.json() (e.g., the block using test_client.get(...,
params={"agent_id": "alice"}, headers=_HEADERS) which assigns resp), assert the
HTTP response status before decoding JSON by adding assert resp.status_code ==
200 immediately after the test_client.get call; do this for the blocks around
the ranges mentioned (lines ~81-88, 97-104, 122-124, 142-144, 164-166, 179-183,
231-233) so failures are caught at the HTTP boundary rather than when calling
resp.json().
- Around line 74-144: Multiple nearly identical tests (test_filter_by_agent_id,
test_filter_by_verdict, test_filter_by_action_type, test_filter_by_tool_name)
should be merged into a single parameterized pytest test; create one test (e.g.,
test_filter_by_field) decorated with `@pytest.mark.parametrize` that takes
parameters for the field name, the matching value, the non-matching value, and
the expected response key, then inside use audit_log.record(_make_entry(...))
twice (one matching, one non-matching), call
test_client.get("/api/v1/security/audit", params={field: value},
headers=_HEADERS), and assert pagination total == 1 and
body["data"][0][expected_key] == value; keep using existing fixtures audit_log
and test_client and the helper _make_entry to construct entries and ensure
parameter list covers ("agent_id","alice","bob","agent_id"),
("verdict","deny","allow","verdict"),
("action_type","deploy:production","code:write","action_type"),
("tool_name","file_read","code_write","tool_name").
In `@tests/unit/api/controllers/test_coordination_metrics.py`:
- Around line 71-73: Add an explicit success-status assertion before decoding
JSON: for each test that calls resp.json() (the ones using the resp variable and
lines where assert body[...] is used), insert assert resp.status_code == 200
immediately before calling resp.json(); update all mentioned test sites (the
resp usages at the ranges referenced: near the assertions of
body["pagination"]["total"], and the other ranges called out) so the pattern
becomes an assertion on resp.status_code followed by body = resp.json().
🪄 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: 51c460f0-8e27-4711-9e1e-a63a1bbe2773
📒 Files selected for processing (4)
docs/design/operations.mdsrc/synthorg/budget/coordination_store.pytests/unit/api/controllers/test_audit.pytests/unit/api/controllers/test_coordination_metrics.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). (5)
- GitHub Check: Dashboard Test
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Backend
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotations— Python 3.14 has PEP 649Use
except A, B:(no parentheses) for exception syntax — PEP 758 rule enforced by ruff on Python 3.14All public functions must have type hints; use mypy strict mode
Google-style docstrings required on public classes and functions, enforced by ruff D rules
Create new objects instead of mutating existing ones. For non-Pydantic internal collections, use
copy.deepcopy()at construction andMappingProxyTypewrapping for read-only enforcement.Use frozen Pydantic models for config/identity; separate mutable-via-copy models for runtime state. Never mix static config fields with mutable runtime fields.
Use Pydantic v2 with
BaseModel,model_validator,computed_field,ConfigDict. Useallow_inf_nan=Falsein allConfigDictdeclarations. Use@computed_fieldfor derived values. UseNotBlankStrfor all identifier/name fields including optional and tuple variants instead of manual whitespace validators.Prefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new code instead of barecreate_taskFunctions must be under 50 lines; files under 800 lines
Handle errors explicitly, never silently swallow. Validate at system boundaries (user input, external APIs, config files).
Use 88-character line length (ruff)
Files:
tests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/controllers/test_audit.pysrc/synthorg/budget/coordination_store.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use pytest markers:
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slow. Maintain 80% minimum coverage.Use
@pytest.mark.parametrizefor testing similar cases. Do not add per-filepytest.mark.timeout(30)markers (global timeout already set); only use non-default overrides liketimeout(60)when needed.Tests must use vendor-agnostic names:
test-provider,test-small-001, etc. Never use real vendor names in tests.Use Hypothesis for property-based testing with
@given+@settings. Configure profiles intests/conftest.py:ci(10 examples, deterministic),dev(1000 examples),fuzz(10,000 examples, no deadline),extreme(500,000 examples). Control viaHYPOTHESIS_PROFILEenv var. When Hypothesis finds a failure, fix the bug and add an explicit@example(...)decorator to permanently cover the case in CI.For timing-sensitive tests, mock
time.monotonic()andasyncio.sleep()to make them deterministic. For tasks that must block indefinitely until cancelled, useasyncio.Event().wait()instead ofasyncio.sleep(large_number).
Files:
tests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/controllers/test_audit.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/controllers/test_coordination_metrics.pytests/unit/api/controllers/test_audit.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic must import
from synthorg.observability import get_loggerthen assignlogger = get_logger(__name__). Never useimport logging/logging.getLogger()/print()in application code (exception: observability setup modules may use stdlib logging).Always use constants from domain-specific modules under
synthorg.observability.eventsfor event names (e.g.,API_REQUEST_STARTEDfromevents.api). Import directly:from synthorg.observability.events.<domain> import EVENT_CONSTANT. Use structured kwargs:logger.info(EVENT, key=value)— neverlogger.info("msg %s", val).All provider calls go through
BaseCompletionProviderwhich applies retry + rate limiting automatically. Never implement retry logic in driver subclasses or calling code. SetRetryConfigandRateLimiterConfigper-provider inProviderConfig. HandleRetryExhaustedErrorat the engine layer for fallback chains.
Files:
src/synthorg/budget/coordination_store.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names:
example-provider,example-large-001,example-medium-001,example-small-001, orlarge/medium/smallaliases. Vendor names may only appear in: (1) Operations design page (docs/design/operations.md), (2).claude/files, (3) third-party imports, (4) provider presets (src/synthorg/providers/presets.py). Tests must usetest-provider,test-small-001, etc.
Files:
src/synthorg/budget/coordination_store.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/budget/coordination_store.py
🧠 Learnings (23)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. Do not silently diverge from the design spec -- every deviation needs explicit user approval. When approved deviations occur, update the relevant `docs/design/` page.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Every implementation plan must be presented to the user for accept/deny before coding starts. At every phase, be critical and surface improvements as suggestions, not silent changes. Prioritize issues by dependency order.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Never skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Commit messages must follow `<type>: <description>` format — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Signed commits required on `main` via branch protection — all commits must be GPG/SSH signed.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Use branch naming convention `<type>/<slug>` from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Pre-commit hooks enforce: ruff check+format on Python files, hadolint on Dockerfile, golangci-lint + go vet on CLI files, no-em-dashes, no-redundant-timeout, eslint-web on web dashboard files (zero warnings).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Always use `-n 8` when running pytest locally to enable parallelism; never run tests sequentially. Pre-push hooks enforce this via `enforce-parallel-tests` hookify rule.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Never create a PR directly with `gh pr create` (blocked by hookify). Always use `/pre-pr-review` to create PRs — it runs automated checks and review agents before creating the PR. Use `/pre-pr-review quick` for trivial/docs-only changes.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: After finishing an issue implementation, always create a feature branch (`<type>/<slug>`), commit, and push — do not create a PR automatically. Do not leave work uncommitted on main.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Never use `cd` in Bash commands — the working directory is already set to project root. Use absolute paths or run commands directly. Exception: `bash -c "cd <dir> && <cmd>"` is safe (runs in child process). Use this for tools without a `-C` flag.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Never use Bash to write or modify files — use the Write or Edit tools. Do not use `cat >`, `cat << EOF`, `echo >`, `echo >>`, `sed -i`, or `tee` to create or modify files. Read-only/inspection uses like piping to stdout are fine.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: See `web/CLAUDE.md` for web dashboard commands, design system, and component inventory.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: See `cli/CLAUDE.md` for CLI commands, flags, and reference. Use `go -C cli` (never `cd cli`).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: When Hypothesis finds a failing property-based test, the shrunk example is saved to `~/.synthorg/hypothesis-examples/` but is not replayed automatically. Do not just rerun and move on — read the failing example, fix the underlying bug, and add an explicit `example(...)` decorator to permanently cover the case.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T08:14:54.519Z
Learning: Fix everything valid when review agents find issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to changes) — never skip or defer.
📚 Learning: 2026-03-21T11:08:01.542Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T11:08:01.542Z
Learning: When implementation deviates from the spec (better approach found, scope evolved, etc.), alert the user and explain why — user decides whether to proceed or update the spec. Do NOT silently diverge — every deviation needs explicit user approval.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-30T10:41:40.176Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-30T10:41:40.176Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations from spec occur
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)
Applied to files:
docs/design/operations.md
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to docs/design/**/*.md : When approved deviations from the design spec occur, update the relevant `docs/design/` page to reflect the new reality
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 7 design pages (index, agents, organization, communication, engine, memory, operations).
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Security: 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:
docs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/memory/**/*.py : Memory package (memory/): pluggable MemoryBackend protocol, backends/ (Mem0 adapter), retrieval pipeline (ranking, RRF fusion, injection, formatting, non-inferable filtering), shared org memory (org/), consolidation/archival (density-aware: DensityClassifier, AbstractiveSummarizer, ExtractivePreserver, DualModeConsolidationStrategy)
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to src/ai_company/!(observability)/**/*.py : All error paths must log at WARNING or ERROR with context before raising.
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-15T16:55:07.730Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:55:07.730Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising.
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation, internal flow, entry/exit of key functions
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to src/ai_company/!(observability)/**/*.py : Use event name constants from domain-specific modules under `ai_company.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`). Import directly: `from ai_company.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from the domain-specific module under `synthorg.observability.events` in logging calls
Applied to files:
src/synthorg/budget/coordination_store.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/budget/coordination_store.py
🔇 Additional comments (4)
docs/design/operations.md (2)
411-433: Good expansion of coordination metrics docs and config examples.The 9-metric table and
coordination_metrics.collectexample are aligned and clear, and the new collect values match the configured metric naming style.
1847-1855: API gap matrix update looks correct and actionable.Marking G2–G5 as implemented with concrete endpoint contracts, plus the explicit
{id}→{name}note and updated prioritization, makes this section much more operationally reliable.tests/unit/api/controllers/test_coordination_metrics.py (2)
161-181: Good coverage for surfaced derived metric flag.The assertion on
message_overhead.is_quadraticverifies value correctness, not just field presence—nice hardening.
74-159: 🛠️ Refactor suggestion | 🟠 MajorConsolidate repetitive filter/pagination tests with
@pytest.mark.parametrize.The cases in Line 74-159 are structurally similar and should be parameterized to reduce duplication and improve maintainability.
As per coding guidelines: "Use
@pytest.mark.parametrizefor testing similar cases."⛔ Skipped due to learnings
Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-17T22:08:13.456Z Learning: Applies to tests/**/*.py : Prefer `pytest.mark.parametrize` for testing similar cases.Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-15T18:28:13.207Z Learning: Applies to tests/**/*.py : Parametrize: Prefer pytest.mark.parametrize for testing similar cases.Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-31T20:29:10.177Z Learning: Applies to tests/**/*.py : Prefer `pytest.mark.parametrize` for testing similar casesLearnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-04-02T07:18:02.381Z Learning: Applies to tests/**/*.py : Prefer `pytest.mark.parametrize` for testing similar casesLearnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-04-07T22:12:30.142Z Learning: Applies to tests/**/*.py : Prefer `pytest.mark.parametrize` for testing similar casesLearnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-04-07T22:12:30.142Z Learning: Applies to tests/**/*.py : Use markers: `pytest.mark.unit`, `pytest.mark.integration`, `pytest.mark.e2e`, `pytest.mark.slow` for test classificationLearnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-04-02T09:04:54.709Z Learning: Applies to tests/**/*.py : Use pytest markers: `pytest.mark.unit`, `pytest.mark.integration`, `pytest.mark.e2e`, `pytest.mark.slow`Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-15T18:28:13.207Z Learning: Applies to tests/**/*.py : Test markers: pytest.mark.unit, pytest.mark.integration, pytest.mark.e2e, pytest.mark.slow. Coverage: 80% minimum (enforced in CI).Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-17T22:08:13.456Z Learning: Applies to tests/**/*.py : Test markers: `pytest.mark.unit`, `pytest.mark.integration`, `pytest.mark.e2e`, `pytest.mark.slow`. Coverage: 80% minimum. Async: `asyncio_mode = 'auto'` — no manual `pytest.mark.asyncio` needed. Timeout: 30 seconds per test. Parallelism: `pytest-xdist` via `-n auto` — ALWAYS include `-n auto` when running pytest, never run tests sequentially.
| resp = test_client.get( | ||
| "/api/v1/security/audit", | ||
| params={"agent_id": "alice"}, | ||
| headers=_HEADERS, | ||
| ) | ||
| body = resp.json() | ||
| assert body["pagination"]["total"] == 1 | ||
| assert body["data"][0]["agent_id"] == "alice" |
There was a problem hiding this comment.
Assert response status before decoding JSON in each test.
Several tests call resp.json() without first checking resp.status_code == 200. Add that assertion in each case so failures are surfaced at the HTTP boundary.
Also applies to: 97-104, 122-124, 142-144, 164-166, 179-183, 231-233
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/unit/api/controllers/test_audit.py` around lines 81 - 88, For every
test in tests/unit/api/controllers/test_audit.py that calls resp.json() (e.g.,
the block using test_client.get(..., params={"agent_id": "alice"},
headers=_HEADERS) which assigns resp), assert the HTTP response status before
decoding JSON by adding assert resp.status_code == 200 immediately after the
test_client.get call; do this for the blocks around the ranges mentioned (lines
~81-88, 97-104, 122-124, 142-144, 164-166, 179-183, 231-233) so failures are
caught at the HTTP boundary rather than when calling resp.json().
03aa6df to
8c2da57
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (5)
src/synthorg/api/controllers/agents.py (1)
508-521:⚠️ Potential issue | 🟠 MajorUse
AgentRegistryService.get(agent_id)as the source of lifecycle fields (contract mismatch).Line 508-Line 521 derives
last_active_atfrom lifecycle events and usesidentity.status, but#1118specifies lifecycle status andlast_active_atshould come fromAgentRegistryService.get(agent_id). Please align the data source to avoid drift between registry state and event-history derivation.Based on learnings: If implementation deviates from the spec (better approach found, scope evolved, etc.), alert the user and explain why. Do NOT silently diverge — every deviation needs explicit user approval.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/agents.py` around lines 508 - 521, The handler currently derives lifecycle_status from identity.status and last_active_at from app_state.persistence.lifecycle_events.list_events, which diverges from the spec; call AgentRegistryService.get(agent_id) and use the returned registry object's lifecycle fields (e.g., lifecycle_status and last_active_at) as the source of truth when constructing AgentHealthResponse instead of identity.status or the events query (remove or keep events only for supplemental info), and ensure the AgentHealthResponse population uses those registry fields so the contract matches AgentRegistryService.get(agent_id).tests/unit/api/controllers/test_settings.py (1)
295-312:⚠️ Potential issue | 🟠 MajorMutate a persistable field in the round-trip test.
This still passes against a validate-only or partial-apply import path. Flip one field that the endpoint is supposed to persist, then assert the second export reflects that change.
🧪 Suggested test change
resp1 = test_client.get( "/api/v1/settings/security/export", headers=auth_headers, ) + assert resp1.status_code == 200 config1 = resp1.json()["data"]["config"] + mutated = { + **config1, + "audit_enabled": not config1["audit_enabled"], + } - test_client.post( + import_resp = test_client.post( "/api/v1/settings/security/import", - json={"config": config1}, + json={"config": mutated}, headers=auth_headers, ) + assert import_resp.status_code == 201 resp2 = test_client.get( "/api/v1/settings/security/export", headers=auth_headers, ) + assert resp2.status_code == 200 config2 = resp2.json()["data"]["config"] - assert config1 == config2 + assert config2["audit_enabled"] == mutated["audit_enabled"]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/api/controllers/test_settings.py` around lines 295 - 312, The round-trip test currently exports config1, re-imports it, and re-exports to compare config2, but never mutates a persistable field so it can pass a validate-only or partial apply import; update the test around the "/api/v1/settings/security/export" and "/api/v1/settings/security/import" calls to flip a known persistable field on config1 (for example toggle a boolean or change a string field present in the exported "config"), then POST the modified config to the "/api/v1/settings/security/import" endpoint and assert that the subsequent export (config2) reflects that modified value (use the existing variables config1 and config2 to locate where to change and assert).src/synthorg/api/controllers/settings.py (2)
589-607:⚠️ Potential issue | 🔴 Critical
/settings/security/importstill reports full success for partial writes.
SecurityConfigvalidates the full document, but_persist_security_settings()only persists four fields and does so one key at a time. That silently drops settings likeenforcement_mode, rule-engine config, deny/allow lists, classifier settings, etc., and a mid-loop failure can leave a partially applied policy while the response echoesvalidated.model_dump()as if the whole config is live. For a security import endpoint, this needs an atomic/batched persistence path or it must reject unsupported fields and return the re-read effective config instead.Also applies to: 613-647
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/settings.py` around lines 589 - 607, The import endpoint validates the entire SecurityConfig but _persist_security_settings writes only four keys one-by-one, causing silent partial writes; change the import flow in the controller handling /settings/security/import to either (A) perform an atomic/batched persistence using a single service method (e.g., add or extend app_state.settings_service with a new persist_security_bundle or update_security_config that writes all supported fields in one transaction) and on success return the re-read effective config (not validated.model_dump()), or (B) validate and reject unsupported fields up-front (compare validated fields against the set persisted by _persist_security_settings) so the endpoint returns an error instead of partially applying; ensure the response uses the actual stored config from app_state.settings_service (read-after-write) and that errors from the persistence call propagate to the API response rather than logging success and returning the original validated payload.
537-539:⚠️ Potential issue | 🟠 MajorExport the resolved security namespace, not
app_state.config.security.This bypasses the settings precedence path, so
/settings/security/exportcan drift from DB overrides, environment overrides, or a prior import while still reporting success. Build the payload from the effective security config returned by the settings service/resolver instead.Based on learnings: "Settings package (settings/): runtime-editable settings persistence (DB > env > YAML > code defaults)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/settings.py` around lines 537 - 539, The export currently reads directly from app_state.config.security (security_cfg) and dumps it, bypassing runtime overrides; instead obtain the effective/resolved security namespace from the settings resolver/service on the AppState and dump that. Replace the use of app_state.config.security with the resolver call on AppState (e.g., state.settings.resolve_namespace("security") or the project’s settings service API) to get the runtime-effective security config, then call model_dump(mode="json") on that resolved object before returning.src/synthorg/api/controllers/audit.py (1)
82-91:⚠️ Potential issue | 🟠 MajorThe 10k fetch cap breaks pagination semantics.
paginate()only sees the first_MAX_AUDIT_QUERYrows returned byaudit_log.query(), sopagination.totalsilently tops out at 10,000 and deeper pages become unreachable even when more audit entries match. This endpoint needs either the true match count from the query layer or explicit truncation metadata in the response.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/audit.py` around lines 82 - 91, The pagination currently calls app_state.audit_log.query(...) with a hard cap _MAX_AUDIT_QUERY and then runs paginate(entries, offset, limit), causing paginate to see only the first 10k rows and return an incorrect total; change the flow so the query layer returns the true matching count (e.g. query returns (entries, total_matches)) or return explicit truncation metadata, then pass the true total (or a truncated flag) into the response meta instead of relying on paginate's view of entries; update references to app_state.audit_log.query, entries, paginate, page, and meta accordingly so pagination.total reflects the real total or meta contains a truncated=true indicator.
🤖 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/controllers/audit.py`:
- Around line 49-50: The since and until parameters must be annotated with
pydantic.AwareDatetime to enforce timezone-aware datetimes at the API boundary;
import AwareDatetime from pydantic and replace the plain datetime type hints for
since and until in both places they appear (the audit endpoint parameters shown
with since/until and the second occurrence around lines 87–88) so Pydantic will
reject naive datetimes before calling audit_log.query().
In `@src/synthorg/api/controllers/coordination_metrics.py`:
- Around line 48-49: The route currently accepts naive datetimes for the window
parameters `since` and `until` (typed as `datetime | None`) but the downstream
code expects timezone-aware `AwareDatetime`; add validation in the controller to
ensure both `since` and `until` (when provided) have non-None tzinfo (i.e., are
timezone-aware) and return a 400/HTTPException with a clear message if they are
naive, referencing the `since` and `until` parameters; apply the same validation
to the other occurrence of these parameters at lines 82–83 so the store
(coordination_store.py comparisons of `computed_at`) never receives naive
datetimes.
In `@src/synthorg/budget/coordination_store.py`:
- Around line 81-82: Update the query() method signature in
coordination_store.py to use the project's identifier type for filters by
changing the parameter types of task_id and agent_id from plain str | None to
NotBlankStr | None; import NotBlankStr from core.types and ensure any callers or
internal validation rely on the typed values rather than manual whitespace
checks so blank/whitespace IDs cannot be passed through.
In `@tests/unit/security/test_audit.py`:
- Around line 360-369: Add a negative test asserting AuditLog.query raises
ValueError when since > until: inside the same test class (near
test_filter_by_since_and_until) create a datetime t = datetime(2026, 4, 1,
tzinfo=UTC) and call log.query(since=t + timedelta(hours=2), until=t +
timedelta(hours=1)) wrapped with pytest.raises(ValueError) to ensure
AuditLog.query enforces inverted time-window rejection; reference the AuditLog
instance and the query(...) method in the assertion.
---
Duplicate comments:
In `@src/synthorg/api/controllers/agents.py`:
- Around line 508-521: The handler currently derives lifecycle_status from
identity.status and last_active_at from
app_state.persistence.lifecycle_events.list_events, which diverges from the
spec; call AgentRegistryService.get(agent_id) and use the returned registry
object's lifecycle fields (e.g., lifecycle_status and last_active_at) as the
source of truth when constructing AgentHealthResponse instead of identity.status
or the events query (remove or keep events only for supplemental info), and
ensure the AgentHealthResponse population uses those registry fields so the
contract matches AgentRegistryService.get(agent_id).
In `@src/synthorg/api/controllers/audit.py`:
- Around line 82-91: The pagination currently calls
app_state.audit_log.query(...) with a hard cap _MAX_AUDIT_QUERY and then runs
paginate(entries, offset, limit), causing paginate to see only the first 10k
rows and return an incorrect total; change the flow so the query layer returns
the true matching count (e.g. query returns (entries, total_matches)) or return
explicit truncation metadata, then pass the true total (or a truncated flag)
into the response meta instead of relying on paginate's view of entries; update
references to app_state.audit_log.query, entries, paginate, page, and meta
accordingly so pagination.total reflects the real total or meta contains a
truncated=true indicator.
In `@src/synthorg/api/controllers/settings.py`:
- Around line 589-607: The import endpoint validates the entire SecurityConfig
but _persist_security_settings writes only four keys one-by-one, causing silent
partial writes; change the import flow in the controller handling
/settings/security/import to either (A) perform an atomic/batched persistence
using a single service method (e.g., add or extend app_state.settings_service
with a new persist_security_bundle or update_security_config that writes all
supported fields in one transaction) and on success return the re-read effective
config (not validated.model_dump()), or (B) validate and reject unsupported
fields up-front (compare validated fields against the set persisted by
_persist_security_settings) so the endpoint returns an error instead of
partially applying; ensure the response uses the actual stored config from
app_state.settings_service (read-after-write) and that errors from the
persistence call propagate to the API response rather than logging success and
returning the original validated payload.
- Around line 537-539: The export currently reads directly from
app_state.config.security (security_cfg) and dumps it, bypassing runtime
overrides; instead obtain the effective/resolved security namespace from the
settings resolver/service on the AppState and dump that. Replace the use of
app_state.config.security with the resolver call on AppState (e.g.,
state.settings.resolve_namespace("security") or the project’s settings service
API) to get the runtime-effective security config, then call
model_dump(mode="json") on that resolved object before returning.
In `@tests/unit/api/controllers/test_settings.py`:
- Around line 295-312: The round-trip test currently exports config1, re-imports
it, and re-exports to compare config2, but never mutates a persistable field so
it can pass a validate-only or partial apply import; update the test around the
"/api/v1/settings/security/export" and "/api/v1/settings/security/import" calls
to flip a known persistable field on config1 (for example toggle a boolean or
change a string field present in the exported "config"), then POST the modified
config to the "/api/v1/settings/security/import" endpoint and assert that the
subsequent export (config2) reflects that modified value (use the existing
variables config1 and config2 to locate where to change and assert).
🪄 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: 9593f89f-51e1-419d-894c-67aed4203e94
📒 Files selected for processing (22)
CLAUDE.mddocs/design/operations.mddocs/design/page-structure.mdsrc/synthorg/api/app.pysrc/synthorg/api/controllers/__init__.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/state.pysrc/synthorg/budget/coordination_store.pysrc/synthorg/engine/agent_engine.pysrc/synthorg/observability/events/api.pysrc/synthorg/security/audit.pytests/unit/api/conftest.pytests/unit/api/controllers/test_agents.pytests/unit/api/controllers/test_audit.pytests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/controllers/test_settings.pytests/unit/budget/test_coordination_store.pytests/unit/security/test_audit.pyweb/src/api/types.ts
| task_id: str | None = None, | ||
| agent_id: str | None = None, |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Use NotBlankStr | None for identifier filters in query().
task_id and agent_id are identifier fields, but the public method currently accepts plain str. Align these parameters with the project’s identifier contract to prevent blank/whitespace IDs from entering filter logic.
🔧 Proposed type-alignment patch
def query(
self,
*,
- task_id: str | None = None,
- agent_id: str | None = None,
+ task_id: NotBlankStr | None = None,
+ agent_id: NotBlankStr | None = None,
since: AwareDatetime | None = None,
until: AwareDatetime | None = None,
limit: int = 10_000,As per coding guidelines: Use NotBlankStr (from core.types) for all identifier/name fields — including optional variants — instead of manual whitespace validators.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/budget/coordination_store.py` around lines 81 - 82, Update the
query() method signature in coordination_store.py to use the project's
identifier type for filters by changing the parameter types of task_id and
agent_id from plain str | None to NotBlankStr | None; import NotBlankStr from
core.types and ensure any callers or internal validation rely on the typed
values rather than manual whitespace checks so blank/whitespace IDs cannot be
passed through.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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/controllers/audit.py`:
- Around line 44-50: Replace the loose string query parameter types in the audit
controller with the stricter boundary types: change agent_id, tool_name, and
action_type to use NotBlankStr (from core.types) instead of Annotated[str,...]
so blank identifiers are rejected, and replace verdict with the constrained
AuditVerdictStr type (or an equivalent enum/str alias) to validate verdict
values at the API boundary; update the function signature in the audit
controller where these parameters are declared and adjust any import statements
to import NotBlankStr and AuditVerdictStr from core.types.
- Around line 77-86: Before raising ClientException in the timezone and order
checks, log the validation failure at WARNING (or ERROR) including the
structured inputs and reason; specifically, log when (since is not None and
since.tzinfo is None) or (until is not None and until.tzinfo is None) and when
(since is not None and until is not None and since > until). Use the module
logger (e.g., logger) to emit a message that includes a domain event constant
imported from synthorg.observability.events (use the appropriate event name
constant from that module) and include a structured payload with keys like
"since", "until", and "reason" before calling raise ClientException(...). Ensure
the logging call occurs immediately before each raise so the same inputs and
rejection reason are recorded.
In `@src/synthorg/api/controllers/coordination_metrics.py`:
- Around line 46-47: Replace the plain str parameter types for task_id and
agent_id with the NotBlankStr type from core.types to ensure identifiers cannot
be empty or whitespace-only at the API boundary; specifically, update the
endpoint parameter declarations (the Annotated task_id and agent_id in
coordination_metrics.py) to use NotBlankStr (preserving the
optionality/Annotated metadata such as Parameter(max_length=QUERY_MAX_LENGTH))
so validation happens automatically without manual whitespace checks.
- Around line 74-83: Validation paths in coordination_metrics.py raise
ClientException for timezone-naive or inverted 'since'/'until' without logging;
before each raise, log a warning (or error if appropriate) using the module
logger with structured kwargs including 'since' and 'until' and the request
context, and use the appropriate event name constant from
synthorg.observability.events (e.g., BAD_REQUEST_TIMEZONE or
BAD_REQUEST_TIME_RANGE) instead of a raw string; update the two branches that
currently raise ClientException to first call logger.warning(...) with the event
constant and fields like {"event": EVENTS.BAD_REQUEST_TIMEZONE, "since":
str(since), "until": str(until)} (or BAD_REQUEST_TIME_RANGE for the ordering
check), then raise the same ClientException.
In `@tests/unit/security/test_audit.py`:
- Around line 354-387: Combine the four similar tests into a single parametrized
test using pytest.mark.parametrize to reduce duplication: create one test (e.g.,
test_query_filters_parametrized) that calls AuditLog(), calls
self._populate(log), and invokes log.query with varying parameter sets for
action_type, since, and until; parametrize over tuples like (action_type, since,
until, expected_count, expected_first_id) corresponding to the four existing
cases (test_filter_by_action_type, test_filter_by_until,
test_filter_by_since_and_until, test_combined_action_type_and_until) and assert
len(results) == expected_count and, when expected_first_id is not None, assert
results[0].id == expected_first_id; keep use of datetime(2026, 4, 1, tzinfo=UTC)
and timedelta values from the original tests to construct since/until inputs.
🪄 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: 69ef3057-b8a0-4cd7-8ea8-6c1211aed96b
📒 Files selected for processing (3)
src/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/coordination_metrics.pytests/unit/security/test_audit.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). (5)
- GitHub Check: Dashboard Test
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Web
- GitHub Check: Build Backend
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use Python 3.14+ with PEP 649 native lazy annotations
Do not use
from __future__ import annotationsin Python codeUse PEP 758 except syntax: use
except A, B:(no parentheses) in PythonRequire type hints on all public functions in Python, with mypy strict mode enforcement
Require Google-style docstrings on all public classes and functions, enforced by ruff D rules
Create new objects instead of mutating existing ones; use copy.deepcopy() and MappingProxyType for immutability
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models for runtime state
Never mix static config fields with mutable runtime fields in one Pydantic model
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict) with allow_inf_nan=False in all ConfigDict declarations
Use
@computed_fieldfor derived values instead of storing and validating redundant fields in Pydantic modelsUse NotBlankStr from core.types for all identifier/name fields, including optional and tuple variants, instead of manual whitespace validators
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code
Enforce 88 character line length limit in Python code
Keep Python functions under 50 lines and files under 800 lines
Handle errors explicitly in Python, never silently swallow them
Validate at system boundaries in Python (user input, external APIs, config files)
Always use
loggeras the variable name for loggers in Python, not_loggerorlogUse structured kwargs in logger calls:
logger.info(EVENT, key=value), neverlogger.info("msg %s", val)Log at WARNING or ERROR with context on all error paths before raising in Python
Log at INFO for all state transitions in Python
Use DEBUG logging for object creation, internal flow, and entry/exit of key functions in Python
Maintain 80% minimum code coverage for Python tests, enforced in CI
Files:
tests/unit/security/test_audit.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Mark Python tests with
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e, or@pytest.mark.slowPrefer
@pytest.mark.parametrizefor testing similar cases in PythonUse test-provider, test-small-001 vendor names in Python tests
Use Hypothesis for property-based testing in Python with
@givenand@settingsdecoratorsAdd explicit
@example(...) decorators to Hypothesis tests when a failure is found to permanently cover the case in CINever skip, dismiss, or ignore flaky Python tests; always fix them fully and fundamentally
Mock time.monotonic() and asyncio.sleep() in timing-sensitive Python tests instead of widening timing margins
Use asyncio.Event().wait() instead of asyncio.sleep(large_number) in Python tests for tasks that must block indefinitely until cancelled
Files:
tests/unit/security/test_audit.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/security/test_audit.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every Python module with business logic must include:
from synthorg.observability import get_loggerthenlogger = get_logger(__name__)Never use
import logging,logging.getLogger(), orprint()in Python application code, except in observability infrastructure modulesAlways use constants from domain-specific modules under synthorg.observability.events for event names
All provider calls must go through BaseCompletionProvider which applies retry and rate limiting automatically
Never implement retry logic in Python provider subclasses or calling code
Set RetryConfig and RateLimiterConfig per-provider in ProviderConfig for Python
Mark retryable errors with is_retryable=True (RateLimitError, ProviderTimeoutError, ProviderConnectionError, ProviderInternalError) in Python
Raise non-retryable errors immediately without retry in Python provider code
Handle RetryExhaustedError in the engine layer to trigger fallback chains
Rate limiter must respect RateLimitError.retry_after from providers and automatically pause future requests
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned Python code, docstrings, comments, tests, or config examples
Use generic names like example-provider, example-large-001, example-medium-001, example-small-001, large/medium/small in Python vendor-agnostic code
Files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.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/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: If implementation deviates from the design spec, alert the user and explain why before proceeding
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Every implementation plan must be presented to the user for accept/deny before coding starts
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: At every phase of planning and implementation, be critical and actively look for ways to improve the design
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Prioritize issues by dependency order, not priority labels
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Pure data models, enums, and re-exports in Python do not need logging
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Always include -n 8 when running pytest locally for Python parallelism, never run tests sequentially
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Vendor names may appear only in: operations design page, .claude/ skill files, third-party imports, and provider presets
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: CI runs 10 deterministic Hypothesis examples per property test with derandomize=True
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Use Git commit message format: <type>: <description> with types: feat, fix, refactor, docs, test, chore, perf, ci
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Enforce Git commits via commitizen using commit-msg hook
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Require GPG/SSH signed commits on main via branch protection
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Use Git branch naming convention: <type>/<slug> from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Block direct `gh pr create` via hookify; must use `/pre-pr-review`
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Enforce -n 8 with pytest via hookify enforce-parallel-tests
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Block `cd` prefix in Bash commands via hookify no-cd-prefix
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Block --cov flags locally via hookify no-local-coverage; CI handles coverage
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Run pre-push hooks: mypy type-check (affected modules), pytest unit tests (affected modules), golangci-lint, go vet, go test, eslint-web
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Use gh issue list via Bash for GitHub issue queries, not MCP list_issues (unreliable field data)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Use squash merge strategy; PR body becomes the squash commit message on main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Preserve existing Closes `#NNN` references in PR body; never remove unless explicitly asked
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: After finishing an issue implementation, create a feature branch (<type>/<slug>), commit, and push immediately; never leave work uncommitted on main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Never create a PR directly with gh pr create; always use /pre-pr-review command
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Use /pre-pr-review quick for trivial/docs-only changes to skip agents but run automated checks
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Use /aurelio-review-pr command to handle external reviewer feedback after PR exists
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Fix all valid findings from review agents when creating PRs; never skip or defer as out of scope
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Never use `cd` in Bash commands; working directory is already set to project root
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Use absolute paths or run commands directly in Bash; exception: bash -c "cd <dir> && <cmd>" for tools without -C flag
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Never use Bash to write or modify files; use Write or Edit tools instead
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Never use cat >, cat << EOF, echo >, echo >>, sed -i, python -c, or tee to create/modify files
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:06:10.548Z
Learning: Use go -C cli flag instead of cd cli for CLI commands
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/engine/coordination/**/*.py : Task coordination uses multi-agent pipeline with 4 dispatchers (SAS/centralized/decentralized/context-dependent), wave execution, and workspace lifecycle integration.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget tracking includes pre-flight/in-flight checks, auto-downgrade, billing periods, cost tiers, quota/subscription. CFO includes anomaly detection, efficiency analysis, downgrade recommendations.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget package (budget/): cost tracking, budget enforcement (pre-flight/in-flight checks, auto-downgrade), billing periods, cost tiers, quota/subscription tracking, CFO cost optimization (anomaly detection, efficiency analysis, downgrade recommendations, approval decisions), spending reports, budget errors (BudgetExhaustedError, DailyLimitExceededError, QuotaExhaustedError)
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): 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), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)
Applied to files:
src/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/security/**/*.py : Security module includes SecOps agent, rule engine (soft-allow/hard-deny), audit log, output scanner, risk classifier, autonomy levels (4 strategies), timeout policies.
Applied to files:
src/synthorg/api/controllers/audit.py
🔇 Additional comments (3)
src/synthorg/api/controllers/coordination_metrics.py (1)
92-97: Good pagination metadata handling with capped upstream query.Passing
total=total_matchespreserves true match counts even when fetched records are capped before pagination.tests/unit/security/test_audit.py (1)
289-295: Good boundary-case coverage for inverted windows.This test precisely locks the
since > untilcontract and uses deterministic timestamps.src/synthorg/api/controllers/audit.py (1)
88-107: Query delegation and paginated response wiring look solid.The endpoint cleanly forwards filters, paginates consistently, and emits structured audit query telemetry.
| agent_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, | ||
| tool_name: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, | ||
| action_type: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | ||
| | None = None, | ||
| verdict: Annotated[str, Parameter(max_length=50)] | None = None, | ||
| since: datetime | None = None, | ||
| until: datetime | None = None, |
There was a problem hiding this comment.
Tighten query parameter types at the API boundary.
Use NotBlankStr for identifier/name filters and a constrained verdict type (e.g., AuditVerdictStr) so blank/invalid values are rejected instead of returning misleading empty results.
As per coding guidelines: "Use NotBlankStr from core.types for all identifier/name fields..." and "Validate at system boundaries in Python".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/controllers/audit.py` around lines 44 - 50, Replace the
loose string query parameter types in the audit controller with the stricter
boundary types: change agent_id, tool_name, and action_type to use NotBlankStr
(from core.types) instead of Annotated[str,...] so blank identifiers are
rejected, and replace verdict with the constrained AuditVerdictStr type (or an
equivalent enum/str alias) to validate verdict values at the API boundary;
update the function signature in the audit controller where these parameters are
declared and adjust any import statements to import NotBlankStr and
AuditVerdictStr from core.types.
| task_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, | ||
| agent_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, |
There was a problem hiding this comment.
Validate blank/whitespace identifiers at the boundary.
task_id and agent_id are identifier fields but are typed as plain str, so empty or whitespace-only filters can pass. Use NotBlankStr for both params.
Suggested fix
from typing import Annotated
@@
from synthorg.api.path_params import QUERY_MAX_LENGTH
from synthorg.budget.coordination_store import CoordinationMetricsRecord
+from synthorg.core.types import NotBlankStr
@@
- task_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None,
- agent_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None,
+ task_id: Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None,
+ agent_id: Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None,As per coding guidelines: Use NotBlankStr from core.types for all identifier/name fields, including optional and tuple variants, instead of manual whitespace validators and Validate at system boundaries in Python.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/controllers/coordination_metrics.py` around lines 46 - 47,
Replace the plain str parameter types for task_id and agent_id with the
NotBlankStr type from core.types to ensure identifiers cannot be empty or
whitespace-only at the API boundary; specifically, update the endpoint parameter
declarations (the Annotated task_id and agent_id in coordination_metrics.py) to
use NotBlankStr (preserving the optionality/Annotated metadata such as
Parameter(max_length=QUERY_MAX_LENGTH)) so validation happens automatically
without manual whitespace checks.
| if (since is not None and since.tzinfo is None) or ( | ||
| until is not None and until.tzinfo is None | ||
| ): | ||
| raise ClientException( | ||
| detail="'since' and 'until' must be timezone-aware", | ||
| ) | ||
| if since is not None and until is not None and since > until: | ||
| raise ClientException( | ||
| detail="'since' must not be after 'until'", | ||
| ) |
There was a problem hiding this comment.
Log rejected requests before raising ClientException.
Both validation error paths raise immediately without WARNING/ERROR logs, which weakens auditability for rejected API calls.
Suggested fix
if (since is not None and since.tzinfo is None) or (
until is not None and until.tzinfo is None
):
+ logger.warning(
+ API_COORDINATION_METRICS_QUERIED,
+ outcome="rejected",
+ reason="naive_datetime_window",
+ )
raise ClientException(
detail="'since' and 'until' must be timezone-aware",
)
if since is not None and until is not None and since > until:
+ logger.warning(
+ API_COORDINATION_METRICS_QUERIED,
+ outcome="rejected",
+ reason="inverted_datetime_window",
+ )
raise ClientException(
detail="'since' must not be after 'until'",
)As per coding guidelines: Log at WARNING or ERROR with context on all error paths before raising in Python, Use structured kwargs in logger calls, and Always use constants from domain-specific modules under synthorg.observability.events for event names.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/controllers/coordination_metrics.py` around lines 74 - 83,
Validation paths in coordination_metrics.py raise ClientException for
timezone-naive or inverted 'since'/'until' without logging; before each raise,
log a warning (or error if appropriate) using the module logger with structured
kwargs including 'since' and 'until' and the request context, and use the
appropriate event name constant from synthorg.observability.events (e.g.,
BAD_REQUEST_TIMEZONE or BAD_REQUEST_TIME_RANGE) instead of a raw string; update
the two branches that currently raise ClientException to first call
logger.warning(...) with the event constant and fields like {"event":
EVENTS.BAD_REQUEST_TIMEZONE, "since": str(since), "until": str(until)} (or
BAD_REQUEST_TIME_RANGE for the ordering check), then raise the same
ClientException.
| def test_filter_by_action_type(self) -> None: | ||
| log = AuditLog() | ||
| self._populate(log) | ||
| results = log.query(action_type="code:write") | ||
| assert len(results) == 2 | ||
|
|
||
| def test_filter_by_until(self) -> None: | ||
| log = AuditLog() | ||
| self._populate(log) | ||
| t = datetime(2026, 4, 1, tzinfo=UTC) | ||
| results = log.query(until=t + timedelta(hours=1)) | ||
| assert len(results) == 2 | ||
|
|
||
| def test_filter_by_since_and_until(self) -> None: | ||
| log = AuditLog() | ||
| self._populate(log) | ||
| t = datetime(2026, 4, 1, tzinfo=UTC) | ||
| results = log.query( | ||
| since=t + timedelta(minutes=30), | ||
| until=t + timedelta(hours=1, minutes=30), | ||
| ) | ||
| assert len(results) == 1 | ||
| assert results[0].id == "e2" | ||
|
|
||
| def test_combined_action_type_and_until(self) -> None: | ||
| log = AuditLog() | ||
| self._populate(log) | ||
| t = datetime(2026, 4, 1, tzinfo=UTC) | ||
| results = log.query( | ||
| action_type="code:write", | ||
| until=t + timedelta(minutes=30), | ||
| ) | ||
| assert len(results) == 1 | ||
| assert results[0].id == "e1" |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider parametrizing the new filter matrix tests.
These four tests follow the same arrange/act/assert shape; @pytest.mark.parametrize would reduce duplication and keep future filter additions easier to maintain.
As per coding guidelines: "tests/**/*.py: Prefer @pytest.mark.parametrize for testing similar cases in Python".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/unit/security/test_audit.py` around lines 354 - 387, Combine the four
similar tests into a single parametrized test using pytest.mark.parametrize to
reduce duplication: create one test (e.g., test_query_filters_parametrized) that
calls AuditLog(), calls self._populate(log), and invokes log.query with varying
parameter sets for action_type, since, and until; parametrize over tuples like
(action_type, since, until, expected_count, expected_first_id) corresponding to
the four existing cases (test_filter_by_action_type, test_filter_by_until,
test_filter_by_since_and_until, test_combined_action_type_and_until) and assert
len(results) == expected_count and, when expected_first_id is not None, assert
results[0].id == expected_first_id; keep use of datetime(2026, 4, 1, tzinfo=UTC)
and timedelta values from the original tests to construct since/until inputs.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (3)
src/synthorg/api/controllers/audit.py (2)
47-50:⚠️ Potential issue | 🟠 MajorUse
NotBlankStrfor identifier filters at the API boundary.On Line [47] to Line [50],
agent_id,tool_name, andaction_typeare plainstr, so blank/whitespace values are accepted. Please switch these toNotBlankStr(keepingParameter(max_length=...)) so invalid identifier filters are rejected upfront.Suggested change
- agent_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, - tool_name: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, - action_type: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] + agent_id: Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] + | None = None, + tool_name: Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] + | None = None, + action_type: Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None,As per coding guidelines: "Use
NotBlankStr(fromcore.types) for all identifier/name fields ..." and "Validate at system boundaries (user input, external APIs, config files)."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/audit.py` around lines 47 - 50, Change the three query parameter types agent_id, tool_name, and action_type from plain str to NotBlankStr so blank/whitespace identifiers are rejected at the API boundary; keep the existing Annotated(..., Parameter(max_length=QUERY_MAX_LENGTH)) and the optional union with None (i.e., Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] | None). Also add the NotBlankStr import from core.types if missing. No other behavior changes required.
112-122: 🧹 Nitpick | 🔵 TrivialConsider exposing truncation metadata when the hard query cap is hit.
With
_MAX_AUDIT_QUERYapplied upstream,pagination.totalcan represent the capped window rather than true match count. Adding an explicit signal (for exampleis_truncated) would prevent clients from misreading deep-page behavior.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/audit.py` around lines 112 - 122, The response currently returns pagination.meta.total which may be capped by `_MAX_AUDIT_QUERY`, so add an explicit truncation signal to avoid client confusion: detect when the upstream cap is applied (compare meta.total or the original match count against `_MAX_AUDIT_QUERY` in the handler that calls paginate) and set a boolean like `is_truncated` on the pagination metadata or the PaginatedResponse; return PaginatedResponse[AuditEntry](data=page, pagination={...meta, is_truncated: True/False}) so clients can reliably know when results were truncated. Ensure you update the code paths using `paginate`, the `PaginatedResponse` construction, and the logger usage around `API_AUDIT_QUERIED` to include the new flag.src/synthorg/api/controllers/coordination_metrics.py (1)
47-48:⚠️ Potential issue | 🟠 MajorUse
NotBlankStrfortask_idandagent_idquery filters.These identifier fields are typed as plain
str, so whitespace-only values can pass boundary validation.🔧 Proposed fix
from synthorg.budget.coordination_store import CoordinationMetricsRecord +from synthorg.core.types import NotBlankStr @@ - task_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, - agent_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, + task_id: Annotated[ + NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH) + ] | None = None, + agent_id: Annotated[ + NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH) + ] | None = None,As per coding guidelines:
Use NotBlankStr (from core.types) for all identifier/name fields — including optional (...) variants — instead of manual whitespace validators.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/coordination_metrics.py` around lines 47 - 48, Replace the plain str annotations for the query filters task_id and agent_id with NotBlankStr (from core.types) so whitespace-only values are rejected; update the parameter declarations to use Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] | None for both task_id and agent_id, and add the import for NotBlankStr from core.types (removing any manual whitespace validators if present) so the endpoint uses the standardized non-blank identifier type.
🤖 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/controllers/coordination_metrics.py`:
- Around line 98-110: The pagination can report misleading totals because
query() caps results with _MAX_METRICS_QUERY before paginate() runs; update the
logic after calling app_state.coordination_metrics_store.query(...) to compute
an effective_total = min(total_matches, _MAX_METRICS_QUERY) and pass
effective_total (not total_matches) into paginate(...). Also handle the case
where offset >= effective_total by returning an empty page and correct meta
(using effective_total) so deep offsets don't produce empty pages with inflated
totals; reference the variables/funcs entries, total_matches,
_MAX_METRICS_QUERY, offset, paginate, page, and meta when making the change.
---
Duplicate comments:
In `@src/synthorg/api/controllers/audit.py`:
- Around line 47-50: Change the three query parameter types agent_id, tool_name,
and action_type from plain str to NotBlankStr so blank/whitespace identifiers
are rejected at the API boundary; keep the existing Annotated(...,
Parameter(max_length=QUERY_MAX_LENGTH)) and the optional union with None (i.e.,
Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] | None). Also add
the NotBlankStr import from core.types if missing. No other behavior changes
required.
- Around line 112-122: The response currently returns pagination.meta.total
which may be capped by `_MAX_AUDIT_QUERY`, so add an explicit truncation signal
to avoid client confusion: detect when the upstream cap is applied (compare
meta.total or the original match count against `_MAX_AUDIT_QUERY` in the handler
that calls paginate) and set a boolean like `is_truncated` on the pagination
metadata or the PaginatedResponse; return
PaginatedResponse[AuditEntry](data=page, pagination={...meta, is_truncated:
True/False}) so clients can reliably know when results were truncated. Ensure
you update the code paths using `paginate`, the `PaginatedResponse`
construction, and the logger usage around `API_AUDIT_QUERIED` to include the new
flag.
In `@src/synthorg/api/controllers/coordination_metrics.py`:
- Around line 47-48: Replace the plain str annotations for the query filters
task_id and agent_id with NotBlankStr (from core.types) so whitespace-only
values are rejected; update the parameter declarations to use
Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] | None for both
task_id and agent_id, and add the import for NotBlankStr from core.types
(removing any manual whitespace validators if present) so the endpoint uses the
standardized non-blank identifier type.
🪄 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: 8dfb0400-5dc7-4532-8c35-f61b7295d411
📒 Files selected for processing (2)
src/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/coordination_metrics.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 (4)
**/*.{py,ts,tsx,js,go}
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotationsin Python — Python 3.14 has PEP 649 native lazy annotations.Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names:
example-provider,example-large-001,example-medium-001,example-small-001,large/medium/smallas aliases. Vendor names may only appear in: (1) Operations design page provider list (docs/design/operations.md), (2).claude/skill/agent files, (3) third-party import paths/module names, (4) provider presets (src/synthorg/providers/presets.py).
Files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use PEP 758 except syntax: use
except A, B:(no parentheses) — ruff enforces this on Python 3.14.Type hints are required on all public functions. Use mypy strict mode for type checking.
Google-style docstrings are required on public classes and functions (enforced by ruff D rules).
Create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries,
BaseTool), usecopy.deepcopy()at construction +MappingProxyTypewrapping for read-only enforcement.For
dict/listfields in frozen Pydantic models, rely onfrozen=Truefor field reassignment prevention andcopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).Use frozen Pydantic models for config/identity. Use separate mutable-via-copy models (using
model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.Use Pydantic v2 (
BaseModel,model_validator,computed_field,ConfigDict). Useallow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/Infin numeric fields at validation time.Use
@computed_fieldfor derived values instead of storing + validating redundant fields (e.g.TokenUsage.total_tokens).Use
NotBlankStr(fromcore.types) for all identifier/name fields — including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants — instead of manual whitespace validators.Prefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_task. Existing code is being migrated incrementally.Line length must be 88 characters (enforced by ruff).
Functions must be less than 50 lines. Files must be less than 800 lines.
Handle errors explicitly. Never silently swallow exceptions.
Validate at system boundaries (user input, external APIs, confi...
Files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic must have:
from synthorg.observability import get_loggerthenlogger = get_logger(__name__).Never use
import logging/logging.getLogger()/print()in application code. Exception:observability/setup.py,observability/sinks.py,observability/syslog_handler.py, andobservability/http_handler.pymay use stdlibloggingandprint(..., file=sys.stderr)for handler construction, bootstrap, and error reporting.Use
loggeras the variable name for logging instances (not_logger, notlog).Always use event name constants from domain-specific modules under
synthorg.observability.events(e.g.,API_REQUEST_STARTED,TOOL_INVOKE_START,GIT_COMMAND_START, etc.). Import directly:from synthorg.observability.events.<domain> import EVENT_CONSTANT.Use structured logging with kwargs: always
logger.info(EVENT, key=value)— neverlogger.info('msg %s', val).All error paths must log at WARNING or ERROR with context before raising.
All state transitions must log at INFO level.
Use DEBUG level for object creation, internal flow, entry/exit of key functions.
Pure data models, enums, and re-exports do NOT need logging.
All provider calls must go through
BaseCompletionProviderwhich applies retry + rate limiting automatically. Never implement retry logic in driver subclasses or calling code — it is handled by the base class.Configure
RetryConfigandRateLimiterConfigper-provider inProviderConfig.Retryable errors (
is_retryable=True):RateLimitError,ProviderTimeoutError,ProviderConnectionError,ProviderInternalError. Non-retryable errors raise immediately without retry.
RetryExhaustedErrorsignals that all retries failed — the engine layer catches this to trigger fallback chains.Rate limiter respects
RateLimitError.retry_afterfrom providers — automatically pauses future requests.
Files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.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/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: Every implementation plan must be presented to the user for accept/deny before coding starts.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: At every phase of planning and implementation, be critical — actively look for ways to improve the design in the spirit of what we're building (robustness, correctness, simplicity, future-proofing where it's free). Surface improvements as suggestions, not silent changes — user decides.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: Prioritize issues by dependency order, not priority labels — unblocked dependencies come first.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: After finishing an issue implementation, always create a feature branch (`<type>/<slug>`), commit, and push — do NOT create a PR automatically.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: Do NOT leave work uncommitted on main — branch, commit, push immediately after finishing.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: Never create a PR directly — `gh pr create` is blocked by hookify. Always use `/pre-pr-review` to create PRs — it runs automated checks + review agents + fixes before creating the PR. For trivial/docs-only changes: `/pre-pr-review quick` skips agents but still runs automated checks.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: After the PR exists, use `/aurelio-review-pr` to handle external reviewer feedback. The `/commit-push-pr` command is effectively blocked (it calls `gh pr create` internally).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: When review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes), fix them all. No deferring, no 'out of scope' skipping.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: Commits must follow format: `<type>: <description>` with types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: Signed commits are required on `main` via branch protection — all commits must be GPG/SSH signed.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:24:38.017Z
Learning: Use branch naming convention: `<type>/<slug>` from main.
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/engine/coordination/**/*.py : Task coordination uses multi-agent pipeline with 4 dispatchers (SAS/centralized/decentralized/context-dependent), wave execution, and workspace lifecycle integration.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget tracking includes pre-flight/in-flight checks, auto-downgrade, billing periods, cost tiers, quota/subscription. CFO includes anomaly detection, efficiency analysis, downgrade recommendations.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget package (budget/): cost tracking, budget enforcement (pre-flight/in-flight checks, auto-downgrade), billing periods, cost tiers, quota/subscription tracking, CFO cost optimization (anomaly detection, efficiency analysis, downgrade recommendations, approval decisions), spending reports, budget errors (BudgetExhaustedError, DailyLimitExceededError, QuotaExhaustedError)
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to src/synthorg/**/*.py : Use `NotBlankStr` from `core.types` for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to **/*.py : Use `NotBlankStr` (from `core.types`) for all identifier/name fields, including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants, instead of manual whitespace validators
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 with adopted conventions: use computed_field for derived values instead of storing + validating redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T11:41:02.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T11:41:02.964Z
Learning: Applies to src/**/*.py : Models: Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing + validating redundant fields. Use `NotBlankStr` for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to **/*.py : Models: Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict). Use computed_field for derived values instead of storing + validating redundant fields. Use NotBlankStr (from core.types) for all identifier/name fields — including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants — instead of manual whitespace validators.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to src/ai_company/!(observability)/**/*.py : All error paths must log at WARNING or ERROR with context before raising.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-15T16:55:07.730Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:55:07.730Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-04-08T11:07:20.358Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.358Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation, internal flow, entry/exit of key functions
Applied to files:
src/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): 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), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)
Applied to files:
src/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/security/**/*.py : Security module includes SecOps agent, rule engine (soft-allow/hard-deny), audit log, output scanner, risk classifier, autonomy levels (4 strategies), timeout policies.
Applied to files:
src/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/api/**/*.py : REST API: Litestar framework, controllers with guards, channels for WebSocket, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. RFC 9457 structured errors (ErrorCategory, ErrorCode, ErrorDetail, ProblemDetail, CATEGORY_TITLES, category_title, category_type_uri, content negotiation).
Applied to files:
src/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. Use `computed_field` for derived values instead of storing redundant fields. Use `NotBlankStr` for all identifier/name fields.
Applied to files:
src/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-16T20:14:00.937Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T20:14:00.937Z
Learning: Applies to **/*.py : Validate: at system boundaries (user input, external APIs, config files).
Applied to files:
src/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : Handle errors explicitly, never silently swallow. Validate at system boundaries (user input, external APIs, config files).
Applied to files:
src/synthorg/api/controllers/audit.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to **/*.py : Validate at system boundaries (user input, external APIs, config files)
Applied to files:
src/synthorg/api/controllers/audit.py
🔇 Additional comments (4)
src/synthorg/api/controllers/audit.py (4)
1-35: Module setup and observability wiring look correct.
36-42: Controller declaration and access guard are clean.
57-79: Endpoint docstring is clear and complete.
80-101: Validation error paths are properly logged before raising.
- GET /security/audit: paginated audit log query with filters
(agent_id, tool_name, action_type, verdict, since, until)
- GET /agents/{name}/health: composite health from performance
tracker, trust service, and registry
- GET /settings/security/export: serialize SecurityConfig to JSON
- POST /settings/security/import: validate SecurityConfig payload
- GET /coordination/metrics: paginated coordination metrics query
with filters (task_id, agent_id, since, until)
Infrastructure:
- Extend AuditLog.query() with until + action_type filters
- Create CoordinationMetricsStore (in-memory ring buffer)
- Add audit_log, trust_service, coordination_metrics_store to
AppState with auto-wiring in create_app()
- Share AuditLog instance between AppState and AgentEngine
- Register AuditController + CoordinationMetricsController
Closes #1118, Closes #1119, Closes #1120, Closes #1121
Pre-reviewed by 15 agents, 18 findings addressed: - Narrow except Exception to ValidationError in security import - Use TrendDirection enum instead of NotBlankStr for trend field - Add safety cap (_MAX_AUDIT_QUERY=10000) to audit query - Add limit parameter to CoordinationMetricsStore.query() - Add cross-field validator to TrustSummary (score requires timestamp) - Add debug logging for missing quality trends - Fix incomplete docstrings on audit/coordination controllers - Add audit_log param to AgentEngine docstring - Add frontend TypeScript types for 4 new response models - Add unit tests for _extract_quality_trend helper - Add model validation tests for health response models - Add AND-combination filter tests for audit and coordination - Update CLAUDE.md with new event constants - Update operations.md gaps table (G2-G5 implemented) - Update page-structure.md with new endpoints
… local agents - Fix ToolCategory enum mismatch between Python and TypeScript (CRITICAL) - Add since > until validation to audit and coordination controllers - Auto-wire trust_service with DisabledTrustStrategy default in create_app - Gate trust_service access in health endpoint (graceful degradation) - Add last_active_at field to AgentHealthResponse from lifecycle events - Add PerformanceSummary cross-field validator (trend requires scores) - Implement security config import persistence via SettingsService - Add structured CoordinationMetricsPayload TypeScript type - Fix coordination_store field description (remove "None when skipped") - Add WARNING logging before ValueError raises in coordination_store - Add AuditController and CoordinationMetricsController to page map - Fix operations.md G5 missing tool_name filter - Update operations.md G3 to reflect persistence (no longer validate-only) - Add since > until validation in AuditLog.query() - Assert HTTP status before reading nested payload in test_agents - Use enum-derived trend assertions in test_agents - Assert is_quadratic value (not just presence) in test_coordination_metrics
- Use COORD_METRICS_VALIDATION_ERROR event for error logging (was using
success event COORD_METRICS_COLLECTION_COMPLETED)
- Add since > until validation to CoordinationMetricsStore.query()
for defense-in-depth (controller already validates)
- Reconcile Coordination Metrics Suite section with implementation:
expand from 5 to all 9 Kim et al. metrics in design table
- Add approved-deviation note to G2 row ({name} vs {id} from #1118)
- Add inverted time window rejection tests for both audit and
coordination metrics controllers
- Promote coordination store record() logging from DEBUG to INFO (state transition per CLAUDE.md rules) - Return (records, total_matches) from CoordinationMetricsStore.query() so pagination.total reflects true match count, not truncated count - Pass total_matches to paginate() in coordination metrics controller - Parametrize 4 audit filter tests into single test_filter_by_field - Add assert resp.status_code == 200 before resp.json() in all audit and coordination metrics tests - Add test_total_matches_exceeds_limit for store query truncation
…g inverted-window test
…metrics controllers
6b7dfcb to
f78f81e
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (7)
src/synthorg/api/controllers/audit.py (1)
47-53:⚠️ Potential issue | 🟠 MajorTighten the audit query params at the boundary.
Lines 47-53 still accept blank identifier/name filters and any arbitrary
verdictstring. That turns typos and whitespace into empty result sets instead of a validation error.agent_id,tool_name, andaction_typeshould beNotBlankStr, andverdictshould use a constrained enum or literal type.As per coding guidelines, "Use NotBlankStr for all identifier/name fields" and "Validate at system boundaries: user input, external APIs, and config files."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/audit.py` around lines 47 - 53, Replace the loose string query parameters with tighter boundary types: change agent_id, tool_name and action_type signatures from Annotated[str, Parameter(...)] to NotBlankStr (preserving the same QUERY_MAX_LENGTH constraint) so blank/whitespace values are rejected, and replace verdict's free string with a constrained enum or Literal type (define an AuditVerdict enum or Literal[...] matching allowed verdict values and use that type for verdict) to enforce valid verdicts at the API boundary; update any import statements to bring in NotBlankStr and the new enum/literal type and adjust downstream references to these parameter names if needed.tests/unit/api/controllers/test_settings.py (1)
289-312:⚠️ Potential issue | 🟡 MinorMake the round-trip test prove persistence.
Line 301 posts
config1unchanged, so this still passes against a validate-only import or an export path that ignores settings-backed overrides. Flip a persisted field before the POST and assert the second export reflects that change.Suggested test change
def test_round_trip( self, test_client: TestClient[Any], auth_headers: dict[str, str], ) -> None: """Export, then import, then export again -- configs match.""" resp1 = test_client.get( "/api/v1/settings/security/export", headers=auth_headers, ) config1 = resp1.json()["data"]["config"] + mutated = { + **config1, + "audit_enabled": not config1["audit_enabled"], + } test_client.post( "/api/v1/settings/security/import", - json={"config": config1}, + json={"config": mutated}, headers=auth_headers, ) resp2 = test_client.get( "/api/v1/settings/security/export", headers=auth_headers, ) config2 = resp2.json()["data"]["config"] - assert config1 == config2 + assert config2["audit_enabled"] == mutated["audit_enabled"]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/api/controllers/test_settings.py` around lines 289 - 312, The test_round_trip currently posts config1 unchanged so it can pass against a validate-only import; modify the test to mutate a persisted setting in config1 (e.g., toggle a boolean or change a numeric/string value that maps to a persisted security setting) before calling the POST to "/api/v1/settings/security/import", then after the second GET assert that config2 reflects that mutation; update references to config1 and config2 in test_round_trip so the POST uses the mutated config and the final assertion verifies persistence rather than a no-op round trip.src/synthorg/api/controllers/coordination_metrics.py (1)
47-48:⚠️ Potential issue | 🟠 MajorReject blank identifier filters.
Lines 47-48 still accept empty or whitespace-only
task_id/agent_id, so callers get a silent empty page instead of a validation error. Tighten both params toNotBlankStr.Suggested fix
from synthorg.api.path_params import QUERY_MAX_LENGTH from synthorg.budget.coordination_store import CoordinationMetricsRecord +from synthorg.core.types import NotBlankStr @@ - task_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, - agent_id: Annotated[str, Parameter(max_length=QUERY_MAX_LENGTH)] | None = None, + task_id: Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] + | None = None, + agent_id: Annotated[NotBlankStr, Parameter(max_length=QUERY_MAX_LENGTH)] + | None = None,As per coding guidelines, "Use NotBlankStr for all identifier/name fields" and "Validate at system boundaries: user input, external APIs, and config files."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/coordination_metrics.py` around lines 47 - 48, The task_id and agent_id query parameters in coordination_metrics.py currently use Annotated[str, Parameter(...)] and allow empty/whitespace strings; change their types to NotBlankStr (e.g., task_id: NotBlankStr | None = None, agent_id: NotBlankStr | None = None) so blank identifiers are rejected at validation, and add the appropriate import for NotBlankStr where annotations are defined; keep the existing Parameter(max_length=QUERY_MAX_LENGTH) constraints if needed or move length validation into NotBlankStr usage to preserve QUERY_MAX_LENGTH behavior.src/synthorg/api/controllers/settings.py (2)
589-607:⚠️ Potential issue | 🟠 MajorThis import still reports success for settings it never applies.
_SECURITY_SETTING_FIELDSonly persists four keys, so changes toenforcement_mode,rule_engine,hard_deny_action_types,auto_approve_action_types, and the other exported fields are silently dropped. On top of that, the helper does independentsvc.set()calls, so a later failure can leave earlier writes committed while Lines 602-607 return the full validated document as if it became active. Either narrow the accepted schema to the persistable subset, or batch/apply the full config atomically and build the response from the effective config plus an applied/ignored breakdown.Also applies to: 613-648
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/settings.py` around lines 589 - 607, The handler currently calls _persist_security_settings but then returns the entire validated document (validated.model_dump) even though _SECURITY_SETTING_FIELDS only persists four keys and _persist_security_settings uses multiple svc.set() calls that can partially apply and hide failures. Fix by either (A) narrowing the validated payload before persisting and returning only the subset in SecurityConfigExportResponse (filter validated to keys in _SECURITY_SETTING_FIELDS) or (B) make _persist_security_settings accept the full config and persist atomically: build a single update object (or a transaction) rather than multiple svc.set() calls, apply it as one operation, then read back the effective config and return that (plus an applied/ignored breakdown). Ensure svc.set usage is replaced/aggregated to avoid partial commits and do not return validated.model_dump unless it is guaranteed to be the effective persisted config.
537-554:⚠️ Potential issue | 🟠 MajorExport the resolved security config, not the startup snapshot.
Line 538 serializes
app_state.config.security, but the import path writes throughSettingsService. After any DB override or successful import,/settings/security/exportcan still return the original startup config instead of the effective security policy. Read the security config through the settings-backed resolver path before serializing it.Based on learnings, settings are runtime-editable with precedence
DB > env > YAML > code defaults.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/api/controllers/settings.py` around lines 537 - 554, The handler currently serializes the startup snapshot at app_state.config.security; instead, fetch the effective, runtime-resolved security config via the settings-backed resolver (use SettingsService or its resolve/get method) and serialize that result before returning; specifically replace reading app_state.config.security with calling the SettingsService resolution API (e.g., SettingsService.resolve_security() or SettingsService.get_security()) to obtain the DB/env/YAML-resolved SecurityConfig instance, then call model_dump(mode="json") and build the ApiResponse using that resolved object and the same exported_at and warning logic.src/synthorg/budget/coordination_store.py (1)
81-82: 🛠️ Refactor suggestion | 🟠 MajorAlign
task_id/agent_idfilters withNotBlankStr.These are identifier filters and should use
NotBlankStr | Nonein the public query signature.🔧 Proposed patch
- task_id: str | None = None, - agent_id: str | None = None, + task_id: NotBlankStr | None = None, + agent_id: NotBlankStr | None = None,As per coding guidelines: "Use
NotBlankStr(fromcore.types) for all identifier/name fields -- including optional variants."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/budget/coordination_store.py` around lines 81 - 82, Change the public query signature to use NotBlankStr for identifier filters: replace the current type annotations for task_id and agent_id (task_id: str | None, agent_id: str | None) with NotBlankStr | None (importing NotBlankStr from core.types) in the method where these parameters are declared so the public API enforces non-blank identifiers; update any related type hints in the same method (e.g., function/method that declares task_id and agent_id) and adjust imports accordingly.tests/unit/security/test_audit.py (1)
354-387: 🧹 Nitpick | 🔵 TrivialParametrize the new filter matrix tests to reduce duplication.
These four tests follow the same arrange/act/assert shape and are good candidates for a single
@pytest.mark.parametrizecase table.As per coding guidelines: "tests/**/*.py: Prefer
@pytest.mark.parametrizefor testing similar cases."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/security/test_audit.py` around lines 354 - 387, Combine the four similar tests (test_filter_by_action_type, test_filter_by_until, test_filter_by_since_and_until, test_combined_action_type_and_until) into a single parametrized pytest using `@pytest.mark.parametrize`: for each case supply the query kwargs (e.g., action_type, since, until), the expected result length, and optionally an expected first id; inside the test instantiate AuditLog(), call self._populate(log), call log.query(**kwargs) and assert len(results) == expected_len and if expected_id is provided assert results[0].id == expected_id; keep references to AuditLog.query and self._populate to locate the code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/design/operations.md`:
- Around line 1847-1855: Update the API Surface table to include the newly
implemented control-plane endpoints referenced in the gap table: add entries for
GET /api/v1/agents/{name}/health, GET /api/v1/security/audit, GET
/api/v1/coordination/metrics, and GET/POST /api/v1/settings/security/export and
/api/v1/settings/security/import so the primary endpoint inventory matches the
G2–G5 "Implemented" status (v0.6.4). Ensure each entry documents method, path,
brief purpose (health: composites performance/trust/lifecycle; audit:
agent_id/tool_name/verdict/action_type/time-range filters; metrics: Kim et al. 9
metrics with filtering; export/import: persist registered settings), and
cross-reference the gap table note about G6/priority so readers see consistency
across the page.
In `@src/synthorg/api/app.py`:
- Around line 761-766: The default builder _build_default_trust_service
currently returns a hardcoded DisabledTrustStrategy() and empty TrustConfig(),
which ignores the app's real trust policy; change _build_default_trust_service
(and the other default path used around the secondary default) to obtain the
application's configured TrustConfig and TrustStrategy from the existing trust
factory/loader (e.g., use the app's TrustFactory or the configured TrustConfig
loader to construct the strategy) and instantiate
TrustService(strategy=configured_strategy, config=configured_config); only fall
back to DisabledTrustStrategy()/empty TrustConfig if no configured
policy/factory is present.
In `@src/synthorg/api/controllers/agents.py`:
- Around line 508-515: Replace deriving last_active_at from lifecycle_events
with the registry value: call AgentRegistryService.get(agent_id) (the registry
getter referenced in `#1118`) and read its last_active_at field to populate
last_active_at; remove the await
app_state.persistence.lifecycle_events.list_events(...) usage for this route,
and ensure you handle the case where the registry record or its last_active_at
is None (fall back to None). Use the registry get method rather than
lifecycle_events to avoid the extra persistence dependency and stale timestamps.
In `@src/synthorg/security/audit.py`:
- Line 83: Change the action_type parameter's annotation from str | None to
NotBlankStr | None in the affected function or method (look for the signature
containing "action_type: str | None" in src/synthorg/security/audit.py, e.g.,
the audit/event/filter function), and add or update the import for NotBlankStr
from core.types at the top of the module if it's not already imported; ensure
any downstream uses still accept Optional values and run static type checks.
In `@tests/unit/api/controllers/test_agents.py`:
- Around line 559-623: Add a positive-path test under TestAgentHealth (e.g.,
test_health_returns_populated_trust_and_activity) that registers the agent with
_make_identity() via agent_registry.register, then populate the TrustService and
activity state for that agent (use the test fixture names for those services in
this suite—e.g., call TrustService.set_trust(agent_id, trust_payload) and
ActivityService.record_activity(agent_id, last_active_at) or the equivalent test
helpers available) before calling GET /api/v1/agents/{_AGENT_NAME}/health;
assert status 200 and that resp.json()["data"]["trust"] matches the populated
trust payload and resp.json()["data"]["last_active_at"] (or the field used by
get_agent_health()) is non-null and equals the timestamp you set, while
preserving the existing checks for agent_id/_AGENT_ID and performance/trend
types.
---
Duplicate comments:
In `@src/synthorg/api/controllers/audit.py`:
- Around line 47-53: Replace the loose string query parameters with tighter
boundary types: change agent_id, tool_name and action_type signatures from
Annotated[str, Parameter(...)] to NotBlankStr (preserving the same
QUERY_MAX_LENGTH constraint) so blank/whitespace values are rejected, and
replace verdict's free string with a constrained enum or Literal type (define an
AuditVerdict enum or Literal[...] matching allowed verdict values and use that
type for verdict) to enforce valid verdicts at the API boundary; update any
import statements to bring in NotBlankStr and the new enum/literal type and
adjust downstream references to these parameter names if needed.
In `@src/synthorg/api/controllers/coordination_metrics.py`:
- Around line 47-48: The task_id and agent_id query parameters in
coordination_metrics.py currently use Annotated[str, Parameter(...)] and allow
empty/whitespace strings; change their types to NotBlankStr (e.g., task_id:
NotBlankStr | None = None, agent_id: NotBlankStr | None = None) so blank
identifiers are rejected at validation, and add the appropriate import for
NotBlankStr where annotations are defined; keep the existing
Parameter(max_length=QUERY_MAX_LENGTH) constraints if needed or move length
validation into NotBlankStr usage to preserve QUERY_MAX_LENGTH behavior.
In `@src/synthorg/api/controllers/settings.py`:
- Around line 589-607: The handler currently calls _persist_security_settings
but then returns the entire validated document (validated.model_dump) even
though _SECURITY_SETTING_FIELDS only persists four keys and
_persist_security_settings uses multiple svc.set() calls that can partially
apply and hide failures. Fix by either (A) narrowing the validated payload
before persisting and returning only the subset in SecurityConfigExportResponse
(filter validated to keys in _SECURITY_SETTING_FIELDS) or (B) make
_persist_security_settings accept the full config and persist atomically: build
a single update object (or a transaction) rather than multiple svc.set() calls,
apply it as one operation, then read back the effective config and return that
(plus an applied/ignored breakdown). Ensure svc.set usage is replaced/aggregated
to avoid partial commits and do not return validated.model_dump unless it is
guaranteed to be the effective persisted config.
- Around line 537-554: The handler currently serializes the startup snapshot at
app_state.config.security; instead, fetch the effective, runtime-resolved
security config via the settings-backed resolver (use SettingsService or its
resolve/get method) and serialize that result before returning; specifically
replace reading app_state.config.security with calling the SettingsService
resolution API (e.g., SettingsService.resolve_security() or
SettingsService.get_security()) to obtain the DB/env/YAML-resolved
SecurityConfig instance, then call model_dump(mode="json") and build the
ApiResponse using that resolved object and the same exported_at and warning
logic.
In `@src/synthorg/budget/coordination_store.py`:
- Around line 81-82: Change the public query signature to use NotBlankStr for
identifier filters: replace the current type annotations for task_id and
agent_id (task_id: str | None, agent_id: str | None) with NotBlankStr | None
(importing NotBlankStr from core.types) in the method where these parameters are
declared so the public API enforces non-blank identifiers; update any related
type hints in the same method (e.g., function/method that declares task_id and
agent_id) and adjust imports accordingly.
In `@tests/unit/api/controllers/test_settings.py`:
- Around line 289-312: The test_round_trip currently posts config1 unchanged so
it can pass against a validate-only import; modify the test to mutate a
persisted setting in config1 (e.g., toggle a boolean or change a numeric/string
value that maps to a persisted security setting) before calling the POST to
"/api/v1/settings/security/import", then after the second GET assert that
config2 reflects that mutation; update references to config1 and config2 in
test_round_trip so the POST uses the mutated config and the final assertion
verifies persistence rather than a no-op round trip.
In `@tests/unit/security/test_audit.py`:
- Around line 354-387: Combine the four similar tests
(test_filter_by_action_type, test_filter_by_until,
test_filter_by_since_and_until, test_combined_action_type_and_until) into a
single parametrized pytest using `@pytest.mark.parametrize`: for each case supply
the query kwargs (e.g., action_type, since, until), the expected result length,
and optionally an expected first id; inside the test instantiate AuditLog(),
call self._populate(log), call log.query(**kwargs) and assert len(results) ==
expected_len and if expected_id is provided assert results[0].id == expected_id;
keep references to AuditLog.query and self._populate to locate the code.
🪄 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: f3cead5d-73ca-4db4-8ea9-8b9937f73d33
📒 Files selected for processing (22)
CLAUDE.mddocs/design/operations.mddocs/design/page-structure.mdsrc/synthorg/api/app.pysrc/synthorg/api/controllers/__init__.pysrc/synthorg/api/controllers/agents.pysrc/synthorg/api/controllers/audit.pysrc/synthorg/api/controllers/coordination_metrics.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/state.pysrc/synthorg/budget/coordination_store.pysrc/synthorg/engine/agent_engine.pysrc/synthorg/observability/events/api.pysrc/synthorg/security/audit.pytests/unit/api/conftest.pytests/unit/api/controllers/test_agents.pytests/unit/api/controllers/test_audit.pytests/unit/api/controllers/test_coordination_metrics.pytests/unit/api/controllers/test_settings.pytests/unit/budget/test_coordination_store.pytests/unit/security/test_audit.pyweb/src/api/types.ts
| def _build_default_trust_service() -> TrustService: | ||
| """Build a default no-op TrustService for agent health queries.""" | ||
| return TrustService( | ||
| strategy=DisabledTrustStrategy(), | ||
| config=TrustConfig(), | ||
| ) |
There was a problem hiding this comment.
The default trust-service wiring ignores the configured trust policy.
Line 761-Line 766 always builds a fresh DisabledTrustStrategy() with a default TrustConfig(), and Line 999-Line 1000 takes that path whenever no explicit service is injected. In the default app startup path, /agents/{name}/health will therefore expose a disabled/empty trust view instead of the company’s configured trust setup. Please build this from the real trust config/factory rather than hardcoding a no-op service.
Also applies to: 994-1000
🤖 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 761 - 766, The default builder
_build_default_trust_service currently returns a hardcoded
DisabledTrustStrategy() and empty TrustConfig(), which ignores the app's real
trust policy; change _build_default_trust_service (and the other default path
used around the secondary default) to obtain the application's configured
TrustConfig and TrustStrategy from the existing trust factory/loader (e.g., use
the app's TrustFactory or the configured TrustConfig loader to construct the
strategy) and instantiate TrustService(strategy=configured_strategy,
config=configured_config); only fall back to DisabledTrustStrategy()/empty
TrustConfig if no configured policy/factory is present.
| # Derive last_active_at from most recent lifecycle event. | ||
| last_active_at: AwareDatetime | None = None | ||
| events = await app_state.persistence.lifecycle_events.list_events( | ||
| agent_id=agent_id, | ||
| limit=1, | ||
| ) | ||
| if events: | ||
| last_active_at = events[0].timestamp |
There was a problem hiding this comment.
Use the registry’s last_active_at here.
Line 510-Line 515 derives last_active_at from lifecycle_events. That adds an unnecessary persistence dependency to /agents/{name}/health and can return a stale timestamp for recent activity that does not emit a lifecycle event. #1118 sources this field from AgentRegistryService.get(agent_id), so the health route should read the registry record instead.
Based on learnings: "If implementation deviates from the spec (better approach found, scope evolved), alert the user and explain why. User decides whether to proceed or update the spec."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/api/controllers/agents.py` around lines 508 - 515, Replace
deriving last_active_at from lifecycle_events with the registry value: call
AgentRegistryService.get(agent_id) (the registry getter referenced in `#1118`) and
read its last_active_at field to populate last_active_at; remove the await
app_state.persistence.lifecycle_events.list_events(...) usage for this route,
and ensure you handle the case where the registry record or its last_active_at
is None (fall back to None). Use the registry get method rather than
lifecycle_events to avoid the extra persistence dependency and stale timestamps.
| tool_name: str | None = None, | ||
| verdict: str | None = None, | ||
| risk_level: ApprovalRiskLevel | None = None, | ||
| action_type: str | None = None, |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Use the project identifier/name type for action_type filter.
Please type action_type as NotBlankStr | None to keep boundary contracts consistent with the repo’s non-blank identifier/name rule.
🔧 Proposed patch
-from synthorg.core.enums import ApprovalRiskLevel # noqa: TC001
+from synthorg.core.enums import ApprovalRiskLevel # noqa: TC001
+from synthorg.core.types import NotBlankStr # noqa: TC001
...
- action_type: str | None = None,
+ action_type: NotBlankStr | None = None,As per coding guidelines: "Use NotBlankStr (from core.types) for all identifier/name fields -- including optional variants."
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| action_type: str | None = None, | |
| from synthorg.core.enums import ApprovalRiskLevel # noqa: TC001 | |
| from synthorg.core.types import NotBlankStr # noqa: TC001 | |
| ... | |
| action_type: NotBlankStr | None = None, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/security/audit.py` at line 83, Change the action_type
parameter's annotation from str | None to NotBlankStr | None in the affected
function or method (look for the signature containing "action_type: str | None"
in src/synthorg/security/audit.py, e.g., the audit/event/filter function), and
add or update the import for NotBlankStr from core.types at the top of the
module if it's not already imported; ensure any downstream uses still accept
Optional values and run static type checks.
| @pytest.mark.unit | ||
| class TestAgentHealth: | ||
| async def test_health_returns_composite_data( | ||
| self, | ||
| test_client: TestClient[Any], | ||
| agent_registry: AgentRegistryService, | ||
| ) -> None: | ||
| await agent_registry.register(_make_identity()) | ||
| resp = test_client.get( | ||
| f"/api/v1/agents/{_AGENT_NAME}/health", | ||
| ) | ||
| assert resp.status_code == 200 | ||
| body = resp.json() | ||
| assert body["success"] is True | ||
| data = body["data"] | ||
| assert data["agent_id"] == _AGENT_ID | ||
| assert data["agent_name"] == _AGENT_NAME | ||
| assert data["lifecycle_status"] == "active" | ||
| assert data["performance"] is not None | ||
|
|
||
| async def test_health_trust_none_when_not_tracked( | ||
| self, | ||
| test_client: TestClient[Any], | ||
| agent_registry: AgentRegistryService, | ||
| ) -> None: | ||
| """Trust is None when TrustService has no state for agent.""" | ||
| await agent_registry.register(_make_identity()) | ||
| resp = test_client.get( | ||
| f"/api/v1/agents/{_AGENT_NAME}/health", | ||
| ) | ||
| assert resp.status_code == 200 | ||
| body = resp.json() | ||
| assert body["data"]["trust"] is None | ||
|
|
||
| def test_health_agent_not_found( | ||
| self, | ||
| test_client: TestClient[Any], | ||
| ) -> None: | ||
| resp = test_client.get("/api/v1/agents/nonexistent/health") | ||
| assert resp.status_code == 404 | ||
|
|
||
| async def test_health_performance_fields( | ||
| self, | ||
| test_client: TestClient[Any], | ||
| agent_registry: AgentRegistryService, | ||
| ) -> None: | ||
| """Verify performance sub-object has correct field types.""" | ||
| await agent_registry.register(_make_identity()) | ||
| resp = test_client.get( | ||
| f"/api/v1/agents/{_AGENT_NAME}/health", | ||
| ) | ||
| assert resp.status_code == 200 | ||
| perf = resp.json()["data"]["performance"] | ||
| assert perf["quality_score"] is None or isinstance( | ||
| perf["quality_score"], | ||
| (int, float), | ||
| ) | ||
| assert perf["collaboration_score"] is None or isinstance( | ||
| perf["collaboration_score"], | ||
| (int, float), | ||
| ) | ||
| # trend is a TrendDirection string or None | ||
| valid_trends = {t.value for t in TrendDirection} | ||
| assert perf["trend"] is None or perf["trend"] in valid_trends | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Add a positive-path health test for populated trust and activity data.
The new suite currently proves only the null path (trust is None) plus generic type checks. Please add one case with a populated trust payload and a non-null last_active_at so the two most regression-prone parts of get_agent_health() are pinned by tests.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/unit/api/controllers/test_agents.py` around lines 559 - 623, Add a
positive-path test under TestAgentHealth (e.g.,
test_health_returns_populated_trust_and_activity) that registers the agent with
_make_identity() via agent_registry.register, then populate the TrustService and
activity state for that agent (use the test fixture names for those services in
this suite—e.g., call TrustService.set_trust(agent_id, trust_payload) and
ActivityService.record_activity(agent_id, last_active_at) or the equivalent test
helpers available) before calling GET /api/v1/agents/{_AGENT_NAME}/health;
assert status 200 and that resp.json()["data"]["trust"] matches the populated
trust payload and resp.json()["data"]["last_active_at"] (or the field used by
get_agent_health()) is non-null and equals the timestamp you set, while
preserving the existing checks for agent_id/_AGENT_ID and performance/trend
types.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/design/operations.md`:
- Around line 416-419: The docs incorrectly state that message_density (c)
requires semantic analysis; update the text referencing `message_density (c)` in
the paragraph that lists metric dependencies (the sentence mentioning `c` and
`R` require semantic analysis) so it matches the earlier/later definitions that
treat `c` as message-count based telemetry. Specifically, change the dependency
description for `c` to indicate it is computed from message-count telemetry
(turn counts/message logs) rather than semantic analysis, and ensure this aligns
with `coordination_metrics.enabled` and the list of execution-telemetry metrics
(`Sc`, `Gs`, `Rt`, `Mo`) for consistency.
🪄 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: 7b05592c-5de8-4ef4-841d-2a6061f2220c
📒 Files selected for processing (1)
docs/design/operations.md
📜 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). (5)
- GitHub Check: Test (Python 3.14)
- GitHub Check: Dashboard Test
- GitHub Check: Build Backend
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Read the relevant docs/design/ page before implementing any feature or planning any issue; reference the DESIGN_SPEC.md pointer file to find the 12 design pages
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Alert the user and explain why if implementation deviates from the design spec; do not silently diverge - every deviation needs explicit user approval
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Update the relevant docs/design/ page to reflect new reality when approved deviations occur
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Present every implementation plan to the user for accept/deny before coding starts
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Be critical at every phase of planning and implementation; actively look for ways to improve the design; surface improvements as suggestions, not silent changes
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Prioritize issues by dependency order, not priority labels - unblocked dependencies come first
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Use `<type>: <description>` format for Git commits; types are: feat, fix, refactor, docs, test, chore, perf, ci; enforced by commitizen
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Signed commits required on main via branch protection - all commits must be GPG/SSH signed
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Use `<type>/<slug>` branch naming convention from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Never use `cd` in Bash commands in work instructions - working directory is already set to project root; use absolute paths or run commands directly; exception: `bash -c "cd <dir> && <cmd>"` is safe for child processes
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Never use Bash to write or modify files - use Write or Edit tools instead; do not use `cat >`, `cat << EOF`, `echo >`, `echo >>`, `sed -i`, `python -c`, or `tee` to create/modify files
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: After finishing an issue implementation, create a feature branch (`<type>/<slug>`), commit, and push - do not create a PR automatically
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Never create a PR directly using `gh pr create` - it is blocked by hookify; always use `/pre-pr-review` to create PRs with automated checks and review agents
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Use `/pre-pr-review quick` for trivial/docs-only changes to skip agents but still run automated checks
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Use `/aurelio-review-pr` to handle external reviewer feedback after PR exists
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:09:08.754Z
Learning: Fix all valid issues found by review agents - never skip or defer fixes; includes pre-existing issues in surrounding code, suggestions, and adjacent findings
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations
Applied to files:
docs/design/operations.md
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.{py,ts,tsx,js,go} : If implementation deviates from the design spec (better approach found, scope evolved, etc.), alert the user and explain why -- user decides whether to proceed or update the spec. Do NOT silently diverge -- every deviation needs explicit user approval.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-21T11:08:01.542Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T11:08:01.542Z
Learning: When implementation deviates from the spec (better approach found, scope evolved, etc.), alert the user and explain why — user decides whether to proceed or update the spec. Do NOT silently diverge — every deviation needs explicit user approval.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-30T10:41:40.176Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-30T10:41:40.176Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations from spec occur
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 7 design pages (index, agents, organization, communication, engine, memory, operations).
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Security: 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:
docs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
docs/design/operations.md
🔇 Additional comments (2)
docs/design/operations.md (2)
1307-1307: API surface additions are accurate and well-scoped.These entries align with the implemented controllers and make the main endpoint inventory consistent with the new control-plane surface.
Also applies to: 1324-1326
1851-1854: Gap-closure table update is clear and consistent.The implemented-status wording, endpoint details, and remaining-priority framing read correctly and are easy to audit against issues.
Also applies to: 1857-1859
…ot semantic analysis)
Summary
Adds 4 control-plane API endpoints closing gaps G2-G5 from
docs/research/control-plane-audit.md:GET /agents/{name}/health-- per-agent composite health (performance + trust + lifecycle status)GET/POST /settings/security/export|import-- security policy export/import for GitOps-style managementGET /coordination/metrics-- coordination metrics query (9 Kim et al. metrics with filtering)GET /security/audit-- audit log query with agent_id, verdict, action_type, and time-range filtersChanges
Source (11 files)
api/controllers/agents.py-- new health endpoint +TrustSummary,PerformanceSummary,AgentHealthResponsemodelsapi/controllers/audit.py-- NEW audit query controller with paginationapi/controllers/coordination_metrics.py-- NEW metrics query controller with paginationapi/controllers/settings.py-- security export/import endpoints +SecurityConfigExportResponse,SecurityConfigImportRequestapi/state.py-- new service properties (audit_log, trust_service, coordination_metrics_store)api/app.py-- wire new services into create_appbudget/coordination_store.py-- NEW in-memory ring-buffer store with filtered queries + limitengine/agent_engine.py-- accept injected audit_log (shared instance)security/audit.py-- addedaction_typeanduntilquery filtersobservability/events/api.py-- 7 new event constantsTests (7 files, +12 new tests from review)
CoordinationMetricsStoreunit tests (CRUD, eviction, filtering)AuditLognew filter tests (action_type, until, combined)_extract_quality_trendhelper tests (found, not found, empty)Docs
operations.md-- gaps table G2-G5 marked as implementedpage-structure.md-- new endpoints added to agent detail + settings pagesCLAUDE.md-- 8 new event constants in logging sectionFrontend
web/src/api/types.ts-- TypeScript types for all new response models (AgentHealthResponse,AuditEntry,CoordinationMetricsRecord,SecurityConfigExportResponse,ToolCategory,AuditVerdictStr)Review Coverage
Pre-reviewed by 15 agents, 18 findings addressed:
except ExceptiontoValidationErrorin security importPerformanceSummary.trendfromNotBlankStrtoTrendDirectionenum_MAX_AUDIT_QUERY=10_000,_MAX_METRICS_QUERY=10_000)limitparameter toCoordinationMetricsStore.query()TrustSummary(score requires last_evaluated_at)audit_logparam toAgentEnginedocstringTest Plan
uv run python -m pytest tests/ -n 8-- 15,767 passed, 9 skippeduv run mypy src/ tests/-- 0 errorsuv run ruff check src/ tests/-- all passednpm --prefix web run type-check-- 0 errorsnpm --prefix web run lint-- 0 warningsCloses #1118
Closes #1119
Closes #1120
Closes #1121