Skip to content

feat: per-initiative operator-set autonomy mode#2579

Merged
Aureliolo merged 6 commits into
mainfrom
feat/operator-set-modes-gate
Jul 15, 2026
Merged

feat: per-initiative operator-set autonomy mode#2579
Aureliolo merged 6 commits into
mainfrom
feat/operator-set-modes-gate

Conversation

@Aureliolo

Copy link
Copy Markdown
Owner

Summary

Phase 2 of #2576: operators can set an oversight mode per initiative, and that mode tunes the per-action SecOps gate. This does not close #2576 (Phase 3, the build/test/review completion oracle, closes it).

  • Domain + resolution: Project.autonomy_mode (AutonomyLevel | None) resolved through a four-level chain (agent > initiative > department > company) into the existing AutonomyPreset/EffectiveAutonomy gate machinery. No new gate code: the mode selects the preset the gate already consumes.
  • Fail-closed: a project-mode lookup failure resolves to the most restrictive tier (locked), never None, so a transient persistence fault can never silently loosen an operator's override (corruption logged at ERROR).
  • CEO-only gate-off opt-in: transitioning an initiative to full (pass-through, gate disabled) requires the CEO role + an explicit confirm=true and is audited at WARNING with actor + from/to modes. Tightening/lateral transitions stay open to write-access roles.
  • Version-guarded writes: the autonomy-mode PATCH threads expected_version through the service into the repository, surfacing a 409 on a concurrent write instead of clobbering.
  • API: PATCH /projects/{id}/autonomy-mode (ProjectAutonomyModeRequest), projects.update rate policy, dedicated api.project.autonomy_mode_changed audit event, and a project.autonomy_mode_changed WS broadcast so other dashboards reflect the change live.
  • Persistence: new autonomy_mode column on projects (both backends) with a closed-set CHECK, one migration per backend, schema-drift clean.
  • Web: a project Oversight mode control (ProjectOversightSection) with a CEO-gated, confirmed opt-in for full, a disabled/stale-response-guarded store action, and the WS-handler + types wiring.

Test plan

  • uv run ruff check . && uv run mypy src/ tests/ (clean, 6184 files)
  • pytest unit + conformance for the resolver, project model, projects controller (CEO-only guardrail, missing-confirm 422, non-CEO 403, 409 version conflict, gate-off WARNING audit), worker glue (fail-closed-to-locked, resolver threading), and dual-backend autonomy_mode round-trip incl. full (181 passed)
  • npm --prefix web run lint | type-check | test (3891 passed, no leaked handles)
  • schema-drift (sqlite + postgres), architecture-drift, module-size, WS-protocol-sync, DTO/enum-in-sync: all green

Review coverage

Pre-reviewed by 15 agents (code / python / conventions / security / persistence / async-concurrency / silent-failure / type-design / api-contract / frontend / test-quality / issue-resolution / docs-consistency / comment-quality + ghost-wiring). Every valid finding addressed: the fail-open degrade and missing confirm+reason guardrail (both CRITICAL, security), the lost-update OCC bypass and audit-trail gap (HIGH, 5-6 agents), the frontend enum-parser + stale-response guard, and all doc/test findings. Two LOW items were resolved by user decision: the live WS broadcast is implemented; the SQLite status-column CHECK was dropped because a table rebuild would cascade-delete child rows via DROP TABLE under foreign_keys=ON (the autonomy_mode CHECK ships on both backends).

Relates to #2576.

@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 539202ff-3183-4a5a-bfcf-8ab0ef9802e8

📥 Commits

Reviewing files that changed from the base of the PR and between dfbdc18 and de56dad.

📒 Files selected for processing (2)
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout. (34)
  • GitHub Check: Build Backend
  • GitHub Check: Dashboard Test (shard 2/4)
  • GitHub Check: Dashboard Test (shard 4/4)
  • GitHub Check: Dashboard Test (shard 1/4)
  • GitHub Check: Dashboard Build
  • GitHub Check: Dashboard Test (shard 3/4)
  • GitHub Check: Dashboard Type Check
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: CodSpeed Python benchmarks
  • GitHub Check: CodSpeed Web benchmarks
  • GitHub Check: Lighthouse Site
  • GitHub Check: Lighthouse Dashboard
  • GitHub Check: Test Integration (shard 4)
  • GitHub Check: Test Unit (shard 3)
  • GitHub Check: Test Integration (shard 2)
  • GitHub Check: Test Integration (shard 3)
  • GitHub Check: Test Unit (shard 1)
  • GitHub Check: Test Integration (shard 1)
  • GitHub Check: Test Unit (shard 4)
  • GitHub Check: Dashboard Lint
  • GitHub Check: Test Unit (shard 2)
  • GitHub Check: Test Conformance (SQLite)
  • GitHub Check: Runtime Stats Freshness Gate
  • GitHub Check: Test E2E
  • GitHub Check: Dashboard E2E (Playwright)
  • GitHub Check: Prompt-Drift Regression Gate
  • GitHub Check: Gates (pre-commit all-files + parity)
  • GitHub Check: Build Preview
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: CLI Test (macos-latest)
  • GitHub Check: pyright (advisory)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (6)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{ts,tsx}: The dashboard is a pure API consumer: it must not persist domain or app state client-side, must hydrate from backend GETs on mount, and must write every change through the REST API immediately.
Do not use localStorage, sessionStorage, IndexedDB, or zustand persist for domain/app state (including setup-wizard state, theme/appearance, and user/org preferences); those values must live in backend settings and be rehydrated from GET/PUT.
Step/progress UI must be derived from backend state, not from a persisted client flag.
The only sanctioned client storage is non-domain transport/UX data: the auth-token cookie shim and the active CSRF token.
Use createLogger from @/lib/logger instead of bare console.* in app code, and use log.debug(), log.warn(), and log.error() with dynamic or untrusted values passed as separate args or structured objects sanitized via sanitizeArg/sanitizeForLog().
Pages that need to filter, sort, search, or aggregate across an entire dataset must load the full set with paginateAll and page it in the browser with useListPagination using ?{ns}Page / ?{ns}Size URL params.
Sanitize untrusted WebSocket strings with sanitizeWsString() / sanitizeWsEnum<T>(); never use raw casts, and do not use makeEnumParser<T> at a WebSocket boundary.
Import ErrorCode and ErrorCategory from @/api/types/errors, and discriminate on ErrorCode.<NAME> rather than raw integers.
Reuse existing components from web/src/components/ui/ before creating new ones; do not hardcode hex colors, fonts, pixel spacing, Motion durations, BCP 47 locale literals, or currency symbols.
Do not use getXIcon(): LucideIcon factories in JSX; export a <XIcon value={...} /> wrapper in its own file instead, and use useViewportSize() rather than raw window.innerWidth in render.
Follow the strict ESLint/type-safety rules: fix types instead of suppressing them, respect exactOptionalPropertyTypes and noUncheckedIndexedAccess...

Files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/stores/**/*.{ts,tsx}: Store create/update/delete mutations must follow the CRUD pattern: try/catch, success state update plus success toast, failure logging plus error toast plus sentinel return, with optimistic updates restoring previous state on error and using getCrudErrorTitle(err, fallback).
Callers must not wrap store mutation calls in try/catch; the store owns the mutation error UX.
List reads should set error: string | null instead of showing toast errors.
Cursor-paginated list endpoints must use opaque PaginationMeta cursors, store nextCursor and hasMore (no offset arithmetic), early-return when !hasMore || !nextCursor, and derive counts from data.length.

Files:

  • web/src/stores/projects/ws-handler.ts
web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/**/*.{js,jsx,ts,tsx}: In the React dashboard, reuse components from web/src/components/ui/ and use design tokens only.
The frontend must be a pure API consumer: do not persist application or domain state in client storage; hydrate through GET requests and write changes through the API.

Files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Every convention pull request must ship its enforcement gate.
Commits must use <type>: <description>, branches must use <type>/<slug>, and changes must be squash-merged.

