refactor: WP-3 API conventions + query performance + project-wide extra=forbid#1953
Conversation
Pre-reviewed by 24 agents; 44 findings addressed across pagination, error-contract, logging, docstrings, tests, tool-parity, and design docs.
Rebase onto main pulled in a frozen model lacking extra=forbid; the project-wide gate self-test (a #1918 acceptance criterion) flagged it. Bundled per the gate-surfaced-preexisting-fix rule.
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request implements a comprehensive set of improvements focusing on API boundary discipline, query performance, and system resilience. It standardizes Pydantic model configurations project-wide, optimizes database access patterns through improved indexing and pagination, and enhances error handling and rate limiting for critical endpoints. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 Recent 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). (8)
🧰 Additional context used📓 Path-based instructions (5)web/src/**/*.{js,jsx,ts,tsx,mts}📄 CodeRabbit inference engine (web/CLAUDE.md)
Files:
web/src/stores/**/*.ts📄 CodeRabbit inference engine (web/CLAUDE.md)
Files:
web/src/{api/endpoints,stores}/**/*.ts📄 CodeRabbit inference engine (web/CLAUDE.md)
Files:
web/src/**/*.{ts,tsx,mts}📄 CodeRabbit inference engine (web/CLAUDE.md)
Files:
web/**/*.{tsx,ts,jsx,js}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (1)📓 Common learnings🔇 Additional comments (1)
WalkthroughThis PR enforces project-wide Pydantic frozen models to set extra="forbid" (new gate + pre-commit hook and tests), adds scripts/check_frozen_model_extra_forbid.py, extends ErrorCode and DomainError classes, converts several controllers to raise domain errors and use PathId types, implements paginated repository APIs plus collect_all/collect_all_mapping helpers and drains in services/controllers, adds indexed single-row message/meeting lookups, introduces DB index migrations, refactors memory preflight to depth/time-bounded walks with outer timeouts, updates cache-control/ETag and telemetry backoff, and adjusts many tests and generated web types. |
There was a problem hiding this comment.
Code Review
This pull request implements a project-wide enforcement of the extra="forbid" constraint for all frozen Pydantic models, replacing the previous API-only gate. It introduces a new static analysis script, updates numerous models across the codebase, and refines error handling with specialized domain exceptions and error codes. Furthermore, the PR optimizes repository performance by implementing pagination for multiple high-traffic read paths, accompanied by new database indices and utility functions for result reassembly. Review feedback highlights an opportunity to improve the consistency of PostgreSQL search queries using explicit escape clauses and suggests implementing cursor-based pagination at the API boundary for subworkflow searches to prevent excessive memory usage.
| # ``limit * versions_per_subworkflow``. | ||
| await cur.execute( | ||
| "SELECT subworkflow_id FROM subworkflows" | ||
| " WHERE name ILIKE %s OR description ILIKE %s" |
There was a problem hiding this comment.
The ILIKE query uses wildcards (%) in the pattern constructed on line 418, but it does not explicitly specify an ESCAPE clause. While PostgreSQL defaults to \ as the escape character, it is safer and more consistent with the SQLite implementation (line 498) to explicitly provide ESCAPE '\\' to ensure that literal backslashes, percent signs, or underscores in the search query are handled correctly regardless of server configuration.
| " WHERE name ILIKE %s OR description ILIKE %s" | |
| " WHERE name ILIKE %s ESCAPE '\\' OR description ILIKE %s ESCAPE '\\'" |
| lambda limit, offset: registry.search( | ||
| NotBlankStr(q), | ||
| limit=limit, | ||
| offset=offset, | ||
| ), |
There was a problem hiding this comment.
This endpoint drains all matching subworkflows from the repository into memory before returning them in a single response. While the repository now supports pagination to bound database-side scan costs, a very large result set could still lead to high memory usage in the API process and large network payloads. Consider implementing cursor-based pagination at the API boundary for this search endpoint, similar to list_parents (line 332).
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/synthorg/persistence/sqlite/subworkflow_repo.py (1)
632-700:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winPagination default can bypass referential-integrity checks.
find_parentsnow returns only one page by default, butdelete_if_unreferencedstill calls it once (Line 592). That can miss references beyondDEFAULT_PAGE_SIZE, allowing deletion of still-referenced versions.🔧 Suggested fix
@@ - parents = await self.find_parents(subworkflow_id, version) + # Must check the full parent set for referential integrity. + parents = await self._find_parents_unpaged(subworkflow_id, version) if parents: await self._db.rollback() return False, parents @@ - async def find_parents( + async def find_parents( self, subworkflow_id: NotBlankStr, version: NotBlankStr | None = None, *, limit: int = DEFAULT_PAGE_SIZE, offset: int = 0, ) -> tuple[ParentReference, ...]: + references = await self._find_parents_unpaged(subworkflow_id, version) + return tuple(references[offset : offset + limit]) + + async def _find_parents_unpaged( + self, + subworkflow_id: NotBlankStr, + version: NotBlankStr | None = None, + ) -> tuple[ParentReference, ...]: ... - references.sort(...) - return tuple(references[offset : offset + limit]) + references.sort(...) + return tuple(references)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/synthorg/persistence/sqlite/subworkflow_repo.py` around lines 632 - 700, find_parents currently returns a single default-sized page which lets delete_if_unreferenced miss later references; update the delete_if_unreferenced call site to fully drain all pages by iterating or using the existing helper collect_all when calling find_parents. Specifically, change the code that calls find_parents (method delete_if_unreferenced) to call synthorg.persistence._shared.collect_all(self.find_parents(...)) or implement a loop that repeatedly calls find_parents with increasing offset until no more results, so every ParentReference is examined before deleting a version.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/synthorg/core/company.py`:
- Line 153: The ReportingLine model's model_config is missing extra="forbid"
(currently ConfigDict(frozen=True, allow_inf_nan=False)), so update
ReportingLine.model_config to ConfigDict(frozen=True, allow_inf_nan=False,
extra="forbid") to prevent unknown fields being accepted in this frozen nested
model; locate the ReportingLine class and its model_config assignment and add
the extra="forbid" flag to match project-wide pydantic v2 guidelines.
In `@src/synthorg/hr/training/config.py`:
- Around line 33-37: Replace the inline numeric caps in the dict returned by the
Config mapping (the entries for ContentType.PROCEDURAL, ContentType.SEMANTIC,
ContentType.TOOL_PATTERNS) with named constants sourced from settings
definitions or module-level annotated constants; add/consume constants like
PROCEDURAL_CAP, SEMANTIC_CAP, TOOL_PATTERNS_CAP (typed, e.g., int) in the
settings/definitions module (or at top of src/synthorg/hr/training/config.py if
settings import is preferred) and then reference those symbols in the return
dict instead of the hardcoded numbers so no plain numeric literals remain in the
mapping.
In `@src/synthorg/memory/service.py`:
- Around line 106-113: Remove migration/history framing from the inline
docstring that describes the CHECKPOINT_ROLLBACK_UNAVAILABLE handling: rewrite
the docstring to explain only the current intent and why the handler emits a 422
with the specific CHECKPOINT_ROLLBACK_UNAVAILABLE code (i.e., checkpoint exists
but required stored backup config is missing), avoid any references to prior
behavior, migrations, reviewer citations or comparative migration context; apply
the same cleanup to other nearby comments/docstrings that reference
migration/history framing related to EXCEPTION_HANDLERS or checkpoint rollback
logic so all in-code comments describe only the current reason/intent.
In `@src/synthorg/persistence/postgres/circuit_breaker_repo.py`:
- Around line 176-189: The load_all method currently forwards pagination args to
list_items without validation; call validate_pagination_args(limit=limit,
offset=offset) at the start of load_all (or alternatively add the same call
inside list_items) to enforce non-negative/allowed bounds and raise the existing
validation error immediately; ensure the import/reference to
validate_pagination_args is present and keep the subsequent return await
self.list_items(limit=limit, offset=offset) unchanged so callers get the same
behavior after validation.
In `@tests/unit/api/fakes_workflow.py`:
- Around line 365-375: The test helper truncates inputs by calling
self.list_summaries() with its default page cap, so change it to fetch all
summaries before filtering: call self.list_summaries with an explicit parameter
to retrieve the full set (or implement a loop to page through until no more
results) and assign that to summaries, then apply the existing filtering (q,
matched, sorting, and slicing by offset/limit) unchanged; reference the
list_summaries call, the summaries variable, and the matched/q/offset/limit
logic when making the change.
In `@tests/unit/engine/workflow/test_subworkflow_registry.py`:
- Around line 155-168: The search function (search) currently calls
list_summaries() with its default capped limit (DEFAULT_PAGE_SIZE), which
truncates candidates before filtering and pagination; fix by fetching the full
untruncated set of summaries before filtering — e.g., call list_summaries with
no limit or a sufficiently large limit (or use a dedicated list_all_summaries
helper) so that matched = sorted((s for s in summaries if q in s.name.lower() or
q in s.description.lower()), ...) operates over all summaries, then apply
offset/limit slicing to matched.
In `@tests/unit/persistence/_shared/test_pagination.py`:
- Around line 33-40: The test test_exact_multiple_stops_on_empty_page currently
only asserts the returned rows and doesn't verify that collect_all performs the
terminating empty fetch; modify the test to track calls to the inner fetch
(e.g., add a counter or list like calls = [] and append the (limit, offset) on
each invocation inside fetch) and assert after collect_all that the expected
sequence of fetch calls occurred including the final empty-page call (for
page_size=100 expect offsets 0,100,200 with the last fetch returning empty).
Ensure references to the inner fetch function and collect_all remain the same so
the test fails if the empty fetch is skipped.
---
Outside diff comments:
In `@src/synthorg/persistence/sqlite/subworkflow_repo.py`:
- Around line 632-700: find_parents currently returns a single default-sized
page which lets delete_if_unreferenced miss later references; update the
delete_if_unreferenced call site to fully drain all pages by iterating or using
the existing helper collect_all when calling find_parents. Specifically, change
the code that calls find_parents (method delete_if_unreferenced) to call
synthorg.persistence._shared.collect_all(self.find_parents(...)) or implement a
loop that repeatedly calls find_parents with increasing offset until no more
results, so every ParentReference is examined before deleting a version.
🪄 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 (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: e4dbfe39-4435-4cf2-a970-a35c7cad9c64
📒 Files selected for processing (202)
.opencode/plugins/synthorg-hooks.ts.pre-commit-config.yamlCLAUDE.mddocs/design/agents.mddocs/design/memory.mddocs/reference/audit-category-gate-coverage.mddocs/reference/convention-gates.mddocs/reference/conventions.mddocs/reference/errors.mdscripts/check_dto_forbid_extra.pyscripts/check_frozen_model_extra_forbid.pysrc/synthorg/api/auth/service.pysrc/synthorg/api/auth/ticket_store.pysrc/synthorg/api/config.pysrc/synthorg/api/controllers/_webhooks_wiring.pysrc/synthorg/api/controllers/agent_identity_versions.pysrc/synthorg/api/controllers/memory.pysrc/synthorg/api/controllers/meta.pysrc/synthorg/api/controllers/settings.pysrc/synthorg/api/controllers/subworkflows.pysrc/synthorg/api/controllers/training.pysrc/synthorg/api/controllers/workflows.pysrc/synthorg/api/cursor_config.pysrc/synthorg/api/etag.pysrc/synthorg/api/pagination.pysrc/synthorg/api/rate_limits/policies.pysrc/synthorg/api/rate_limits/protocol.pysrc/synthorg/api/ws_models.pysrc/synthorg/backup/errors.pysrc/synthorg/budget/baseline_store.pysrc/synthorg/budget/call_analytics_config.pysrc/synthorg/budget/call_analytics_models.pysrc/synthorg/budget/call_classifier.pysrc/synthorg/budget/category_analytics.pysrc/synthorg/budget/config.pysrc/synthorg/budget/coordination_config.pysrc/synthorg/budget/coordination_metrics.pysrc/synthorg/budget/coordination_store.pysrc/synthorg/budget/cost_record.pysrc/synthorg/budget/cost_tiers.pysrc/synthorg/budget/hierarchy.pysrc/synthorg/budget/optimizer_models.pysrc/synthorg/budget/project_cost_aggregate.pysrc/synthorg/budget/quota.pysrc/synthorg/budget/quota_poller_config.pysrc/synthorg/budget/report_config.pysrc/synthorg/budget/report_templates.pysrc/synthorg/budget/reports.pysrc/synthorg/budget/risk_check.pysrc/synthorg/budget/risk_config.pysrc/synthorg/budget/risk_record.pysrc/synthorg/budget/spending_summary.pysrc/synthorg/budget/trends.pysrc/synthorg/communication/handler.pysrc/synthorg/communication/loop_prevention/circuit_breaker.pysrc/synthorg/communication/meetings/service.pysrc/synthorg/communication/message.pysrc/synthorg/communication/messages/service.pysrc/synthorg/coordination/ceremony_policy/service.pysrc/synthorg/core/agent.pysrc/synthorg/core/approval.pysrc/synthorg/core/artifact.pysrc/synthorg/core/auth/config.pysrc/synthorg/core/auth/models.pysrc/synthorg/core/auth/refresh_record.pysrc/synthorg/core/auth/session.pysrc/synthorg/core/company.pysrc/synthorg/core/domain_errors.pysrc/synthorg/core/error_taxonomy.pysrc/synthorg/core/evidence.pysrc/synthorg/core/project.pysrc/synthorg/core/resilience_config.pysrc/synthorg/core/role.pysrc/synthorg/core/structured_artifact.pysrc/synthorg/core/task.pysrc/synthorg/core/tool_disclosure.pysrc/synthorg/engine/decisions.pysrc/synthorg/engine/strategy/context.pysrc/synthorg/engine/trajectory/models.pysrc/synthorg/engine/workflow/subworkflow_registry.pysrc/synthorg/engine/workflow/subworkflow_service.pysrc/synthorg/hr/training/config.pysrc/synthorg/integrations/config.pysrc/synthorg/integrations/connections/models.pysrc/synthorg/integrations/mcp_catalog/installations.pysrc/synthorg/integrations/mcp_catalog/service.pysrc/synthorg/integrations/webhooks/models.pysrc/synthorg/memory/service.pysrc/synthorg/meta/analytics/models.pysrc/synthorg/meta/chief_of_staff/config.pysrc/synthorg/meta/chief_of_staff/models.pysrc/synthorg/meta/config.pysrc/synthorg/meta/evolution/outcome_models.pysrc/synthorg/meta/mcp/handlers/common.pysrc/synthorg/meta/mcp/registry.pysrc/synthorg/meta/models.pysrc/synthorg/meta/reports/models.pysrc/synthorg/meta/rollout/ab_models.pysrc/synthorg/meta/rollout/group_aggregator.pysrc/synthorg/meta/rollout/regression/statistical.pysrc/synthorg/meta/rollout/regression/welch.pysrc/synthorg/meta/rules/custom.pysrc/synthorg/meta/signal_models.pysrc/synthorg/meta/telemetry/config.pysrc/synthorg/meta/telemetry/models.pysrc/synthorg/notifications/config.pysrc/synthorg/notifications/models.pysrc/synthorg/observability/audit_chain/chain.pysrc/synthorg/observability/config.pysrc/synthorg/observability/events/memory.pysrc/synthorg/observability/events/persistence.pysrc/synthorg/ontology/config.pysrc/synthorg/ontology/models.pysrc/synthorg/ontology/service.pysrc/synthorg/persistence/_shared/__init__.pysrc/synthorg/persistence/_shared/pagination.pysrc/synthorg/persistence/agent_state_protocol.pysrc/synthorg/persistence/checkpoint_protocol.pysrc/synthorg/persistence/circuit_breaker_protocol.pysrc/synthorg/persistence/config.pysrc/synthorg/persistence/idempotency_protocol.pysrc/synthorg/persistence/memory_protocol.pysrc/synthorg/persistence/message_protocol.pysrc/synthorg/persistence/ontology_protocol.pysrc/synthorg/persistence/parked_context_protocol.pysrc/synthorg/persistence/postgres/agent_state_repo.pysrc/synthorg/persistence/postgres/circuit_breaker_repo.pysrc/synthorg/persistence/postgres/heartbeat_repo.pysrc/synthorg/persistence/postgres/ontology_entity_repo.pysrc/synthorg/persistence/postgres/org_fact_repo.pysrc/synthorg/persistence/postgres/parked_context_repo.pysrc/synthorg/persistence/postgres/repositories.pysrc/synthorg/persistence/postgres/revisions/20260517000001_wp3_query_indices.sqlsrc/synthorg/persistence/postgres/schema.sqlsrc/synthorg/persistence/postgres/subworkflow_repo.pysrc/synthorg/persistence/settings_protocol.pysrc/synthorg/persistence/sqlite/agent_state_repo.pysrc/synthorg/persistence/sqlite/circuit_breaker_repo.pysrc/synthorg/persistence/sqlite/heartbeat_repo.pysrc/synthorg/persistence/sqlite/ontology_entity_repo.pysrc/synthorg/persistence/sqlite/org_fact_repo.pysrc/synthorg/persistence/sqlite/parked_context_repo.pysrc/synthorg/persistence/sqlite/repositories.pysrc/synthorg/persistence/sqlite/revisions/20260517000001_wp3_query_indices.sqlsrc/synthorg/persistence/sqlite/schema.sqlsrc/synthorg/persistence/sqlite/subworkflow_repo.pysrc/synthorg/persistence/subworkflow_protocol.pysrc/synthorg/providers/cost_recording.pysrc/synthorg/providers/management/capability_dtos.pysrc/synthorg/settings/bootstrap_resolver.pysrc/synthorg/settings/definitions/memory.pysrc/synthorg/settings/errors.pysrc/synthorg/settings/models.pysrc/synthorg/telemetry/collector.pysrc/synthorg/telemetry/protocol.pysrc/synthorg/templates/preset_service.pysrc/synthorg/tools/analytics/config.pysrc/synthorg/tools/base.pysrc/synthorg/tools/communication/config.pysrc/synthorg/tools/database/config.pysrc/synthorg/tools/design/config.pysrc/synthorg/tools/design/image_generator.pysrc/synthorg/tools/disclosure_config.pysrc/synthorg/tools/git_url_validator.pysrc/synthorg/tools/html_parse_guard.pysrc/synthorg/tools/integrity_check.pysrc/synthorg/tools/invocation_record.pysrc/synthorg/tools/mcp/config.pysrc/synthorg/tools/mcp/models.pysrc/synthorg/tools/network_validator.pysrc/synthorg/tools/sandbox/config.pysrc/synthorg/tools/sandbox/docker_config.pysrc/synthorg/tools/sandbox/lifecycle/config.pysrc/synthorg/tools/sandbox/policy.pysrc/synthorg/tools/sandbox/sandboxing_config.pysrc/synthorg/tools/sub_constraint_enforcer.pysrc/synthorg/tools/terminal/config.pysrc/synthorg/tools/web/config.pysrc/synthorg/versioning/models.pysrc/synthorg/workers/claim.pysrc/synthorg/workers/config.pytests/conformance/persistence/test_core_repositories.pytests/integration/engine/test_multi_agent_delegation.pytests/unit/api/controllers/test_agent_identity_versions.pytests/unit/api/controllers/test_memory_admin.pytests/unit/api/controllers/test_workflows.pytests/unit/api/fakes_workflow.pytests/unit/api/rate_limits/test_controller_coverage.pytests/unit/api/rate_limits/test_guard.pytests/unit/api/test_dto_forbid_extra.pytests/unit/api/test_etag.pytests/unit/api/test_exception_handlers.pytests/unit/communication/meetings/test_service.pytests/unit/communication/messages/test_service.pytests/unit/engine/workflow/test_subworkflow_registry.pytests/unit/memory/test_service.pytests/unit/persistence/_shared/test_pagination.pytests/unit/persistence/test_protocol.pytests/unit/scripts/test_check_frozen_model_extra_forbid.pytests/unit/telemetry/test_collector.pyweb/src/api/types/error-codes.gen.tsweb/src/api/types/openapi.gen.ts
💤 Files with no reviewable changes (2)
- scripts/check_dto_forbid_extra.py
- tests/unit/api/test_dto_forbid_extra.py
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1953 +/- ##
==========================================
+ Coverage 84.89% 84.92% +0.02%
==========================================
Files 1858 1858
Lines 109992 110151 +159
Branches 9412 9420 +8
==========================================
+ Hits 93380 93543 +163
+ Misses 14308 14306 -2
+ Partials 2304 2302 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
CI: regenerate data/runtime_stats.yaml (tests display drift 31,000+ vs 30,000+). CodeRabbit: core/company.py ReportingLine gains extra=forbid (WP-3 scope); hr/training/config.py caps become module-level Final[int] constants; memory/service.py docstrings and comments stripped of migration/history framing; postgres/circuit_breaker_repo.py list_items calls validate_pagination_args (sqlite parity); sqlite/subworkflow_repo.py adds _find_parents_unpaged so delete_if_unreferenced sees the full parent set (parity with postgres _find_parents_with_conn; fixes truncated parent set returned to the API); tests fakes_workflow.py and test_subworkflow_registry.py search() no longer pre-truncate; test_pagination.py asserts the terminating empty-page fetch sequence. Gemini: postgres/subworkflow_repo.py ILIKE gets an explicit ESCAPE clause (sqlite parity); /subworkflows/search is now cursor-paginated (PaginatedResponse), openapi.gen.ts regenerated and the web endpoint/store/mocks/test updated.
…rbid extra=forbid (added this round for the WP-3 gate) makes computed keys subordinate_key/supervisor_key non-round-trippable as constructor inputs; exclude them on model_validate, matching the project-wide forbid contract.
Round 1's cursor-pagination cascade left a TS7022 in stores/subworkflows.ts: the search/list ternary defeated return-type inference for the loop-local page. Annotate page as PaginatedResult<SubworkflowSummary> and import the type from @/api/client. Fixes Dashboard Type Check + Dashboard Build; the melange and Lighthouse failures were downstream of the build break. Verified locally: web type-check, vite build, and the subworkflows store test all green.
<!-- HIGHLIGHTS_START --> ## Highlights > _AI-generated summary (model: `openai/gpt-4.1-mini` via GitHub Models). Commit-based changelog below._ ### What you'll notice - Frontend WP-6 update with UX polish improves user interface and workflow. - Dashboard and training endpoint improvements enhance observability and dispatch behavior. - Web storybook now supports change detection for more responsive UI interactions. - Git hooks now isolated per worktree for cleaner repository management. - Providers automatically detect native streaming support in Litellm models. ### What's new - Added a new pipeline to convert Pydantic DTOs to TypeScript for better front-end compatibility. ### Under the hood - Refactored settings to three precedence categories, removing YAML tier for simpler configuration. - Completed RootConfig mirror coverage for enhanced configuration consistency. - Adopted API conventions with better query performance and forbidden extra fields for stricter validation. - Improved persistence, layer discipline, and restart safety in core work packages. - CI updated with split test jobs and tightened coverage gates for better test quality. - Switched to direct Trivy binary for security scans, removing previous Trivy action dependency. - Enhanced memory management with per-call processing options and better observability during speech-to-text encoding. - Various dependency updates for Python, infrastructure, and lock files maintain security and stability. - Removed TypeScript DTO type-tightening overlays to simplify type management. - Codebase audit tightened skill sets to prevent false positivity in class detection by 2026. <!-- HIGHLIGHTS_END --> :robot: I have created a release *beep* *boop* --- ## [0.8.5](v0.8.4...v0.8.5) (2026-05-17) ### Features * **codegen:** pydantic-to-typescript DTO pipeline + parity gate (closes [#1889](#1889)) ([#1909](#1909)) ([0265ef5](0265ef5)) * **storybook:** enable changeDetection + trim web/CLAUDE.md ([#1939](#1939)) ([3b1f4c0](3b1f4c0)) * **web,setup:** WP-6 frontend + UX polish ([#1941](#1941)) ([d9ca76d](d9ca76d)) ### Bug Fixes * correct invalid git for-each-ref syntax in post-merge-cleanup skill ([#1946](#1946)) ([69a1649](69a1649)) * dashboard polish, training endpoint dispatch, and observability cleanup ([#1911](#1911)) ([b61e9e8](b61e9e8)) * per-worktree git-hook isolation + hookify gate migration + MSW drift fix ([#1949](#1949)) ([e3f8495](e3f8495)) * **providers:** read supports_native_streaming from litellm model info ([#1942](#1942)) ([60364ca](60364ca)) * security and audit coverage (closes [#1883](#1883)) ([#1904](#1904)) ([d8ebf55](d8ebf55)) ### Performance * **ci:** mypy --num-workers=4 + enable ruff TID255 ([#1944](#1944)) ([484c1d3](484c1d3)) ### Refactoring * **ci:** drop aquasecurity/trivy-action, use direct trivy binary ([#1940](#1940)) ([df1f946](df1f946)) * **memory:** per-call processing_kwargs + observability for ST encode ([#1943](#1943)) ([3aa9d20](3aa9d20)) * Phase 7 follow-up — complete RootConfig mirror coverage (closes [#1907](#1907)) ([#1914](#1914)) ([605500b](605500b)) * **settings:** collapse precedence to three categories; drop YAML tier (closes [#1890](#1890)) ([#1910](#1910)) ([efd54c9](efd54c9)) * WP-3 API conventions + query performance + project-wide extra=forbid ([#1953](#1953)) ([504d579](504d579)), closes [#1918](#1918) * WP-4 settings + cross-cutting (clock seam, contextvars, dispatch, plugin surfaces) ([#1954](#1954)) ([7207d92](7207d92)) * **wp1:** persistence + layer discipline + restart safety ([#1945](#1945)) ([57586fb](57586fb)) ### Documentation * **wp5:** public-facing truth refresh ([#1924](#1924)) ([afb5cc5](afb5cc5)) ### CI/CD * split test job by marker with airtight aggregate coverage gate ([#1948](#1948)) ([0b818d5](0b818d5)), closes [#1938](#1938) [#1937](#1937) ### Maintenance * **codebase-audit:** tighten skill to prevent 2026-05-15 FP classes ([#1923](#1923)) ([9317ed1](9317ed1)) * Lock file maintenance ([#1913](#1913)) ([c08a355](c08a355)) * Lock file maintenance ([#1950](#1950)) ([8940ab1](8940ab1)) * remove TS DTO type-tightening overlays ([#1915](#1915)) ([d296214](d296214)), closes [#1906](#1906) * Update Infrastructure dependencies ([#1928](#1928)) ([d19fae5](d19fae5)) * Update Python dependencies ([#1929](#1929)) ([75cc2c8](75cc2c8)) * **wp7:** hygiene, stubs, test/CI/tooling, doc gaps, boundary patterns doc ([#1926](#1926)) ([c29eb32](c29eb32)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: synthorg-repo-bot[bot] <279117679+synthorg-repo-bot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
WP-3 (#1918): API boundary discipline + query performance + the project-wide
extra="forbid"rollout with its new enforcement gate.PathIdpath params across the 5 memory admin handlers (redundantNotBlankStr(...)runtime wraps dropped — they were no-ops).POST /training/{agent}/planandPUT .../overrides.extra="forbid"(~266 frozen models) + newcheck_frozen_model_extra_forbid.pygate;default_volume_capslambda → named factory.InternalServerException/NotFoundExceptionand inline 404s →DomainErrorsubclasses; ~15 newErrorCodeentries; regenerated TS error-code constants.MessageRepository.get_by_id+ indexed meeting lookup replace O(N) scans; real two-step SQL pagination forsubworkflow.search; sargableagent_state.get_active; composite/partial indices (snapshot, oplog, approvals, heartbeat) in both backends via one consolidated revision per backend.Cache-Controlon streaming ETag passthrough.Pre-PR review coverage
Reviewed by 24 agents (full roster + 5 audit mini-pass) before first push. 47 findings triaged: 41 fixed (36 code/test changes + the gate-surfaced
RefreshRotationfix), 3 dropped as verified false positives (would have violated MANDATORY rules / project structure — convention_gate_map registration, Code-conventions(MANDATORY)promotion, RS-sourced count hand-edit), 8 resolved by analysis as already-covered (existing layered tests / existing indices / intentional design), 1 invalid conflict (PEP 758except A, B:is correct per CLAUDE.md — not "fixed").Key behavioural test additions: training-endpoint burst-rejection (429), telemetry retry-exhaustion path, workflows 404
error_codeassertions;mock_of[...]specs replace bare mocks; design-doc model examples updated; OpenCode↔Claude tool-parity gap (check_no_git_no_verify.sh) closed.Test plan
ruff check/ruff format: cleanmypy --strict(full): clean, 3851 filesCloses #1918