Files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
**/*.{py,js,jsx,ts,tsx,go}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{py,js,jsx,ts,tsx,go}: Do not add AGPL/GPL (non-LGPL) dependencies; attribute permitted LGPL dependencies in NOTICE.
Never use real vendor names in project code or tests; use approved example provider names, except in documented allowlisted locations.

Files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
web/src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{test,spec}.{ts,tsx}: Tests must override MSW behavior with server.use(...) and must not vi.mock('@/api/endpoints/*').
Unit tests run under the active-handle tracker and must not leak event-loop resources from web/src/ frames.

Files:

  • web/src/__tests__/stores/projects.test.ts
🧠 Learnings (9)
📚 Learning: 2026-05-28T22:27:09.037Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/auth-sessions.test.ts:8-8
Timestamp: 2026-05-28T22:27:09.037Z
Learning: In the frontend, `SessionInfo` is a local type alias for `SessionResponse` defined only in `web/src/api/types/auth.ts` (exported as `SessionResponse as SessionInfo`). It is not re-exported via the `@/api/types` barrel (which only re-exports `dtos.gen` including `SessionResponse`). Therefore, all code (including React components, stores, and tests) that needs `SessionInfo` must import it from `@/api/types/auth` and not from `@/api/types`. (Import `SessionResponse` from `@/api/types` only when `SessionResponse` is what you need.)

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-28T22:27:14.761Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/backups.test.ts:9-9
Timestamp: 2026-05-28T22:27:14.761Z
Learning: In the synthorg web package, follow the established convention for importing DTOs from the domain-specific sub-barrels under `@/api/types/<domain>`, e.g. `import type { BackupInfo } from '`@/api/types/backup`'`. These domain sub-barrels are curated and re-export from generated DTOs (e.g., `./dtos.gen`), so they are not considered “deep reach” imports. Do not recommend changing these imports to the top-level `@/api/types` barrel (e.g., `@/api/types`)—production code and tests consistently use the domain-specific sub-barrel paths (such as `stores/backups.ts`, `AdminBackupsPage.tsx`, and `mocks/handlers/backup.ts`).

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-28T22:27:25.293Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/workflows-export.test.ts:7-7
Timestamp: 2026-05-28T22:27:25.293Z
Learning: When reviewing code in this repository, if the change touches or adds types related to workflows, ensure those imports come from the domain-specific curated barrel at `@/api/types/workflows` (e.g., `@/api/types/workflows`), not from the top-level `@/api/types` barrel. Do not recommend switching workflow-related type imports to the top-level barrel; this convention is the established pattern across workflow UI/components, workflow editor store code, related hooks, and workflow-related tests.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-29T15:33:54.576Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2163
File: web/src/pages/providers/provider-form-helpers.ts:1-9
Timestamp: 2026-05-29T15:33:54.576Z
Learning: In the synthorg web package (web/src), import provider-related DTO types (e.g., AuthType, CloudPreset, CreateFromPresetRequest, CreateProviderRequest, ProviderConfig, ProviderPreset, UpdateProviderRequest) from the domain sub-barrel `@/api/types/providers` and not from the top-level `@/api/types` barrel. These types are not re-exported from `@/api/types`; using the top-level barrel will cause compilation errors. Follow the established convention when updating provider-related code and imports.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-29T15:35:11.914Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2163
File: web/src/pages/setup/CompanyStep.tsx:18-18
Timestamp: 2026-05-29T15:35:11.914Z
Learning: In the synthorg web package, when using setup-related DTO types (e.g., `SetupAgentSummary`, `SetupCompanyResponse`), import them from the setup domain sub-barrel `@/api/types/setup` rather than from the top-level `@/api/types`. The setup DTOs are not re-exported from `@/api/types`, so importing from the top-level barrel will fail to compile. Follow the existing domain-sub-barrel convention used elsewhere (e.g., `@/api/types/backup`, `@/api/types/workflows`, `@/api/types/auth`) and do not recommend moving setup-domain type imports to `@/api/types`.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-31T00:00:32.734Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2172
File: web/src/pages/project-brain/BrainEntryList.tsx:12-45
Timestamp: 2026-05-31T00:00:32.734Z
Learning: In the synthorg web package, do not flag React components for ESLint `max-params` violations based on destructured prop fields. ESLint `max-params` counts the number of function parameters (arity), not properties inside a destructured object. For example, `function BrainEntryList({ entries, loading, hasMore, ... }: BrainEntryListProps)` has exactly 1 parameter (the props object) and should not be considered a `max-params: 5` violation, even if the props type/interface contains 10+ fields. Only flag when a function declares 6+ separate parameters.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-06-13T14:07:55.334Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2356
File: web/src/components/ui/ws-connection-banner.tsx:30-45
Timestamp: 2026-06-13T14:07:55.334Z
Learning: In the synthorg web package, treat leading underscores on function names as an intentional convention for module-local, non-exported helper/utility functions (e.g., `_resolveBannerKind`, `_handleConflict`, `_statusFallback`, `_hasRequiredCredentials`, `_decideRetryWait`, `_shouldKeepRetrying`). Do not flag these or suggest renaming to remove the underscore. This does not conflict with React hook linting rules (e.g., the rule that React hook/sub-hook helpers must start with `use` and must not use leading underscores); only apply that hook-specific guidance to actual hook helpers, not plain utility functions.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-06-25T14:59:52.946Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2476
File: web/CLAUDE.md:31-34
Timestamp: 2026-06-25T14:59:52.946Z
Learning: For the TypeScript/React web dashboard code under web/src (e.g., dashboard utilities/components), follow the web logging convention: import and use `createLogger` from `@/lib/logger`, and name the resulting logger variable `log`. Do not apply the Python backend logging helper pattern (`get_logger` from `src/synthorg/observability/_logger.py` and its `logger` variable) to web TypeScript files.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-06-05T10:17:59.769Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2231
File: web/src/pages/org/build-org-tree-types.ts:122-122
Timestamp: 2026-06-05T10:17:59.769Z
Learning: When indexing an exhaustive TypeScript `Record<K, V>` (e.g., `SENIORITY_RANK: Record<SeniorityLevel, number>`) using a value whose parameter/type is the same union key type (e.g., `seniorityOf(level: SeniorityLevel)`), TypeScript already guarantees the key is covered at build time. In this case, do NOT request a runtime `?? fallback` or suggest handling for an `UNKNOWN` key unless the codebase has an explicit/ documented runtime drift or “unrecognized value” contract (like the one handled in `computeCategoryBreakdown` in `web/src/utils/budget.ts`). Also, don’t suggest non-existent keys that are not part of the union type.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
🔇 Additional comments (2)
web/src/__tests__/stores/projects.test.ts (1)

546-546: LGTM!

Also applies to: 568-616

web/src/stores/projects/ws-handler.ts (1)

22-28: LGTM!


Walkthrough

Adds nullable project-level autonomy modes with persistence, four-level resolution, guarded API updates, audit events, WebSocket propagation, worker integration, and fail-closed lookup behavior. The web application adds an oversight-mode selector with CEO-confirmed full mode, optimistic request handling, and synchronized project state. Project deletion cascade logic is moved into a dedicated controller module for plan and task termination. Documentation and tests cover the new contracts and flows.

Suggested labels: prio:medium, scope:web

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.64% which is insufficient. The required threshold is 40.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately names the main change: per-initiative operator-set autonomy mode.
Description check ✅ Passed The description clearly matches the autonomy-mode feature, its API, persistence, UI, and safety behavior updates.
Linked Issues check ✅ Passed The PR implements the per-initiative autonomy mode, fail-closed lookup, CEO-only full opt-in, versioned writes, and API/UI/persistence wiring required by #2576.
Out of Scope Changes check ✅ Passed The changes stay focused on the autonomy-mode feature set, with docs, tests, and generated types supporting the same scope.

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 granular autonomy management system, enabling operators to define oversight modes at the initiative level. By extending the existing autonomy resolution chain, the system now evaluates project-specific settings alongside agent, department, and company defaults. The implementation includes a robust API for updates, strict authorization for sensitive 'full' mode transitions, and comprehensive fail-closed safety checks to maintain security integrity even during transient persistence faults.

Highlights

  • Per-Initiative Autonomy Control: Introduced a new Project.autonomy_mode field, allowing operators to set specific oversight levels for individual initiatives.
  • Security & Authorization: Implemented a CEO-only 'full' mode (gate-off) that requires explicit confirmation and generates a WARNING audit event.
  • Optimistic Concurrency: Added version-guarded writes using expected_version to prevent race conditions during autonomy mode updates.
  • Fail-Closed Mechanism: Ensured that any project-mode lookup failure defaults to the most restrictive locked tier to prevent accidental privilege escalation.
  • Real-time Updates: Integrated WebSocket broadcasts to ensure that autonomy mode changes are reflected live across all connected dashboards.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai coderabbitai Bot added prio:medium Should do, but not blocking scope:web Vue 3 dashboard labels Jul 15, 2026
@Aureliolo
Aureliolo temporarily deployed to cloudflare-preview July 15, 2026 06:01 — with GitHub Actions Inactive

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a four-level autonomy resolution chain by adding a per-initiative (project-level) operator-set autonomy mode override, resolving below per-agent overrides and above department/company defaults. It includes database schema migrations, API updates with a new PATCH endpoint, worker execution service integration, and frontend UI controls. The review feedback highlights a potential fail-open security risk where an absent project lookup falls back to defaults, suggesting instead to fail closed to LOCKED autonomy.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

error=safe_error_description(exc),
)
return AutonomyLevel.LOCKED
return project.autonomy_mode if project is not None else None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-medium medium

If a task is associated with a project_id but the project cannot be found in the repository (i.e., project is None), returning None will cause the resolver to fall back to the department or company default. If the default is permissive (e.g., full or semi), this could lead to a fail-open scenario for an orphaned or anomalous task.

To align with the fail-closed philosophy, consider treating an absent project as a lookup failure and failing closed to AutonomyLevel.LOCKED. Note that if you apply this change, you will also need to update the corresponding test test_absent_project_returns_none in tests/unit/workers/test_execution_service.py to expect AutonomyLevel.LOCKED instead of None.

Suggested change
return project.autonomy_mode if project is not None else None
if project is None:
logger.warning(
WORKERS_EXECUTION_SERVICE_AUTONOMY_DEGRADED,
project_id=project_id,
reason="project_not_found",
fail_closed_to=AutonomyLevel.LOCKED.value,
)
return AutonomyLevel.LOCKED
return project.autonomy_mode

@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 106 untouched benchmarks


Comparing feat/operator-set-modes-gate (de56dad) with main (4b36d50)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (9e23459) during the generation of this report, so 4b36d50 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/synthorg/api/controllers/_project_autonomy.py`:
- Around line 36-39: Update the mode field declaration in the project autonomy
request model to remain nullable while requiring callers to provide it
explicitly; remove its default=None value and preserve the existing description
and type.

In `@src/synthorg/api/controllers/projects.py`:
- Around line 231-235: Update the project mutation flow around expected_version
to require the client-provided version instead of falling back to
project.version. Reject omitted expected_version consistently, and update the
web caller to send the displayed project version with the request so stale
writes produce the intended conflict response.
- Around line 221-227: Update the project autonomy change flow around
guard_full_autonomy_optin to resolve the effective post-change mode when
data.mode is None, including inherited department or company settings, and pass
that resolved target to the guard. Perform this resolution before persisting the
change and ensure audit data reflects whether the effective mode is full, so
clearing an override cannot bypass CEO confirmation.

In `@tests/conformance/persistence/test_project_repository.py`:
- Around line 59-75: Update the mode parameter list in
test_autonomy_mode_set_round_trips to include AutonomyLevel.SEMI, add its
matching “semi” pytest ID, and preserve the existing real-backend round-trip
assertions for every autonomy tier.

In `@tests/unit/api/controllers/test_projects.py`:
- Around line 190-207: Extend test_set_autonomy_mode_version_conflict after the
rejected PATCH by fetching the project with the existing async_test_client and
authentication headers, then assert autonomy_mode remains unchanged and,
preferably, version is unchanged from its initial value. Keep the existing 409
and success assertions while verifying the failed version-guarded write did not
mutate the row.

In `@web/src/api/types/websocket/provider.ts`:
- Around line 35-38: Update WsProjectAutonomyModeChangedPayload so new_mode and
previous_mode use the Project['autonomy_mode'] union type, preserving their
optional and nullable behavior instead of accepting arbitrary strings.

In `@web/src/mocks/handlers/projects.ts`:
- Line 6: Change the setProjectAutonomyMode import in the mock handlers module
to a type-only import, preserving its existing typeof usage and removing it from
the runtime dependency graph.

In `@web/src/stores/projects/crud-actions.ts`:
- Line 271: Include the current project version as expected_version in the
setProjectAutonomyModeApi call within the autonomy-mode update flow, preserving
mode and confirm. Update the mock handler in web/src/mocks/handlers/projects.ts
(lines 66-76) and the related tests in web/src/__tests__/stores/projects.test.ts
(lines 347-433) to accept and verify the version-aware request.

In `@web/src/stores/projects/ws-handler.ts`:
- Around line 64-75: The project.autonomy_mode_changed handler should
distinguish a legitimate null clear from an invalid mode. In the event block
around sanitizeWsEnumOrNull and applyAutonomyModeChanged, preserve raw null as
null without enum validation, but return early when a non-null payload.new_mode
fails sanitization; only call applyAutonomyModeChanged for valid modes or an
explicit null.
🪄 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 Plus

Run ID: 08efbd10-f55d-4897-8d3c-b2c560f0f8fb

📥 Commits

Reviewing files that changed from the base of the PR and between 4b36d50 and 398ba30.

📒 Files selected for processing (51)
  • docs/architecture/decisions.md
  • docs/design/page-structure.md
  • docs/design/security.md
  • docs/guides/security.md
  • src/synthorg/api/controllers/_project_autonomy.py
  • src/synthorg/api/controllers/_project_cascade.py
  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/guards.py
  • src/synthorg/api/rate_limits/policies.py
  • src/synthorg/api/services/project_service.py
  • src/synthorg/api/ws_models.py
  • src/synthorg/api/ws_payloads/__init__.py
  • src/synthorg/api/ws_payloads/_domain.py
  • src/synthorg/core/project.py
  • src/synthorg/observability/events/api.py
  • src/synthorg/persistence/postgres/project_repo.py
  • src/synthorg/persistence/postgres/revisions/20260715000000_project_autonomy_mode.sql
  • src/synthorg/persistence/postgres/schema.sql
  • src/synthorg/persistence/sqlite/project_repo.py
  • src/synthorg/persistence/sqlite/revisions/20260715000000_project_autonomy_mode.sql
  • src/synthorg/persistence/sqlite/schema.sql
  • src/synthorg/security/autonomy/resolver.py
  • src/synthorg/workers/execution_resume.py
  • src/synthorg/workers/execution_service/_agent_engine.py
  • src/synthorg/workers/execution_service/_autonomy.py
  • src/synthorg/workers/runtime_builder.py
  • tests/conformance/persistence/test_project_repository.py
  • tests/unit/api/controllers/test_projects.py
  • tests/unit/core/test_project.py
  • tests/unit/security/autonomy/test_resolver.py
  • tests/unit/workers/test_execution_service.py
  • tests/unit/workers/test_runtime_builder.py
  • web/src/__tests__/helpers/factories.ts
  • web/src/__tests__/pages/ProjectDetailPage.test.tsx
  • web/src/__tests__/pages/ProjectOversightSection.test.tsx
  • web/src/__tests__/stores/projects.test.ts
  • web/src/api/endpoints/projects.ts
  • web/src/api/types/backend-enums.gen.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/openapi.gen.ts
  • web/src/api/types/projects.ts
  • web/src/api/types/websocket/core.ts
  • web/src/api/types/websocket/provider.ts
  • web/src/mocks/handlers/projects.ts
  • web/src/pages/ProjectDetailPage.tsx
  • web/src/pages/projects/ProjectOversightSection.tsx
  • web/src/stores/projects.ts
  • web/src/stores/projects/_state.ts
  • web/src/stores/projects/crud-actions.ts
  • web/src/stores/projects/types.ts
  • web/src/stores/projects/ws-handler.ts

Comment thread src/synthorg/api/controllers/_project_autonomy.py
Comment thread src/synthorg/api/controllers/projects.py
Comment thread src/synthorg/api/controllers/projects.py
Comment thread tests/conformance/persistence/test_project_repository.py
Comment thread tests/unit/api/controllers/test_projects.py
Comment thread web/src/api/types/websocket/provider.ts Outdated
createProject,
getProject,
listProjects,
setProjectAutonomyMode,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Import the endpoint symbol as type-only.

setProjectAutonomyMode is used only through typeof; keep it out of the mock handler’s runtime dependency graph.

Proposed fix
-import {
-  setProjectAutonomyMode,
-} from '`@/api/endpoints/projects`'
+import type {
+  setProjectAutonomyMode,
+} from '`@/api/endpoints/projects`'

As per coding guidelines, “MSW handlers … import endpoint types with import type only.”

📝 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.

Suggested change
setProjectAutonomyMode,
import type {
setProjectAutonomyMode,
} from '`@/api/endpoints/projects`'
🤖 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 `@web/src/mocks/handlers/projects.ts` at line 6, Change the
setProjectAutonomyMode import in the mock handlers module to a type-only import,
preserving its existing typeof usage and removing it from the runtime dependency
graph.

Source: Coding guidelines

Comment thread web/src/stores/projects/crud-actions.ts Outdated
Comment thread web/src/stores/projects/ws-handler.ts Outdated
Adds Project.autonomy_mode resolved through a four-level chain (agent > initiative > department > company) into the SecOps gate, a CEO-only confirmed opt-in for the gate-off full mode, a dedicated audit event, version-guarded writes, a live WS broadcast, and the project oversight-mode control. Pre-reviewed by 15 agents; all valid findings addressed.
@Aureliolo
Aureliolo force-pushed the feat/operator-set-modes-gate branch from 398ba30 to 1b44a01 Compare July 15, 2026 06:31
@Aureliolo
Aureliolo temporarily deployed to cloudflare-preview July 15, 2026 06:33 — with GitHub Actions Inactive
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.71795% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.08%. Comparing base (9e23459) to head (de56dad).

Files with missing lines Patch % Lines
src/synthorg/api/controllers/_project_cascade.py 95.45% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main    #2579    +/-   ##
========================================
  Coverage   89.08%   89.08%            
========================================
  Files        3283     3286     +3     
  Lines      168910   169014   +104     
========================================
+ Hits       150467   150570   +103     
- Misses      18443    18444     +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@docs/guides/security.md`:
- Line 241: Update the resolution-chain text adjacent to the department override
guidance to include the existing project-level override as the fallback after
clearing a department override, before the company default. Preserve the
documented precedence order and adjust only the fallback description.

In `@src/synthorg/api/controllers/_project_cascade.py`:
- Around line 45-47: Update the project teardown path and task/plan creation
paths to use a shared deleting or lock state for the project. Mark the project
as deleting before scanning children, have child creation reject or wait while
that state is active, and remove the state only after the project row and
cascade complete, preventing children from being created between the final scan
and deletion.

In `@web/src/pages/projects/ProjectOversightSection.tsx`:
- Around line 80-82: Update the full-mode confirmation handler in
ProjectOversightSection to return the setAutonomyMode result as a boolean,
mapping the store’s null failure sentinel to false so ConfirmDialog stays open
when the PATCH fails while successful updates close it normally. Add a
regression test covering the failed full-mode update and retryable dialog
behavior.

In `@web/src/stores/projects/_state.ts`:
- Line 3: Replace the module-wide _autonomyModeRequestToken with per-project
token storage, and update setAutonomyModeImpl to pass the project ID when
creating and validating request tokens. Ensure each project’s latest request
invalidates only earlier requests for that same project, while updates for
different projects remain independent.
🪄 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 Plus

Run ID: c42fe610-fcc0-465e-9224-53c86093d99e

📥 Commits

Reviewing files that changed from the base of the PR and between 398ba30 and 1b44a01.

📒 Files selected for processing (52)
  • docs/architecture/decisions.md
  • docs/design/page-structure.md
  • docs/design/security.md
  • docs/guides/security.md
  • src/synthorg/api/controllers/_project_autonomy.py
  • src/synthorg/api/controllers/_project_cascade.py
  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/guards.py
  • src/synthorg/api/rate_limits/policies.py
  • src/synthorg/api/services/project_service.py
  • src/synthorg/api/ws_models.py
  • src/synthorg/api/ws_payloads/__init__.py
  • src/synthorg/api/ws_payloads/_domain.py
  • src/synthorg/core/project.py
  • src/synthorg/observability/events/api.py
  • src/synthorg/persistence/postgres/project_repo.py
  • src/synthorg/persistence/postgres/revisions/20260715000000_project_autonomy_mode.sql
  • src/synthorg/persistence/postgres/schema.sql
  • src/synthorg/persistence/sqlite/project_repo.py
  • src/synthorg/persistence/sqlite/revisions/20260715000000_project_autonomy_mode.sql
  • src/synthorg/persistence/sqlite/schema.sql
  • src/synthorg/persistence/state.py
  • src/synthorg/security/autonomy/resolver.py
  • src/synthorg/workers/execution_resume.py
  • src/synthorg/workers/execution_service/_agent_engine.py
  • src/synthorg/workers/execution_service/_autonomy.py
  • src/synthorg/workers/runtime_builder.py
  • tests/conformance/persistence/test_project_repository.py
  • tests/unit/api/controllers/test_projects.py
  • tests/unit/core/test_project.py
  • tests/unit/security/autonomy/test_resolver.py
  • tests/unit/workers/test_execution_service.py
  • tests/unit/workers/test_runtime_builder.py
  • web/src/__tests__/helpers/factories.ts
  • web/src/__tests__/pages/ProjectDetailPage.test.tsx
  • web/src/__tests__/pages/ProjectOversightSection.test.tsx
  • web/src/__tests__/stores/projects.test.ts
  • web/src/api/endpoints/projects.ts
  • web/src/api/types/backend-enums.gen.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/openapi.gen.ts
  • web/src/api/types/projects.ts
  • web/src/api/types/websocket/core.ts
  • web/src/api/types/websocket/provider.ts
  • web/src/mocks/handlers/projects.ts
  • web/src/pages/ProjectDetailPage.tsx
  • web/src/pages/projects/ProjectOversightSection.tsx
  • web/src/stores/projects.ts
  • web/src/stores/projects/_state.ts
  • web/src/stores/projects/crud-actions.ts
  • web/src/stores/projects/types.ts
  • web/src/stores/projects/ws-handler.ts

Comment thread docs/guides/security.md
### Set a department-level override

Resolution chain: per-agent > per-department > company default. To set a department-wide override:
Resolution chain: per-agent > per-initiative > per-department > company default. To set a department-wide override:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Qualify the department-clear fallback.

After adding the per-initiative layer, clearing a department override does not always fall directly to the company default: an existing project override still takes precedence. Update the adjacent fallback text to describe the next less-specific configured level.

🤖 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 `@docs/guides/security.md` at line 241, Update the resolution-chain text
adjacent to the department override guidance to include the existing
project-level override as the fallback after clearing a department override,
before the company default. Preserve the documented precedence order and adjust
only the fallback description.

Comment thread src/synthorg/api/controllers/_project_cascade.py
Comment thread web/src/pages/projects/ProjectOversightSection.tsx Outdated
Comment thread web/src/stores/projects/_state.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/synthorg/api/controllers/projects.py (1)

249-253: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Restore expected_version on the request DTO.

ProjectAutonomyModeRequest now defines only mode and confirm, but this handler still reads data.expected_version. With extra="forbid", supplied versions are rejected before the handler; omitted versions reach this line and raise AttributeError, breaking every successful PATCH path.

Proposed fix
 class ProjectAutonomyModeRequest(BaseModel):
     mode: AutonomyLevel | None = Field(...)
     confirm: bool = False
+    expected_version: int | None = Field(default=None, ge=1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/synthorg/api/controllers/projects.py` around lines 249 - 253, Restore the
expected_version field on the ProjectAutonomyModeRequest DTO so the handler’s
data.expected_version access is valid. Make it optional with the appropriate
version type and preserve extra="forbid", allowing omitted values to fall back
to project.version while accepting supplied versions.
♻️ Duplicate comments (1)
src/synthorg/api/controllers/projects.py (1)

225-240: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Resolve department inheritance before guarding the transition.

The fallback skips the documented department layer. If the department resolves to FULL while the company default is gated, clearing an override is misclassified as gated and bypasses the CEO confirmation guard and WARNING audit.

Resolve the effective previous/new modes through the same initiative → department → company machinery used at runtime.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/synthorg/api/controllers/projects.py` around lines 225 - 240, Update the
transition setup in the project mode-change controller to resolve effective
previous and new modes using the same initiative → department → company
inheritance machinery used at runtime, rather than falling back directly to
company_default. Ensure department-level FULL values are reflected before the
CEO confirmation guard and WARNING audit, while preserving explicit override
values and the existing AutonomyModeTransition flow.
🤖 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 `@web/src/stores/projects/crud-actions.ts`:
- Around line 275-278: Update the request construction in the project autonomy
mutation to never create an unguarded payload when current is null. Fetch the
latest project/version before building ProjectAutonomyModeRequest, or fail the
mutation; every successful write must include expected_version while preserving
the existing guarded path.

In `@web/src/stores/projects/ws-handler.ts`:
- Around line 37-47: Update the WebSocket mode-update flow around
applyAutonomyModeChanged to synchronize the project’s version alongside
new_mode. Validate and apply the event’s updated version when available,
including the null-mode path, or refetch the project before updating local
state; do not leave the project with a stale version that causes subsequent
PATCH conflicts.

---

Outside diff comments:
In `@src/synthorg/api/controllers/projects.py`:
- Around line 249-253: Restore the expected_version field on the
ProjectAutonomyModeRequest DTO so the handler’s data.expected_version access is
valid. Make it optional with the appropriate version type and preserve
extra="forbid", allowing omitted values to fall back to project.version while
accepting supplied versions.

---

Duplicate comments:
In `@src/synthorg/api/controllers/projects.py`:
- Around line 225-240: Update the transition setup in the project mode-change
controller to resolve effective previous and new modes using the same initiative
→ department → company inheritance machinery used at runtime, rather than
falling back directly to company_default. Ensure department-level FULL values
are reflected before the CEO confirmation guard and WARNING audit, while
preserving explicit override values and the existing AutonomyModeTransition
flow.
🪄 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 Plus

Run ID: 99e6dd81-909a-46b3-967c-1784f98c163a

📥 Commits

Reviewing files that changed from the base of the PR and between 1b44a01 and eb4950a.

📒 Files selected for processing (16)
  • docs/guides/security.md
  • src/synthorg/api/controllers/_project_autonomy.py
  • src/synthorg/api/controllers/projects.py
  • src/synthorg/workers/execution_service/_autonomy.py
  • tests/conformance/persistence/test_project_repository.py
  • tests/unit/api/controllers/test_project_autonomy.py
  • tests/unit/api/controllers/test_projects.py
  • tests/unit/workers/test_execution_service.py
  • web/src/__tests__/pages/ProjectOversightSection.test.tsx
  • web/src/__tests__/stores/projects.test.ts
  • web/src/api/types/openapi.gen.ts
  • web/src/api/types/websocket/provider.ts
  • web/src/pages/projects/ProjectOversightSection.tsx
  • web/src/stores/projects/_state.ts
  • web/src/stores/projects/crud-actions.ts
  • web/src/stores/projects/ws-handler.ts

Comment thread web/src/stores/projects/crud-actions.ts
Comment thread web/src/stores/projects/ws-handler.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/stores/projects/ws-handler.ts (1)

43-60: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not apply autonomy changes without a valid new_version.

When new_version is missing or malformed, newVersion becomes null, but the handler still updates autonomy_mode while retaining the stale local version. The backend payload requires this revision, and the next guarded PATCH can therefore spuriously return 409.

Drop or refetch the event before applying either a mode change or an override clear when newVersion === null, and add regression coverage for invalid versions.

Suggested guard
   const newVersion = sanitizeWsVersion(payload.new_version)
+  if (newVersion === null) return
+
   if (payload.new_mode === null) {
🤖 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 `@web/src/stores/projects/ws-handler.ts` around lines 43 - 60, Validate
newVersion immediately after sanitizeWsVersion in the autonomy-change handler
and return or trigger the existing refetch path when it is null. Ensure neither
the null override branch nor the sanitized newMode branch calls
applyAutonomyModeChanged without a valid version, and add regression coverage
for missing or malformed new_version values.
🤖 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.

Outside diff comments:
In `@web/src/stores/projects/ws-handler.ts`:
- Around line 43-60: Validate newVersion immediately after sanitizeWsVersion in
the autonomy-change handler and return or trigger the existing refetch path when
it is null. Ensure neither the null override branch nor the sanitized newMode
branch calls applyAutonomyModeChanged without a valid version, and add
regression coverage for missing or malformed new_version values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f99472d6-88dd-4dc3-a388-3b279ecd2559

📥 Commits

Reviewing files that changed from the base of the PR and between eb4950a and 4e96759.

📒 Files selected for processing (6)
  • data/runtime_stats.yaml
  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
  • web/src/__tests__/stores/projects.test.ts
  • web/src/api/types/websocket/provider.ts
  • web/src/stores/projects/ws-handler.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (32)
  • GitHub Check: Dashboard Test (shard 2/4)
  • GitHub Check: Dashboard Type Check
  • GitHub Check: Dashboard Test (shard 3/4)
  • GitHub Check: Dashboard Test (shard 1/4)
  • GitHub Check: Dashboard Test (shard 4/4)
  • GitHub Check: Dashboard Build
  • GitHub Check: Build Backend
  • GitHub Check: CodSpeed Web benchmarks
  • GitHub Check: CodSpeed Python benchmarks
  • GitHub Check: Lighthouse Dashboard
  • GitHub Check: Lighthouse Site
  • GitHub Check: Test Integration (shard 3)
  • GitHub Check: Test Integration (shard 1)
  • GitHub Check: Test Conformance (SQLite)
  • GitHub Check: Test Integration (shard 4)
  • GitHub Check: Test Integration (shard 2)
  • GitHub Check: Test Unit (shard 1)
  • GitHub Check: Test Unit (shard 3)
  • GitHub Check: Dashboard Lint
  • GitHub Check: Dashboard E2E (Playwright)
  • GitHub Check: Test Unit (shard 4)
  • GitHub Check: Test Unit (shard 2)
  • GitHub Check: Test E2E
  • GitHub Check: Gates (pre-commit all-files + parity)
  • GitHub Check: Runtime Stats Freshness Gate
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: Build Preview
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: CLI Test (macos-latest)
  • GitHub Check: pyright (advisory)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (10)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Every convention pull request must ship its enforcement gate.
Commits must use <type>: <description>, branches must use <type>/<slug>, and changes must be squash-merged.

Files:

  • data/runtime_stats.yaml
  • web/src/api/types/websocket/provider.ts
  • src/synthorg/api/controllers/projects.py
  • web/src/__tests__/stores/projects.test.ts
  • src/synthorg/api/ws_payloads/_domain.py
  • web/src/stores/projects/ws-handler.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{ts,tsx}: The dashboard is a pure API consumer: it must not persist domain or app state client-side, must hydrate from backend GETs on mount, and must write every change through the REST API immediately.
Do not use localStorage, sessionStorage, IndexedDB, or zustand persist for domain/app state (including setup-wizard state, theme/appearance, and user/org preferences); those values must live in backend settings and be rehydrated from GET/PUT.
Step/progress UI must be derived from backend state, not from a persisted client flag.
The only sanctioned client storage is non-domain transport/UX data: the auth-token cookie shim and the active CSRF token.
Use createLogger from @/lib/logger instead of bare console.* in app code, and use log.debug(), log.warn(), and log.error() with dynamic or untrusted values passed as separate args or structured objects sanitized via sanitizeArg/sanitizeForLog().
Pages that need to filter, sort, search, or aggregate across an entire dataset must load the full set with paginateAll and page it in the browser with useListPagination using ?{ns}Page / ?{ns}Size URL params.
Sanitize untrusted WebSocket strings with sanitizeWsString() / sanitizeWsEnum<T>(); never use raw casts, and do not use makeEnumParser<T> at a WebSocket boundary.
Import ErrorCode and ErrorCategory from @/api/types/errors, and discriminate on ErrorCode.<NAME> rather than raw integers.
Reuse existing components from web/src/components/ui/ before creating new ones; do not hardcode hex colors, fonts, pixel spacing, Motion durations, BCP 47 locale literals, or currency symbols.
Do not use getXIcon(): LucideIcon factories in JSX; export a <XIcon value={...} /> wrapper in its own file instead, and use useViewportSize() rather than raw window.innerWidth in render.
Follow the strict ESLint/type-safety rules: fix types instead of suppressing them, respect exactOptionalPropertyTypes and noUncheckedIndexedAccess...

Files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
web/src/api/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

Health and readiness callers must treat getLiveness() as always 200, getReadiness() (/readyz) as 200/503 binary, and getHealthDetail() (/health) as the full breakdown; new callers must handle 503 explicitly.

Files:

  • web/src/api/types/websocket/provider.ts
web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/**/*.{js,jsx,ts,tsx}: In the React dashboard, reuse components from web/src/components/ui/ and use design tokens only.
The frontend must be a pure API consumer: do not persist application or domain state in client storage; hydrate through GET requests and write changes through the API.

Files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
**/*.{py,js,jsx,ts,tsx,go}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{py,js,jsx,ts,tsx,go}: Do not add AGPL/GPL (non-LGPL) dependencies; attribute permitted LGPL dependencies in NOTICE.
Never use real vendor names in project code or tests; use approved example provider names, except in documented allowlisted locations.

Files:

  • web/src/api/types/websocket/provider.ts
  • src/synthorg/api/controllers/projects.py
  • web/src/__tests__/stores/projects.test.ts
  • src/synthorg/api/ws_payloads/_domain.py
  • web/src/stores/projects/ws-handler.ts
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Only src/synthorg/persistence/ may import SQLite/PostgreSQL libraries or emit raw SQL.
Use the prescribed configuration precedence: database over environment over code defaults for Cat-1, environment over code defaults for Cat-2, and pure environment configuration for Cat-3 bootstrap secrets. Avoid os.environ.get outside approved startup contexts.
Every restart_required=True or read_only_post_init=True setting must have a per-line justification or be listed in the approved baseline; per-request and per-tick settings must be hot-reloadable.
Keep numeric configuration values in settings/definitions/; only approved numeric literals and annotated module-level Final constants are exceptions.
Each ErrorCode must map to exactly one DomainError subclass, except for documented inheritance aliases and SHAREABLE_CODES fallbacks.
Do not add stubs under src/synthorg/: avoid bare NotImplementedError, empty bodies, stub classes/modules, and stub: sentinel data; implement fully or fail loudly.
Every cost_recording_scope() call must pass purpose=, using a PromptPurposeId or explicit None.
Prompt classes tagging LLM chokepoints with a non-None purpose must expose metadata -> ModelPinMetadata returning pin_for(self._PURPOSE_ID); pins belong in llm/model_pins.py.
Respect the tiered module-size budgets declared by # module-kind: headers.
Use declarative import-layering contracts and preserve architectural boundaries, including the raw-SQL boundary, DTO boundary, and dependency inversion.
Comments must explain why only; do not include reviewer citations, issue back-references, or migration framing.
Keep type-only imports at module level and use TYPE_CHECKING only for genuine cycle breakers.
Use public-function type hints, Google-style docstrings, 88-character lines, and functions shorter than 50 lines.
Domain errors must follow <Domain><Condition>Error and inherit from DomainError, never directly from Exception or ...

Files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Do not use from __future__ import annotations; use the specified Python 3.14 exception syntax.

Files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.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/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
web/src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{test,spec}.{ts,tsx}: Tests must override MSW behavior with server.use(...) and must not vi.mock('@/api/endpoints/*').
Unit tests run under the active-handle tracker and must not leak event-loop resources from web/src/ frames.

Files:

  • web/src/__tests__/stores/projects.test.ts
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/stores/**/*.{ts,tsx}: Store create/update/delete mutations must follow the CRUD pattern: try/catch, success state update plus success toast, failure logging plus error toast plus sentinel return, with optimistic updates restoring previous state on error and using getCrudErrorTitle(err, fallback).
Callers must not wrap store mutation calls in try/catch; the store owns the mutation error UX.
List reads should set error: string | null instead of showing toast errors.
Cursor-paginated list endpoints must use opaque PaginationMeta cursors, store nextCursor and hasMore (no offset arithmetic), early-return when !hasMore || !nextCursor, and derive counts from data.length.

Files:

  • web/src/stores/projects/ws-handler.ts
🧠 Learnings (35)
📚 Learning: 2026-06-11T17:01:48.351Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2321
File: .github/actions/start-postgres/action.yml:100-106
Timestamp: 2026-06-11T17:01:48.351Z
Learning: When using Docker CLI v29.5.3+ with `docker tag`, a digest-qualified reference is valid as the SOURCE but not as the TARGET. Specifically, `docker tag SOURCEsha256:<digest> TARGET:tag` should work, while the error like “refusing to create a tag with a digest reference” applies when the digest reference is used as the TARGET (e.g., `docker tag src imagesha256:<digest>`). A digest-qualified source resolves to a locally available image (typically one you’ve pulled) before tagging it with `TARGET:tag`.

Applied to files:

  • data/runtime_stats.yaml
📚 Learning: 2026-06-25T10:42:32.801Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2473
File: docs/design/self-improvement.md:0-0
Timestamp: 2026-06-25T10:42:32.801Z
Learning: When reviewing documentation or YAML-based assertions around MCP tool counts in Aureliolo/synthorg, treat “domain/published” tool counts and “full-registry” tool counts as intentionally different. The published/domain-modules count under `src/synthorg/meta/mcp/domains/` is 245 tools (245 builder call-sites), and `data/runtime_stats.yaml`’s `mcp_tools` should match 245. By contrast, `build_full_registry().tool_count` is expected to be 246 because the full registry additionally includes the `_demo` regression-guard tool defined in `src/synthorg/_demo/mcp.py` (outside the domain modules). Do not flag mismatches between these two scopes; they are expected by design.

Applied to files:

  • data/runtime_stats.yaml
📚 Learning: 2026-05-28T22:27:09.037Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/auth-sessions.test.ts:8-8
Timestamp: 2026-05-28T22:27:09.037Z
Learning: In the frontend, `SessionInfo` is a local type alias for `SessionResponse` defined only in `web/src/api/types/auth.ts` (exported as `SessionResponse as SessionInfo`). It is not re-exported via the `@/api/types` barrel (which only re-exports `dtos.gen` including `SessionResponse`). Therefore, all code (including React components, stores, and tests) that needs `SessionInfo` must import it from `@/api/types/auth` and not from `@/api/types`. (Import `SessionResponse` from `@/api/types` only when `SessionResponse` is what you need.)

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-05-28T22:27:14.761Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/backups.test.ts:9-9
Timestamp: 2026-05-28T22:27:14.761Z
Learning: In the synthorg web package, follow the established convention for importing DTOs from the domain-specific sub-barrels under `@/api/types/<domain>`, e.g. `import type { BackupInfo } from '`@/api/types/backup`'`. These domain sub-barrels are curated and re-export from generated DTOs (e.g., `./dtos.gen`), so they are not considered “deep reach” imports. Do not recommend changing these imports to the top-level `@/api/types` barrel (e.g., `@/api/types`)—production code and tests consistently use the domain-specific sub-barrel paths (such as `stores/backups.ts`, `AdminBackupsPage.tsx`, and `mocks/handlers/backup.ts`).

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-05-28T22:27:25.293Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/workflows-export.test.ts:7-7
Timestamp: 2026-05-28T22:27:25.293Z
Learning: When reviewing code in this repository, if the change touches or adds types related to workflows, ensure those imports come from the domain-specific curated barrel at `@/api/types/workflows` (e.g., `@/api/types/workflows`), not from the top-level `@/api/types` barrel. Do not recommend switching workflow-related type imports to the top-level barrel; this convention is the established pattern across workflow UI/components, workflow editor store code, related hooks, and workflow-related tests.

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-05-29T15:33:54.576Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2163
File: web/src/pages/providers/provider-form-helpers.ts:1-9
Timestamp: 2026-05-29T15:33:54.576Z
Learning: In the synthorg web package (web/src), import provider-related DTO types (e.g., AuthType, CloudPreset, CreateFromPresetRequest, CreateProviderRequest, ProviderConfig, ProviderPreset, UpdateProviderRequest) from the domain sub-barrel `@/api/types/providers` and not from the top-level `@/api/types` barrel. These types are not re-exported from `@/api/types`; using the top-level barrel will cause compilation errors. Follow the established convention when updating provider-related code and imports.

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-05-29T15:35:11.914Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2163
File: web/src/pages/setup/CompanyStep.tsx:18-18
Timestamp: 2026-05-29T15:35:11.914Z
Learning: In the synthorg web package, when using setup-related DTO types (e.g., `SetupAgentSummary`, `SetupCompanyResponse`), import them from the setup domain sub-barrel `@/api/types/setup` rather than from the top-level `@/api/types`. The setup DTOs are not re-exported from `@/api/types`, so importing from the top-level barrel will fail to compile. Follow the existing domain-sub-barrel convention used elsewhere (e.g., `@/api/types/backup`, `@/api/types/workflows`, `@/api/types/auth`) and do not recommend moving setup-domain type imports to `@/api/types`.

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-05-31T00:00:32.734Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2172
File: web/src/pages/project-brain/BrainEntryList.tsx:12-45
Timestamp: 2026-05-31T00:00:32.734Z
Learning: In the synthorg web package, do not flag React components for ESLint `max-params` violations based on destructured prop fields. ESLint `max-params` counts the number of function parameters (arity), not properties inside a destructured object. For example, `function BrainEntryList({ entries, loading, hasMore, ... }: BrainEntryListProps)` has exactly 1 parameter (the props object) and should not be considered a `max-params: 5` violation, even if the props type/interface contains 10+ fields. Only flag when a function declares 6+ separate parameters.

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-06-13T14:07:55.334Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2356
File: web/src/components/ui/ws-connection-banner.tsx:30-45
Timestamp: 2026-06-13T14:07:55.334Z
Learning: In the synthorg web package, treat leading underscores on function names as an intentional convention for module-local, non-exported helper/utility functions (e.g., `_resolveBannerKind`, `_handleConflict`, `_statusFallback`, `_hasRequiredCredentials`, `_decideRetryWait`, `_shouldKeepRetrying`). Do not flag these or suggest renaming to remove the underscore. This does not conflict with React hook linting rules (e.g., the rule that React hook/sub-hook helpers must start with `use` and must not use leading underscores); only apply that hook-specific guidance to actual hook helpers, not plain utility functions.

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-06-25T14:59:52.946Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2476
File: web/CLAUDE.md:31-34
Timestamp: 2026-06-25T14:59:52.946Z
Learning: For the TypeScript/React web dashboard code under web/src (e.g., dashboard utilities/components), follow the web logging convention: import and use `createLogger` from `@/lib/logger`, and name the resulting logger variable `log`. Do not apply the Python backend logging helper pattern (`get_logger` from `src/synthorg/observability/_logger.py` and its `logger` variable) to web TypeScript files.

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-06-05T10:17:59.769Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2231
File: web/src/pages/org/build-org-tree-types.ts:122-122
Timestamp: 2026-06-05T10:17:59.769Z
Learning: When indexing an exhaustive TypeScript `Record<K, V>` (e.g., `SENIORITY_RANK: Record<SeniorityLevel, number>`) using a value whose parameter/type is the same union key type (e.g., `seniorityOf(level: SeniorityLevel)`), TypeScript already guarantees the key is covered at build time. In this case, do NOT request a runtime `?? fallback` or suggest handling for an `UNKNOWN` key unless the codebase has an explicit/ documented runtime drift or “unrecognized value” contract (like the one handled in `computeCategoryBreakdown` in `web/src/utils/budget.ts`). Also, don’t suggest non-existent keys that are not part of the union type.

Applied to files:

  • web/src/api/types/websocket/provider.ts
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-05-21T22:55:20.496Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2035
File: src/synthorg/meta/toolsmith/models.py:114-114
Timestamp: 2026-05-21T22:55:20.496Z
Learning: In this repo’s “magic number” review standard, the existing gate in `scripts/check_no_magic_numbers.py` intentionally does NOT flag numeric literals used as raw call-site arguments. So, do not flag numeric literals passed as keyword arguments to Pydantic `Field()` (e.g., `Field(ge=0, le=100)` / `Field(ge=1, le=50)`)—this is an established idiom. Only treat numeric literals as “magic numbers” when they occur in the locations the gate checks (module-level assignments and function/method parameter defaults).

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-05-29T08:50:58.380Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2160
File: src/synthorg/persistence/sqlite/escalation_repo.py:370-370
Timestamp: 2026-05-29T08:50:58.380Z
Learning: In this repo, Ruff flake8-unused-arguments (ARG002) already suppresses unused-argument warnings on parameters of methods decorated with `override` (from `typing`). Therefore, if you see `# noqa: ARG002` (or equivalent) on parameters of an `override`-decorated method, treat it as stale/unused and remove it. Do not recommend re-adding `# noqa: ARG002` in these cases, because Ruff will flag the redundant directive (RUF100) and fail the Ruff CI gate.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-09T09:22:47.752Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2283
File: src/synthorg/engine/evolution/config.py:278-280
Timestamp: 2026-06-09T09:22:47.752Z
Learning: This repository uses ruff rule TC006 (`runtime-cast-value`), which requires the quoted string-literal form for the type argument in `cast()` calls (e.g., `cast("object", value)` rather than `cast(object, value)`). During code review, do not suggest removing the quotes from the `cast(<type>, ...)` first argument; the unquoted form will be auto-reverted by ruff on commit, so the quoted form should be treated as lint-compliant.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-28T19:03:11.016Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2513
File: src/synthorg/persistence/secret_backends/env_var.py:39-42
Timestamp: 2026-06-28T19:03:11.016Z
Learning: In this repository’s Python code, when cleaning up `property` or `cached_property` docstrings (especially the `Returns:` section), avoid requesting that you inline an “obvious” literal return value into the docstring if the removed code block only restated the annotated return type. Repository convention is to keep property docstrings as one-line summaries and rely on the type annotation for the return type; don’t duplicate what’s already evident from the immediate `return` statement because it restates WHAT (not WHY) and increases doc-rot risk.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-07-05T11:05:42.525Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2539
File: scripts/check_mcp_capability_gap_documented.py:42-71
Timestamp: 2026-07-05T11:05:42.525Z
Learning: Because this repository targets Python 3.14+ (where PEP 649 deferred annotation evaluation is the default), reviewers should not treat TYPE_CHECKING-only imports as errors just because they’re referenced in live/runtime function annotations in the same module. In particular, if an import guarded by `if TYPE_CHECKING:` (e.g., `from collections.abc import Iterable`) is only needed for annotations, it is safe under PEP 649 since annotations are evaluated lazily on demand rather than eagerly at `def` time. Do flag/consider issues only if the module changes annotation behavior (e.g., uses `from __future__ import annotations`) or if the referenced name is used in non-annotation runtime code.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-05-21T22:55:09.289Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2035
File: src/synthorg/meta/toolsmith/config.py:29-30
Timestamp: 2026-05-21T22:55:09.289Z
Learning: For this repo’s Pydantic configuration idiom, do not treat numeric literals passed directly as arguments to `pydantic.Field(...)` as “magic numbers” during review. This includes call-site usages like `Field(default=0.2, ge=0.0, le=1.0)` (e.g., in config models such as `ToolAuthoringConfig`, `ToolValidationConfig`, `ToolsmithConfig`). Do not request extracting those `Field(...)` numeric arguments into named constants, since the repo’s `scripts/check_no_magic_numbers.py` intentionally excludes call-site `Field(...)` numerics and relies on `Field(...)` as the canonical way to express these constraints/defaults.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-28T17:04:20.222Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2511
File: src/synthorg/engine/quality/decomposers/llm.py:371-373
Timestamp: 2026-06-28T17:04:20.222Z
Learning: When reviewing calls to `cost_recording_scope(...)` in this repository, do not flag missing prompt-class attribution if the call explicitly passes `purpose=None` as an intentional opt-out path under the `check_cost_scope_purpose` gate. This is sanctioned for prompts that are intentionally outside the registered prompt-class inventory. In particular, if the code comments/documentation indicate the cost is charged to the calling evaluator (not to a registered system prompt class)—for example in `LLMCriteriaDecomposer._invoke_provider` (`src/synthorg/engine/quality/decomposers/llm.py`)—treat the lack of prompt-class attribution as expected and do not raise a review issue.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-07-11T21:02:36.875Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2569
File: src/synthorg/tools/sandbox/docker_sandbox_sidecar.py:55-55
Timestamp: 2026-07-11T21:02:36.875Z
Learning: In synthorg Python code review, treat stub/seam patterns as follows: (1) If a normal (non-interface) method body contains `raise NotImplementedError`, flag it—`scripts/check_no_stubs.py` bans these stubs. (2) Do NOT flag an `...` (Ellipsis) body as unsafe when the method is intentionally interface-only and is enforced to be unreachable unless overridden—specifically methods decorated with `abstractmethod` or `overload`, and methods defined on classes that are `Protocol` (i.e., the method is part of a typing interface). In these cases, the `...` body is the supported no-implementation marker and should be considered safe.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-05-30T18:10:10.435Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2171
File: src/synthorg/api/auth/controllers/sessions_mgmt.py:78-79
Timestamp: 2026-05-30T18:10:10.435Z
Learning: When reviewing Python code under src/synthorg/api, do not flag callsites that use `session_store_of(app_state)` as unsafe/bare field dereferences for missing-session-store scenarios. `session_store_of(app_state)` already routes through `require_service(slice.session_store, 'Session Store')`, which raises `ServiceUnavailableError` (HTTP 503) when the session store is not wired (e.g., JWT-only deployments). The existing 503 guard prevents the missing-store from becoming an unsafe access.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-05-31T18:00:32.445Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2180
File: src/synthorg/engine/intervention/models.py:182-203
Timestamp: 2026-05-31T18:00:32.445Z
Learning: In this repository, `NotBlankStr` is a Pydantic `Annotated[str, ...]` type alias (defined in `synthorg/core/types.py`). At runtime, calling `NotBlankStr(value)` acts like an identity/cast to `str(value)` and does not execute the `StringConstraints` or `AfterValidator(...)`. Therefore, during code review, do not treat `NotBlankStr(x)` used inside non-Pydantic model methods as a place that would raise `ValidationError`; it won’t. Similarly, when `tuple[NotBlankStr, ...]` values are involved, `NotBlankStr` erases to `str` at runtime, so membership tests/comparisons can be done with raw `str` values.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-10T12:09:37.293Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2295
File: src/synthorg/project_brain/service.py:77-80
Timestamp: 2026-06-10T12:09:37.293Z
Learning: Do not flag or recommend moving imports out of `if TYPE_CHECKING:` in `src/synthorg` when the imported class is a collaborator type that’s intentionally “concrete-faked” in tests (duck-typed stubs injected into code under constructor/typing annotations). This pattern is used to avoid runtime import side effects where runtime type enforcement (e.g., `typeguard`/`isinstance` checks against the concrete type) would cause the test fakes to be rejected. If the code relies only on annotations for those collaborators and tests provide duck-typed stubs, keep the import under `TYPE_CHECKING` rather than promoting it to a module-level runtime import.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-10T12:09:46.221Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2295
File: src/synthorg/settings/dispatcher.py:43-46
Timestamp: 2026-06-10T12:09:46.221Z
Learning: In this repository’s Python modules, do not treat `if TYPE_CHECKING:` imports as violations of any “hoist to module level” rule when they are deliberately used to support duck-typed test fakes (“concrete-faked collaborators”).

Concretely: if the code includes a comment/docstring indicating that tests drive the module using a duck-typed stub (e.g., “Concrete-faked collaborator: tests drive … with a duck-typed … stub, so a runtime import would make typeguard reject the fake”), then keep that collaborator import/type reference under `if TYPE_CHECKING:` rather than importing it at runtime. The intent is to avoid runtime typeguard validation rejecting the test fake; these guards are intentional and should not be flagged.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-20T14:08:03.848Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2423
File: src/synthorg/api/lifecycle.py:292-292
Timestamp: 2026-06-20T14:08:03.848Z
Learning: When reviewing calls to `provider_credential_catalog_of(app_state)` (from `src/synthorg/integrations/state.py`), treat it as a soft/optional accessor: it returns `None` when the provider credential catalog is not wired and does not raise. Do not flag such uses as potentially raising exceptions or as hard dependencies that would disable functionality if the catalog is absent. (By contrast, `connection_catalog_of(app_state)` is a hard accessor that raises via `require_service`.)

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-28T19:03:23.438Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2513
File: src/synthorg/persistence/secret_backends/sqlite_row_store.py:42-46
Timestamp: 2026-06-28T19:03:23.438Z
Learning: In Aureliolo/synthorg, when reviewing updates to Python `property` or `cached_property` docstrings, keep the docstring as a one-line summary if the removed `Returns:` block only restated the type/value shape already implied by the code.

Do not add back (or request) a fixed literal or value that’s already immediately obvious from the first `return` statement (e.g., if the `return` is `"encrypted_sqlite"`, don’t ask to restate that exact literal in the docstring). Prefer docstrings that explain WHAT and especially WHY/behavior, avoiding duplication that increases doc-rot risk.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-28T19:03:57.476Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2513
File: src/synthorg/persistence/secret_backends/postgres_row_store.py:65-69
Timestamp: 2026-06-28T19:03:57.476Z
Learning: For Python code in this repo using `property` and `cached_property`, ensure the docstring follows the repo’s one-line-summary convention documented in `docs/reference/convention-gates.md`. When the prior/removed docstring `Returns:` section only restated the return *type* (i.e., it repeats a fixed literal value like `Result of type ``NotBlankStr``.`), do not reintroduce that literal-value restatement in the docstring—treat it as WHAT-not-WHY duplication and a potential doc-rot hazard. Prefer describing the purpose/meaning (WHY) of the returned value rather than repeating the type/value wording.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-07-11T21:02:36.144Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2569
File: src/synthorg/integrations/connections/types/gitea.py:40-40
Timestamp: 2026-07-11T21:02:36.144Z
Learning: Follow the repository’s `scripts/check_no_stubs.py` rule: do not use a bare `raise NotImplementedError` in a method body. Ellipsis (`...`) is the mandated convention for interface-only seams—i.e., methods whose bodies are `...` when they are decorated with `abstractmethod`, `overload`, or are members defined inside a `Protocol`. For concrete implementations, raise a typed `DomainError` (not `NotImplementedError`) instead of stubbing.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-07-11T21:03:18.103Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2569
File: src/synthorg/persistence/postgres/backend_migration.py:45-48
Timestamp: 2026-07-11T21:03:18.103Z
Learning: For code under src/synthorg/**/*.py, follow the enforcement in scripts/check_no_stubs.py:
- Do not allow `raise NotImplementedError` anywhere in any function/method body (no exemptions for `abstractmethod` or `overload`).
- A function/method body that is exactly `...` or `pass` is only acceptable if it’s an interface-only declaration: the enclosing function is decorated with `abstractmethod`/`overload`, the enclosing class is a `Protocol`, or the definition appears inside `if TYPE_CHECKING:`.
- Therefore, `abstractmethod` methods must use `...` (or otherwise fail loudly by raising a typed `DomainError`), but must never use `raise NotImplementedError`.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-03T11:43:13.104Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2200
File: tests/unit/engine/artifacts/test_service.py:42-45
Timestamp: 2026-06-03T11:43:13.104Z
Learning: For the D7 protocol method `save_returning_outcome(artifact: Artifact) -> bool` defined in `src/synthorg/persistence/artifact_protocol.py`, any implementation—including fake/stub/test doubles—must use the exact same parameter name `artifact` (i.e., `save_returning_outcome(self, artifact=...)` / `save_returning_outcome(self, artifact: Artifact)`), not `entity`. This name must match for typeguard positional-or-keyword name conformance. Do not suggest renaming the protocol method’s parameter to `entity`.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-09T10:06:53.040Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2283
File: src/synthorg/engine/middleware/coordination_constraints.py:152-152
Timestamp: 2026-06-09T10:06:53.040Z
Learning: Use International/British English spellings throughout the repository (code comments, docstrings, and documentation). British spellings such as "Analyse" (not "Analyze"), "Behaviour" (not "Behavior"), and "Colour" (not "Color") are mandatory and should not be flagged as spelling errors or inconsistencies during code review. This repo’s style is enforced via `vale` (see `CLAUDE.md` → "Regional Defaults (MANDATORY)"). If an American spelling appears, prefer the corresponding British spelling.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-13T08:51:11.124Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2348
File: docs/guides/custom-mcp-server-dev.md:155-161
Timestamp: 2026-06-13T08:51:11.124Z
Learning: When reviewing Aureliolo/synthorg usage of `mcp_descriptor()` (from `src/synthorg/meta/mcp/feature_descriptors.py`), ensure all call sites pass the keyword argument `handlers=...` (type `Callable[[], Mapping[str, object]]`). `mcp_descriptor()` maps this `handlers` value internally to the descriptor’s `handlers_factory` field; `handlers_factory=...` is not a valid keyword and will raise `TypeError: unexpected keyword argument`. Also ensure documentation and code examples do not suggest renaming `handlers` to `handlers_factory`; always show `handlers=`.

Applied to files:

  • src/synthorg/api/controllers/projects.py
  • src/synthorg/api/ws_payloads/_domain.py
📚 Learning: 2026-06-20T14:08:01.947Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2423
File: src/synthorg/api/controllers/meta.py:268-273
Timestamp: 2026-06-20T14:08:01.947Z
Learning: In Aureliolo/synthorg controller code, do not flag an O(N) pre-materialization/performance issue when cursor pagination is implemented using the canonical idiom: `collect_all(lambda limit, offset: repo.list_items(...)) + paginate_cursor(...)` (e.g., in `custom_rules.py`, `meta.py`). Treat this as intentional because `paginate_cursor` requires the fully ordered collection to compute truncation/`has_more`, and repository protocol methods explicitly forbid bespoke `count`/extra methods under ADR-0001 (`IdKeyedRepository` compose-only). Only apply this “do not flag” guidance when the pagination is built from `repo.list_items(...)` via `collect_all` and then passed into `paginate_cursor` as part of cursor-pagination logic for low-cardinality datasets.

Applied to files:

  • src/synthorg/api/controllers/projects.py
📚 Learning: 2026-06-22T15:30:01.837Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2459
File: src/synthorg/api/controllers/risk_overrides.py:37-41
Timestamp: 2026-06-22T15:30:01.837Z
Learning: When reviewing controller helper code in this project, reading the ASGI `request.scope` user (e.g., `request.scope.get("user")` / `request.scope["user"]`) should NOT be treated as untrusted input that requires `parse_typed()` / `check_boundary_typed()`.

In Aureliolo/synthorg, the project’s auth middleware populates `scope["user"]` with an already-constructed `AuthenticatedUser` Pydantic model, not arbitrary external dict data. The correct boundary check is to validate the type, e.g. `isinstance(actor, AuthenticatedUser)` (and raise `UnauthorizedError` when it fails), rather than adding `parse_typed()` around `scope["user"]`.

Applied to files:

  • src/synthorg/api/controllers/projects.py
📚 Learning: 2026-06-22T15:30:20.153Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2459
File: src/synthorg/api/controllers/risk_overrides.py:39-40
Timestamp: 2026-06-22T15:30:20.153Z
Learning: In controller-layer code, do NOT log WARNING/ERROR with context immediately before raising client-facing guard exceptions that are part of normal request handling.

Specifically:
- For actor/auth guard helpers (e.g., `_require_actor`-style helpers) that raise `UnauthorizedError` when no authenticated actor is present, skip the preceding `logger.warning()`/`logger.error()` call and raise directly.
- For controller handlers that raise `NotFoundError` for missing resources (e.g., when a service returns `None`), skip the preceding log and raise directly (4xx “not found” is routine).

Only apply the “log WARNING/ERROR with context before raising” guideline to service-layer failures and state transitions (i.e., unexpected/operational failures), not routine controller authorization/not-found guards. Use the established idiom shown by `src/synthorg/api/controllers/users/org_roles.py::_require_actor` and the pattern in this controller (`risk_overrides.py`).

Applied to files:

  • src/synthorg/api/controllers/projects.py
🔇 Additional comments (5)
src/synthorg/api/controllers/projects.py (1)

6-25: LGTM!

Also applies to: 35-56, 176-281, 319-319

src/synthorg/api/ws_payloads/_domain.py (1)

97-119: LGTM!

web/src/api/types/websocket/provider.ts (1)

3-3: LGTM!

Also applies to: 36-42

web/src/__tests__/stores/projects.test.ts (1)

56-56: LGTM!

Also applies to: 347-475, 477-546

data/runtime_stats.yaml (1)

2-8: LGTM!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@web/src/__tests__/stores/projects.test.ts`:
- Around line 546-566: The test around updateFromWsEvent should cover both
missing and malformed new_version values, not only the missing-field case. Add
an invalid typed new_version scenario and assert that projects[0].version and
selectedProject.version both remain unchanged, alongside the existing
autonomy_mode assertions.

In `@web/src/stores/projects/ws-handler.ts`:
- Around line 22-25: Update the project.autonomy_mode_changed handling around
the patch helper to ignore events when newVersion is not greater than the
current version. Apply this version gate independently to both the project list
row and selectedProject, preserving each existing state update only for newer
WebSocket versions.
🪄 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 Plus

Run ID: 446599bc-0395-455c-a941-987ef3318625

📥 Commits

Reviewing files that changed from the base of the PR and between 4e96759 and dfbdc18.

📒 Files selected for processing (2)
  • web/src/__tests__/stores/projects.test.ts
  • web/src/stores/projects/ws-handler.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (32)
  • GitHub Check: Dashboard Test (shard 1/4)
  • GitHub Check: Dashboard Test (shard 2/4)
  • GitHub Check: Dashboard Test (shard 3/4)
  • GitHub Check: Dashboard Test (shard 4/4)
  • GitHub Check: Dashboard Type Check
  • GitHub Check: Dashboard Build
  • GitHub Check: Build Backend
  • GitHub Check: CodSpeed Python benchmarks
  • GitHub Check: CodSpeed Web benchmarks
  • GitHub Check: Lighthouse Dashboard
  • GitHub Check: Lighthouse Site
  • GitHub Check: Test E2E
  • GitHub Check: Test Integration (shard 3)
  • GitHub Check: Test Integration (shard 4)
  • GitHub Check: Dashboard E2E (Playwright)
  • GitHub Check: Test Unit (shard 4)
  • GitHub Check: Test Integration (shard 2)
  • GitHub Check: Test Unit (shard 2)
  • GitHub Check: Dashboard Lint
  • GitHub Check: Test Unit (shard 3)
  • GitHub Check: Test Unit (shard 1)
  • GitHub Check: Runtime Stats Freshness Gate
  • GitHub Check: Test Integration (shard 1)
  • GitHub Check: Test Conformance (SQLite)
  • GitHub Check: Gates (pre-commit all-files + parity)
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: Build Preview
  • GitHub Check: pyright (advisory)
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: CLI Test (macos-latest)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (6)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{ts,tsx}: The dashboard is a pure API consumer: it must not persist domain or app state client-side, must hydrate from backend GETs on mount, and must write every change through the REST API immediately.
Do not use localStorage, sessionStorage, IndexedDB, or zustand persist for domain/app state (including setup-wizard state, theme/appearance, and user/org preferences); those values must live in backend settings and be rehydrated from GET/PUT.
Step/progress UI must be derived from backend state, not from a persisted client flag.
The only sanctioned client storage is non-domain transport/UX data: the auth-token cookie shim and the active CSRF token.
Use createLogger from @/lib/logger instead of bare console.* in app code, and use log.debug(), log.warn(), and log.error() with dynamic or untrusted values passed as separate args or structured objects sanitized via sanitizeArg/sanitizeForLog().
Pages that need to filter, sort, search, or aggregate across an entire dataset must load the full set with paginateAll and page it in the browser with useListPagination using ?{ns}Page / ?{ns}Size URL params.
Sanitize untrusted WebSocket strings with sanitizeWsString() / sanitizeWsEnum<T>(); never use raw casts, and do not use makeEnumParser<T> at a WebSocket boundary.
Import ErrorCode and ErrorCategory from @/api/types/errors, and discriminate on ErrorCode.<NAME> rather than raw integers.
Reuse existing components from web/src/components/ui/ before creating new ones; do not hardcode hex colors, fonts, pixel spacing, Motion durations, BCP 47 locale literals, or currency symbols.
Do not use getXIcon(): LucideIcon factories in JSX; export a <XIcon value={...} /> wrapper in its own file instead, and use useViewportSize() rather than raw window.innerWidth in render.
Follow the strict ESLint/type-safety rules: fix types instead of suppressing them, respect exactOptionalPropertyTypes and noUncheckedIndexedAccess...

Files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/stores/**/*.{ts,tsx}: Store create/update/delete mutations must follow the CRUD pattern: try/catch, success state update plus success toast, failure logging plus error toast plus sentinel return, with optimistic updates restoring previous state on error and using getCrudErrorTitle(err, fallback).
Callers must not wrap store mutation calls in try/catch; the store owns the mutation error UX.
List reads should set error: string | null instead of showing toast errors.
Cursor-paginated list endpoints must use opaque PaginationMeta cursors, store nextCursor and hasMore (no offset arithmetic), early-return when !hasMore || !nextCursor, and derive counts from data.length.

Files:

  • web/src/stores/projects/ws-handler.ts
web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/**/*.{js,jsx,ts,tsx}: In the React dashboard, reuse components from web/src/components/ui/ and use design tokens only.
The frontend must be a pure API consumer: do not persist application or domain state in client storage; hydrate through GET requests and write changes through the API.

Files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Every convention pull request must ship its enforcement gate.
Commits must use <type>: <description>, branches must use <type>/<slug>, and changes must be squash-merged.

Files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
**/*.{py,js,jsx,ts,tsx,go}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{py,js,jsx,ts,tsx,go}: Do not add AGPL/GPL (non-LGPL) dependencies; attribute permitted LGPL dependencies in NOTICE.
Never use real vendor names in project code or tests; use approved example provider names, except in documented allowlisted locations.

Files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
web/src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{test,spec}.{ts,tsx}: Tests must override MSW behavior with server.use(...) and must not vi.mock('@/api/endpoints/*').
Unit tests run under the active-handle tracker and must not leak event-loop resources from web/src/ frames.

Files:

  • web/src/__tests__/stores/projects.test.ts
🧠 Learnings (9)
📚 Learning: 2026-05-28T22:27:09.037Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/auth-sessions.test.ts:8-8
Timestamp: 2026-05-28T22:27:09.037Z
Learning: In the frontend, `SessionInfo` is a local type alias for `SessionResponse` defined only in `web/src/api/types/auth.ts` (exported as `SessionResponse as SessionInfo`). It is not re-exported via the `@/api/types` barrel (which only re-exports `dtos.gen` including `SessionResponse`). Therefore, all code (including React components, stores, and tests) that needs `SessionInfo` must import it from `@/api/types/auth` and not from `@/api/types`. (Import `SessionResponse` from `@/api/types` only when `SessionResponse` is what you need.)

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-28T22:27:14.761Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/backups.test.ts:9-9
Timestamp: 2026-05-28T22:27:14.761Z
Learning: In the synthorg web package, follow the established convention for importing DTOs from the domain-specific sub-barrels under `@/api/types/<domain>`, e.g. `import type { BackupInfo } from '`@/api/types/backup`'`. These domain sub-barrels are curated and re-export from generated DTOs (e.g., `./dtos.gen`), so they are not considered “deep reach” imports. Do not recommend changing these imports to the top-level `@/api/types` barrel (e.g., `@/api/types`)—production code and tests consistently use the domain-specific sub-barrel paths (such as `stores/backups.ts`, `AdminBackupsPage.tsx`, and `mocks/handlers/backup.ts`).

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-28T22:27:25.293Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2159
File: web/src/__tests__/stores/workflows-export.test.ts:7-7
Timestamp: 2026-05-28T22:27:25.293Z
Learning: When reviewing code in this repository, if the change touches or adds types related to workflows, ensure those imports come from the domain-specific curated barrel at `@/api/types/workflows` (e.g., `@/api/types/workflows`), not from the top-level `@/api/types` barrel. Do not recommend switching workflow-related type imports to the top-level barrel; this convention is the established pattern across workflow UI/components, workflow editor store code, related hooks, and workflow-related tests.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-29T15:33:54.576Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2163
File: web/src/pages/providers/provider-form-helpers.ts:1-9
Timestamp: 2026-05-29T15:33:54.576Z
Learning: In the synthorg web package (web/src), import provider-related DTO types (e.g., AuthType, CloudPreset, CreateFromPresetRequest, CreateProviderRequest, ProviderConfig, ProviderPreset, UpdateProviderRequest) from the domain sub-barrel `@/api/types/providers` and not from the top-level `@/api/types` barrel. These types are not re-exported from `@/api/types`; using the top-level barrel will cause compilation errors. Follow the established convention when updating provider-related code and imports.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-29T15:35:11.914Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2163
File: web/src/pages/setup/CompanyStep.tsx:18-18
Timestamp: 2026-05-29T15:35:11.914Z
Learning: In the synthorg web package, when using setup-related DTO types (e.g., `SetupAgentSummary`, `SetupCompanyResponse`), import them from the setup domain sub-barrel `@/api/types/setup` rather than from the top-level `@/api/types`. The setup DTOs are not re-exported from `@/api/types`, so importing from the top-level barrel will fail to compile. Follow the existing domain-sub-barrel convention used elsewhere (e.g., `@/api/types/backup`, `@/api/types/workflows`, `@/api/types/auth`) and do not recommend moving setup-domain type imports to `@/api/types`.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-05-31T00:00:32.734Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2172
File: web/src/pages/project-brain/BrainEntryList.tsx:12-45
Timestamp: 2026-05-31T00:00:32.734Z
Learning: In the synthorg web package, do not flag React components for ESLint `max-params` violations based on destructured prop fields. ESLint `max-params` counts the number of function parameters (arity), not properties inside a destructured object. For example, `function BrainEntryList({ entries, loading, hasMore, ... }: BrainEntryListProps)` has exactly 1 parameter (the props object) and should not be considered a `max-params: 5` violation, even if the props type/interface contains 10+ fields. Only flag when a function declares 6+ separate parameters.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-06-13T14:07:55.334Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2356
File: web/src/components/ui/ws-connection-banner.tsx:30-45
Timestamp: 2026-06-13T14:07:55.334Z
Learning: In the synthorg web package, treat leading underscores on function names as an intentional convention for module-local, non-exported helper/utility functions (e.g., `_resolveBannerKind`, `_handleConflict`, `_statusFallback`, `_hasRequiredCredentials`, `_decideRetryWait`, `_shouldKeepRetrying`). Do not flag these or suggest renaming to remove the underscore. This does not conflict with React hook linting rules (e.g., the rule that React hook/sub-hook helpers must start with `use` and must not use leading underscores); only apply that hook-specific guidance to actual hook helpers, not plain utility functions.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-06-25T14:59:52.946Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2476
File: web/CLAUDE.md:31-34
Timestamp: 2026-06-25T14:59:52.946Z
Learning: For the TypeScript/React web dashboard code under web/src (e.g., dashboard utilities/components), follow the web logging convention: import and use `createLogger` from `@/lib/logger`, and name the resulting logger variable `log`. Do not apply the Python backend logging helper pattern (`get_logger` from `src/synthorg/observability/_logger.py` and its `logger` variable) to web TypeScript files.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
📚 Learning: 2026-06-05T10:17:59.769Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2231
File: web/src/pages/org/build-org-tree-types.ts:122-122
Timestamp: 2026-06-05T10:17:59.769Z
Learning: When indexing an exhaustive TypeScript `Record<K, V>` (e.g., `SENIORITY_RANK: Record<SeniorityLevel, number>`) using a value whose parameter/type is the same union key type (e.g., `seniorityOf(level: SeniorityLevel)`), TypeScript already guarantees the key is covered at build time. In this case, do NOT request a runtime `?? fallback` or suggest handling for an `UNKNOWN` key unless the codebase has an explicit/ documented runtime drift or “unrecognized value” contract (like the one handled in `computeCategoryBreakdown` in `web/src/utils/budget.ts`). Also, don’t suggest non-existent keys that are not part of the union type.

Applied to files:

  • web/src/stores/projects/ws-handler.ts
  • web/src/__tests__/stores/projects.test.ts
🔇 Additional comments (1)
web/src/stores/projects/ws-handler.ts (1)

36-61: LGTM!

Comment thread web/src/__tests__/stores/projects.test.ts Outdated
Comment thread web/src/stores/projects/ws-handler.ts Outdated
@Aureliolo
Aureliolo temporarily deployed to cloudflare-preview July 15, 2026 09:56 — with GitHub Actions Inactive
@Aureliolo
Aureliolo merged commit 0d8049a into main Jul 15, 2026
109 checks passed
@Aureliolo
Aureliolo deleted the feat/operator-set-modes-gate branch July 15, 2026 10:09
@Aureliolo
Aureliolo temporarily deployed to cloudflare-preview July 15, 2026 10:09 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

prio:medium Should do, but not blocking scope:web Vue 3 dashboard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace agent seniority/promotion/trust with operator-set org modes + a layered auto-gate

1 participant