fix: settings page UX polish -- toggle bug, source badges, form improvements#712
fix: settings page UX polish -- toggle bug, source badges, form improvements#712
Conversation
…vements (#709) Fix advanced toggle not reverting on cancel, normalize dashboard status casing, make department card buttons visible, grey out env-sourced settings, add agent dropdown to department form, use grouped layout for company general tab, hide setup_complete from UI, rename source badges to user-friendly labels, remove unused default_provider setting, and make department head required to align with backend schema. Closes #709 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Backend Department model now allows head=None instead of requiring it. Departments without a head assigned show a warning in the UI card rather than being silently filtered from the Org Chart. The department form keeps the agent dropdown UX but head is no longer required. Pre-reviewed by 6 agents (docs-consistency, frontend-reviewer, conventions-enforcer, test-quality, code-reviewer, issue-verifier). 17 findings addressed across all agents. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughDepartment `head` is now optional (`None`) and hierarchy construction omits inferring team-lead→department-head links for headless departments. The `providers.default_provider` setting and its watcher were removed. `api/setup_complete` was set to advanced and is filtered from the UI. Frontend changes: source badge labels updated, environment-sourced settings render read-only with an explanatory message, hidden settings are excluded from renderers, `SystemStatus` uppercases status, department forms use a nullable `Select` for `head` and show “No head assigned,” and department card action buttons use outlined styling. Tests and constants updated accordingly. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a comprehensive set of user experience and functional improvements across the application, primarily focusing on the settings page and department management. It addresses several UI inconsistencies and bugs, enhances clarity for users regarding setting sources and system status, and refines backend models to support more flexible organizational structures. The changes aim to make the application's configuration and organizational tools more intuitive and robust. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/components/settings/SettingField.vue (1)
152-235:⚠️ Potential issue | 🟠 MajorEnv-sourced settings are still saveable through the JSON format path.
The UI presents env entries as read-only, but
Format JSONcan still mutatelocalValue, andcanSavecurrently allows saving when dirty. This breaks the non-editable contract for env-sourced settings.🔧 Proposed fix
-const canSave = computed(() => isDirty.value && validationError.value === null && !props.saving) +const canSave = computed( + () => !isEnvSourced.value && isDirty.value && validationError.value === null && !props.saving, +) function formatJson() { + if (isEnvSourced.value) return try { const parsed = JSON.parse(localValue.value) localValue.value = JSON.stringify(parsed, null, 2) } catch { // Invalid JSON -- do nothing } }<Button label="Format JSON" text size="small" class="mt-1" + :disabled="saving || isEnvSourced" `@click`="formatJson" />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/settings/SettingField.vue` around lines 152 - 235, The JSON editing path currently allows mutation for env-sourced settings; update the UI and save logic so env-sourced entries are truly read-only: when isEnvSourced is true, disable or set the JSON Textarea (the element bound to localValue under def.type === 'json') and also short-circuit the save guard (canSave) to return false if isEnvSourced, ensuring no save action can run for env-provided keys; locate references to localValue, the JSON Textarea block, and canSave to apply these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/utils/constants.ts`:
- Around line 110-113: HIDDEN_SETTINGS is currently exported as a mutable Set;
change it to export a ReadonlySet backed by an internal constant to prevent
runtime mutation. Create an internal const (e.g., _HIDDEN_SETTINGS or
HIDDEN_SETTINGS_SET) initialized with the strings, then export export const
HIDDEN_SETTINGS: ReadonlySet<string> = _HIDDEN_SETTINGS so consumers get a
read-only view while the module retains the original Set for any internal
checks.
---
Outside diff comments:
In `@web/src/components/settings/SettingField.vue`:
- Around line 152-235: The JSON editing path currently allows mutation for
env-sourced settings; update the UI and save logic so env-sourced entries are
truly read-only: when isEnvSourced is true, disable or set the JSON Textarea
(the element bound to localValue under def.type === 'json') and also
short-circuit the save guard (canSave) to return false if isEnvSourced, ensuring
no save action can run for env-provided keys; locate references to localValue,
the JSON Textarea block, and canSave to apply these changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 385fef30-a92d-47c2-ad70-efeb5b895334
📒 Files selected for processing (20)
src/synthorg/communication/delegation/hierarchy.pysrc/synthorg/core/company.pysrc/synthorg/settings/definitions/api.pysrc/synthorg/settings/definitions/providers.pysrc/synthorg/settings/subscribers/provider_subscriber.pytests/unit/settings/test_provider_subscriber.pyweb/src/__tests__/components/SystemStatus.test.tsweb/src/__tests__/components/settings/SettingField.test.tsweb/src/__tests__/components/settings/SettingGroupRenderer.test.tsweb/src/__tests__/components/settings/SettingSourceBadge.test.tsweb/src/components/company/CompanyDepartmentCard.vueweb/src/components/company/CompanyDepartmentFormDialog.vueweb/src/components/company/CompanyGeneralForm.vueweb/src/components/dashboard/SystemStatus.vueweb/src/components/settings/SettingField.vueweb/src/components/settings/SettingGroupRenderer.vueweb/src/components/settings/SettingSourceBadge.vueweb/src/utils/constants.tsweb/src/views/CompanyPage.vueweb/src/views/SettingsPage.vue
💤 Files with no reviewable changes (2)
- src/synthorg/settings/definitions/providers.py
- tests/unit/settings/test_provider_subscriber.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Sandbox
- GitHub Check: Build Backend
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (7)
web/src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Vue 3 components must use TypeScript with type safety in the dashboard
Files:
web/src/__tests__/components/SystemStatus.test.tsweb/src/components/dashboard/SystemStatus.vueweb/src/views/CompanyPage.vueweb/src/utils/constants.tsweb/src/__tests__/components/settings/SettingGroupRenderer.test.tsweb/src/components/company/CompanyDepartmentCard.vueweb/src/__tests__/components/settings/SettingSourceBadge.test.tsweb/src/components/settings/SettingSourceBadge.vueweb/src/components/settings/SettingField.vueweb/src/components/company/CompanyGeneralForm.vueweb/src/components/settings/SettingGroupRenderer.vueweb/src/views/SettingsPage.vueweb/src/__tests__/components/settings/SettingField.test.tsweb/src/components/company/CompanyDepartmentFormDialog.vue
web/src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for Vue linting in the dashboard and run lint checks via
npm --prefix web run lint
Files:
web/src/__tests__/components/SystemStatus.test.tsweb/src/components/dashboard/SystemStatus.vueweb/src/views/CompanyPage.vueweb/src/utils/constants.tsweb/src/__tests__/components/settings/SettingGroupRenderer.test.tsweb/src/components/company/CompanyDepartmentCard.vueweb/src/__tests__/components/settings/SettingSourceBadge.test.tsweb/src/components/settings/SettingSourceBadge.vueweb/src/components/settings/SettingField.vueweb/src/components/company/CompanyGeneralForm.vueweb/src/components/settings/SettingGroupRenderer.vueweb/src/views/SettingsPage.vueweb/src/__tests__/components/settings/SettingField.test.tsweb/src/components/company/CompanyDepartmentFormDialog.vue
web/src/__tests__/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Use Vitest for Vue component unit tests with fast-check for property-based testing
Files:
web/src/__tests__/components/SystemStatus.test.tsweb/src/__tests__/components/settings/SettingGroupRenderer.test.tsweb/src/__tests__/components/settings/SettingSourceBadge.test.tsweb/src/__tests__/components/settings/SettingField.test.ts
web/**/*.test.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Use fast-check for property-based testing in Vue tests with
fc.assert+fc.property
Files:
web/src/__tests__/components/SystemStatus.test.tsweb/src/__tests__/components/settings/SettingGroupRenderer.test.tsweb/src/__tests__/components/settings/SettingSourceBadge.test.tsweb/src/__tests__/components/settings/SettingField.test.ts
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Nofrom __future__ import annotationsin Python code -- Python 3.14 has PEP 649 native lazy annotations
Useexcept A, B:syntax (no parentheses) for exception handling on Python 3.14 -- enforced by ruff
Line length must be 88 characters -- enforced by ruff
Files:
src/synthorg/core/company.pysrc/synthorg/communication/delegation/hierarchy.pysrc/synthorg/settings/subscribers/provider_subscriber.pysrc/synthorg/settings/definitions/api.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.py: All public functions must have type hints and Google-style docstrings -- enforced by ruff D rules and mypy strict mode
Use immutability patterns: create new objects instead of mutating existing ones. For non-Pydantic collections, usecopy.deepcopy()at construction andMappingProxyTypefor read-only enforcement
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models for runtime state that evolves
Use@computed_fieldinstead of storing redundant fields; useNotBlankStrfor all identifier/name fields instead of manual whitespace validators
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code instead of barecreate_task
Functions must be < 50 lines, files < 800 lines
All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO
Every module with business logic MUST import logger viafrom synthorg.observability import get_loggerthenlogger = get_logger(__name__). Never useimport loggingorprint()in application code
Use event name constants fromsynthorg.observability.events.<domain>modules instead of string literals (e.g.,API_REQUEST_STARTEDfromevents.api)
Always uselogger.info(EVENT, key=value)for structured logging -- never uselogger.info('msg %s', val)format strings
Validate input at system boundaries (user input, external APIs, config files) rather than throughout application code
Handle errors explicitly and never silently swallow them
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples -- use generic names likeexample-provider,example-large-001,test-provider,test-small-001
Usecopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization) for Pydantic models with dict/list fields
Files:
src/synthorg/core/company.pysrc/synthorg/communication/delegation/hierarchy.pysrc/synthorg/settings/subscribers/provider_subscriber.pysrc/synthorg/settings/definitions/api.py
src/synthorg/{tools,core}/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
For non-Pydantic internal collections (registries, BaseTool), use
copy.deepcopy()at construction and wrap withMappingProxyTypefor read-only enforcement
Files:
src/synthorg/core/company.py
🧠 Learnings (3)
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
Applied to files:
web/src/__tests__/components/SystemStatus.test.ts
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
web/src/views/CompanyPage.vueweb/src/components/company/CompanyDepartmentFormDialog.vue
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/settings/**/*.py : Settings package (settings/): runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge (JSON serialization for Pydantic/collections), ConfigResolver (typed accessors), validation, registry, change notifications via message bus, SettingsSubscriber protocol, SettingsChangeDispatcher (polls `#settings` channel, routes to subscribers, restart_required filtering)
Applied to files:
src/synthorg/settings/subscribers/provider_subscriber.py
🧬 Code graph analysis (2)
web/src/__tests__/components/SystemStatus.test.ts (2)
web/src/api/types.ts (1)
HealthStatus(599-605)src/synthorg/api/controllers/health.py (1)
HealthStatus(31-54)
src/synthorg/settings/definitions/api.py (2)
web/src/api/types.ts (1)
SettingLevel(923-923)src/synthorg/settings/enums.py (1)
SettingLevel(39-47)
🔇 Additional comments (25)
src/synthorg/settings/subscribers/provider_subscriber.py (1)
33-36: Docstring now correctly matches runtime behavior.The updated wording accurately reflects that
retry_max_attemptsis advisory-only and only logged when changed, without triggering router rebuild.web/src/views/SettingsPage.vue (3)
41-46: Local toggle buffer is correctly synchronized with store state.This is a solid fix for ToggleSwitch visual desync and keeps UI state aligned with
settingsStore.showAdvanced.
88-90: Warning/cancel branches now correctly reset visual toggle state.Resetting
advancedToggleValuein both paths addresses the “stuck-on” visual behavior when advanced mode is not confirmed.Also applies to: 98-100
203-205: Template event wiring matches the new buffered-toggle flow.Binding
ToggleSwitchto the local ref and handling dialog@cancelcloses the UX gap described in the PR objective.Also applies to: 363-363
web/src/components/dashboard/SystemStatus.vue (1)
25-25: LGTM!The uppercase transformation correctly normalizes status display casing (e.g.,
'ok'→'OK','degraded'→'DEGRADED') as intended by the PR objectives. The conditional logic properly handles thenullcase with "Unreachable".web/src/__tests__/components/SystemStatus.test.ts (1)
29-42: LGTM!Tests correctly updated to assert the new uppercase status behavior (
'OK'and'DEGRADED'), matching the component'stoUpperCase()transformation. The test names and assertions are properly aligned with the implementation.src/synthorg/core/company.py (1)
271-271: LGTM!Making
Department.headoptional withNotBlankStr | Noneis the correct approach — when present, the value must still be non-blank. The docstring attribute description is updated appropriately, and frozen model config is maintained.Also applies to: 281-284
web/src/views/CompanyPage.vue (1)
384-384: LGTM!Passing agent names derived from the reactive
agentscomputed property correctly supplies the dropdown options to the department form dialog. The fallback handling (agentNames ?? []) in the child component ensures safety when agents list is empty.src/synthorg/communication/delegation/hierarchy.py (1)
44-52: LGTM!The truthiness guard on
dept.headcorrectly handles optional department heads. WhenheadisNone, team leads won't have a phantom supervisor relationship established, and the short-circuit evaluation ensures the comparisonteam.lead != dept.headis never reached with aNonevalue.web/src/components/company/CompanyDepartmentCard.vue (2)
22-23: LGTM!The conditional rendering correctly handles the optional head field with a clear amber "No head assigned" fallback message. This aligns with the backend change making
Department.headoptional.
26-43: LGTM!Switching from
texttooutlinedbutton style improves visibility on dark backgrounds while maintaining the existing icon, size, and severity configuration. Both buttons retain theiraria-labelattributes for accessibility.web/src/components/company/CompanyDepartmentFormDialog.vue (4)
19-19: LGTM!The optional
agentNamesprop with safe fallback (agentNames ?? []on line 156) correctly handles the case when no agent list is provided.
138-140: LGTM!Adding the required marker asterisk to the Name field label is consistent with the
canSavevalidation logic that requires a non-empty name.
193-195: LGTM!The helper text under each JSON accordion section provides clear guidance on the expected data structure, improving form usability.
Also applies to: 202-204, 211-213
153-161: Test PrimeVue Selecteditablebehavior for edge cases.The
editableprop correctly allows users to type custom agent names beyond the dropdown list. Verify these scenarios work correctly:
- User types a name, clears the input, then selects from the dropdown
- User edits an existing department where the current head is not present in the
agentNameslistEnsure the model binding handles these cases without losing or corrupting the selected value.
web/src/components/settings/SettingSourceBadge.vue (1)
10-12: Label mapping update is correct and type-safe.
db → "Custom"andyaml → "Config File"cleanly implement the UX rename without widening source types.web/src/__tests__/components/settings/SettingSourceBadge.test.ts (1)
15-17: Test expectations were updated correctly for renamed badges.This keeps assertions aligned with the new
db/yamldisplay labels.src/synthorg/settings/definitions/api.py (1)
171-171:setup_completeadvanced-level classification is correctly applied.This aligns backend metadata with UI filtering behavior for internal setup state.
web/src/__tests__/components/settings/SettingGroupRenderer.test.ts (1)
216-232: Hidden-setting regression test is well-targeted.This directly protects the
api/setup_completefiltering path when advanced mode is enabled.web/src/__tests__/components/settings/SettingField.test.ts (2)
131-131: Source-label expectation update is correct.The test now matches the renamed
"Config File"badge text.
395-415: Good coverage for environment-sourced read-only UX.These cases validate both disabled input behavior and conditional env messaging.
web/src/components/company/CompanyGeneralForm.vue (1)
3-3: Renderer refactor is a solid improvement.Using
SettingGroupRendererhere centralizes filtering/layout behavior and keeps event forwarding consistent.Also applies to: 32-42
web/src/components/settings/SettingGroupRenderer.vue (3)
4-4: Good central import for hidden-setting policy.Pulling
HIDDEN_SETTINGSfrom shared constants keeps this behavior consistent across components.
19-22:isHiddenhelper is clean and correctly scoped.Using the fully-qualified
namespace/keystring here is a solid way to avoid key collisions.
24-33: Hidden-entry filtering is applied consistently to both sections.Excluding hidden entries in both
basicEntriesandadvancedEntriescloses the UI leak for system-managed settings.
There was a problem hiding this comment.
Code Review
This pull request introduces a variety of UX improvements and bug fixes across the settings and company management pages. Key changes include making department heads optional and improving the form for editing them, renaming source badges for clarity, hiding internal settings from the UI, and fixing a visual bug with the 'Advanced' toggle. The code quality is high, and the changes are well-implemented with corresponding test updates. I have one suggestion to improve data integrity in the department form by restricting the department head selection to existing agents.
| <Select | ||
| input-id="dept-head" | ||
| v-model="head" | ||
| :options="agentNames ?? []" | ||
| class="w-full" | ||
| placeholder="e.g. agent-cto-001" | ||
| editable | ||
| show-clear | ||
| placeholder="Select or type agent name" | ||
| /> |
There was a problem hiding this comment.
Using an editable Select for the department head introduces a risk of user error, such as typos, which could lead to assigning a non-existent agent. This would be silently accepted by the backend but would cause the department to not have a functional head in the organizational hierarchy. To improve data integrity, consider removing the editable prop to enforce that the department head must be an existing agent from the dropdown.
<Select
input-id="dept-head"
v-model="head"
:options="agentNames ?? []"
class="w-full"
show-clear
placeholder="Select an agent"
/>
…mini Tests: add hierarchy test for headless departments, Department head=None model tests, Company with headless department test. Refactor subscriber tests to use shared helper. Fix saveBtn existence assertions in frontend. Bugs: block env-sourced settings from save via canSave guard and Format JSON button. Add missing @dirty handler on CompanyGeneralForm. Remove editable prop from dept head Select to prevent typos. Docs: update Department.head to optional in organization.md, entity diagram in index.md, and HIDDEN_SETTINGS concept in operations.md. Add missing autonomy_level and approval_timeout to docstrings. Code quality: remove redundant set() in hierarchy, add namespace guard in provider subscriber, ReadonlySet for HIDDEN_SETTINGS, security warning for auth_exclude_paths, update FakeDepartment type. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/components/company/CompanyDepartmentFormDialog.vue (1)
31-31:⚠️ Potential issue | 🟡 MinorPotential runtime error when clearing the head Select.
PrimeVue's
Selectwithshow-clearsets the model value tonullwhen cleared, butheadis initialized as an empty string andhandleSavecallshead.value.trim()on line 119. Ifhead.valueisnull, this will throw a TypeError.🛠️ Proposed fix
const head = ref('')And update the save logic to handle null:
- if (head.value.trim()) dept.head = head.value.trim() + if (head.value?.trim()) dept.head = head.value.trim()Alternatively, coerce null to empty string in the watch that resets form state:
- head.value = props.department.head ?? '' + head.value = props.department?.head ?? ''The simplest fix is using optional chaining on line 119.
Also applies to: 119-119, 153-160
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/company/CompanyDepartmentFormDialog.vue` at line 31, The Select's show-clear can set head to null but head is initialized as an empty string and handleSave calls head.value.trim() (function handleSave) which will throw if head.value is null; update the form handling so head can be null-safe — either initialize head as ref(null) or change handleSave to use optional chaining/coercion (e.g., head.value?.trim() ?? '' ) before using the value; also apply the same null-safe access in the reset/populate logic that touches head (the watch/resetForm code paths around the save/reset logic) so clearing the Select won't cause a TypeError.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/unit/settings/test_provider_subscriber.py`:
- Around line 99-103: The test test_retry_max_attempts_change_is_noop is passing
a misleading get_return_value="5" to the helper _make_subscriber even though
retry_max_attempts does not trigger a rebuild (so settings_service.get() is
never invoked); remove the get_return_value argument (or pass None) from the
_make_subscriber call in this test, or add a short comment next to the call
clarifying the return value is irrelevant for this no-op test, and keep the rest
of the test (asserting state.model_router is old_router) unchanged.
---
Outside diff comments:
In `@web/src/components/company/CompanyDepartmentFormDialog.vue`:
- Line 31: The Select's show-clear can set head to null but head is initialized
as an empty string and handleSave calls head.value.trim() (function handleSave)
which will throw if head.value is null; update the form handling so head can be
null-safe — either initialize head as ref(null) or change handleSave to use
optional chaining/coercion (e.g., head.value?.trim() ?? '' ) before using the
value; also apply the same null-safe access in the reset/populate logic that
touches head (the watch/resetForm code paths around the save/reset logic) so
clearing the Select won't cause a TypeError.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 302337bc-40bd-4e5c-88fc-d92bf8873c0c
📒 Files selected for processing (15)
docs/design/index.mddocs/design/operations.mddocs/design/organization.mdsrc/synthorg/communication/delegation/hierarchy.pysrc/synthorg/core/company.pysrc/synthorg/settings/subscribers/provider_subscriber.pytests/unit/communication/delegation/test_hierarchy.pytests/unit/core/test_company.pytests/unit/settings/conftest.pytests/unit/settings/test_provider_subscriber.pyweb/src/__tests__/components/settings/SettingField.test.tsweb/src/components/company/CompanyDepartmentFormDialog.vueweb/src/components/settings/SettingField.vueweb/src/utils/constants.tsweb/src/views/CompanyPage.vue
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Backend
- GitHub Check: Build Web
- GitHub Check: Build Sandbox
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Nofrom __future__ import annotationsin Python code -- Python 3.14 has PEP 649 native lazy annotations
Useexcept A, B:syntax (no parentheses) for exception handling on Python 3.14 -- enforced by ruff
Line length must be 88 characters -- enforced by ruff
Files:
tests/unit/core/test_company.pysrc/synthorg/settings/subscribers/provider_subscriber.pytests/unit/settings/conftest.pysrc/synthorg/communication/delegation/hierarchy.pytests/unit/communication/delegation/test_hierarchy.pytests/unit/settings/test_provider_subscriber.pysrc/synthorg/core/company.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
tests/**/*.py: Use@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slowmarkers for tests
Use Hypothesis for property-based testing in Python with@given+@settingsdecorators. HYPOTHESIS_PROFILE env var controls examples (ci=50, dev=1000)
Never skip, dismiss, or ignore flaky tests -- always fix them fully. For timing-sensitive tests, mocktime.monotonic()andasyncio.sleep()instead of widening margins. Useasyncio.Event().wait()for indefinite blocking instead ofasyncio.sleep(large_number)
Prefer@pytest.mark.parametrizefor testing similar cases instead of writing multiple test functions
Files:
tests/unit/core/test_company.pytests/unit/settings/conftest.pytests/unit/communication/delegation/test_hierarchy.pytests/unit/settings/test_provider_subscriber.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.py: All public functions must have type hints and Google-style docstrings -- enforced by ruff D rules and mypy strict mode
Use immutability patterns: create new objects instead of mutating existing ones. For non-Pydantic collections, usecopy.deepcopy()at construction andMappingProxyTypefor read-only enforcement
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models for runtime state that evolves
Use@computed_fieldinstead of storing redundant fields; useNotBlankStrfor all identifier/name fields instead of manual whitespace validators
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code instead of barecreate_task
Functions must be < 50 lines, files < 800 lines
All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO
Every module with business logic MUST import logger viafrom synthorg.observability import get_loggerthenlogger = get_logger(__name__). Never useimport loggingorprint()in application code
Use event name constants fromsynthorg.observability.events.<domain>modules instead of string literals (e.g.,API_REQUEST_STARTEDfromevents.api)
Always uselogger.info(EVENT, key=value)for structured logging -- never uselogger.info('msg %s', val)format strings
Validate input at system boundaries (user input, external APIs, config files) rather than throughout application code
Handle errors explicitly and never silently swallow them
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples -- use generic names likeexample-provider,example-large-001,test-provider,test-small-001
Usecopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization) for Pydantic models with dict/list fields
Files:
src/synthorg/settings/subscribers/provider_subscriber.pysrc/synthorg/communication/delegation/hierarchy.pysrc/synthorg/core/company.py
web/src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Vue 3 components must use TypeScript with type safety in the dashboard
Files:
web/src/views/CompanyPage.vueweb/src/utils/constants.tsweb/src/components/company/CompanyDepartmentFormDialog.vueweb/src/__tests__/components/settings/SettingField.test.tsweb/src/components/settings/SettingField.vue
web/src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for Vue linting in the dashboard and run lint checks via
npm --prefix web run lint
Files:
web/src/views/CompanyPage.vueweb/src/utils/constants.tsweb/src/components/company/CompanyDepartmentFormDialog.vueweb/src/__tests__/components/settings/SettingField.test.tsweb/src/components/settings/SettingField.vue
web/src/__tests__/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Use Vitest for Vue component unit tests with fast-check for property-based testing
Files:
web/src/__tests__/components/settings/SettingField.test.ts
web/**/*.test.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Use fast-check for property-based testing in Vue tests with
fc.assert+fc.property
Files:
web/src/__tests__/components/settings/SettingField.test.ts
src/synthorg/{tools,core}/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
For non-Pydantic internal collections (registries, BaseTool), use
copy.deepcopy()at construction and wrap withMappingProxyTypefor read-only enforcement
Files:
src/synthorg/core/company.py
🧠 Learnings (14)
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)
Applied to files:
docs/design/index.md
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/hr/**/*.py : HR engine must provide: hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, trend detection), promotion/demotion
Applied to files:
docs/design/index.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/settings/**/*.py : Settings package (settings/): runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge (JSON serialization for Pydantic/collections), ConfigResolver (typed accessors), validation, registry, change notifications via message bus, SettingsSubscriber protocol, SettingsChangeDispatcher (polls `#settings` channel, routes to subscribers, restart_required filtering)
Applied to files:
src/synthorg/settings/subscribers/provider_subscriber.pydocs/design/operations.md
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/providers/**/*.py : Providers: LLM provider abstraction (LiteLLM adapter), auth types (api_key/oauth/custom_header/none), presets (PROVIDER_PRESETS), runtime CRUD (ProviderManagementService with asyncio.Lock serialization), hot-reload via AppState swap.
Applied to files:
src/synthorg/settings/subscribers/provider_subscriber.pydocs/design/operations.md
📚 Learning: 2026-03-16T19:13:36.562Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:13:36.562Z
Learning: Applies to src/synthorg/providers/**/*.py : RetryConfig and RateLimiterConfig are set per-provider in ProviderConfig.
Applied to files:
src/synthorg/settings/subscribers/provider_subscriber.py
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
web/src/views/CompanyPage.vueweb/src/components/company/CompanyDepartmentFormDialog.vue
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Settings: Runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge, ConfigResolver (typed composed reads for controllers), validation, registry, change notifications via message bus. Per-namespace setting definitions in definitions/ submodule (api, company, providers, memory, budget, security, coordination, observability, backup).
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/settings/**/*.py : Settings use runtime-editable persistence with precedence: DB > env > YAML > code defaults. 8 namespaces with Fernet encryption for sensitive values.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.
Applied to files:
docs/design/operations.md
🧬 Code graph analysis (3)
tests/unit/core/test_company.py (1)
src/synthorg/core/company.py (2)
Department(262-338)Company(420-503)
tests/unit/communication/delegation/test_hierarchy.py (2)
src/synthorg/core/company.py (2)
Department(262-338)Team(228-259)src/synthorg/communication/delegation/hierarchy.py (2)
HierarchyResolver(16-282)get_supervisor(141-150)
src/synthorg/core/company.py (1)
src/synthorg/hr/full_snapshot_strategy.py (1)
name(65-67)
🔇 Additional comments (28)
docs/design/index.md (1)
146-146: LGTM!The Mermaid diagram correctly reflects the optional nature of
Department.headusing a dashed arrow and the "(Agent, optional)" label, aligning with the model change insrc/synthorg/core/company.py.docs/design/organization.md (1)
107-109: LGTM!The documentation accurately describes the optional
headfield behavior, including the default value (None) and the impact on hierarchy resolution. This aligns with the implementation inhierarchy.pyand the model definition incompany.py.tests/unit/core/test_company.py (2)
138-142: LGTM!Good test coverage for the new optional
headfield. The test verifies both the defaultNonevalue and confirmsbudget_percentstill defaults correctly.
372-376: LGTM!Properly validates that
Companyaccepts departments withhead=None, ensuring the model integration works correctly for headless departments.tests/unit/settings/conftest.py (1)
46-51: LGTM!The
FakeDepartmentfixture correctly mirrors the realDepartmentmodel's optionalheadfield type (str | None). The default value"lead"preserves backward compatibility with existing tests.web/src/views/CompanyPage.vue (3)
250-256: LGTM!The
handleDirtyfunction properly handles dirty state tracking by conditionally callingsetDirtyorclearDirtyon the settings store. The payload is well-typed with all necessary fields.
318-318: LGTM!The
@dirtyevent listener is correctly wired tohandleDirty, enabling dirty state propagation fromCompanyGeneralForm.
393-393: LGTM!Passing
:agent-namesto the department form dialog enables the agent dropdown forDepartment.headselection, addressing the PR objective to replace the raw text input.src/synthorg/communication/delegation/hierarchy.py (2)
45-53: LGTM!The conditional logic correctly guards the team-lead-to-department-head relationship creation by checking
dept.headtruthiness first. This properly skips headless departments while maintaining the existing self-cycle and prior-assignment guards.
25-25: LGTM!The docstring accurately documents the new behavior: the team-lead-to-head link is skipped when
headisNone.docs/design/operations.md (1)
1142-1142: LGTM!The documentation accurately describes the new settings UI behaviors:
HIDDEN_SETTINGSfiltering for system-managed settings likeapi/setup_complete, and read-only display with warning messages for environment-sourced settings.tests/unit/communication/delegation/test_hierarchy.py (2)
85-96: LGTM!Excellent test coverage for the headless department scenario. The test correctly verifies that:
- Team leads in headless departments have no supervisor (
get_supervisorreturnsNone)- Team members still report to their team lead regardless of department head status
98-113: LGTM!Good test for the coexistence scenario. This validates that headed and headless departments work correctly together, ensuring the conditional logic in
HierarchyResolver.__init__doesn't inadvertently affect other departments.web/src/components/company/CompanyDepartmentFormDialog.vue (2)
192-212: LGTM!The helper text additions for the JSON accordion sections improve discoverability and align with the PR objective to add JSON help/examples and contextual hints.
138-160: LGTM!The required asterisk on the Name field and the agent dropdown for department head improve form clarity. The
input-idprop is correctly used for PrimeVue Select.web/src/utils/constants.ts (1)
110-119: LGTM!The implementation correctly uses
ReadonlySet<string>backed by internal const arrays, addressing the previous review feedback about preventing accidental runtime mutation.web/src/__tests__/components/settings/SettingField.test.ts (3)
127-132: LGTM!The assertion update from "YAML" to "Config File" correctly reflects the source badge label change in the implementation.
240-246: LGTM!The strengthened button assertions with explicit
expect(...).toBeDefined()before non-null assertion!.trigger('click')improve test reliability and provide clearer failure messages.Also applies to: 254-259, 389-394
396-418: LGTM!Good test coverage for the new env-sourced settings behavior:
- Verifies input is disabled when
source: 'env'- Verifies environment variable message is shown
- Verifies message is not shown for non-env sources
web/src/components/settings/SettingField.vue (3)
107-120: LGTM!The
isEnvSourcedandisSecuritySensitivecomputed properties are well-implemented. ThecanSaveguard correctly prevents saving env-sourced settings. AlthoughisEnvSourcedis referenced incanSavebefore its declaration, Vue's computed properties are lazily evaluated, so this works correctly.
160-165: LGTM!The warning messages for security-sensitive and env-sourced settings provide clear guidance to users. The amber color for env-sourced and red for security-sensitive appropriately convey the severity of each concern.
230-237: LGTM!The enum Select placeholder now shows the definition default when available, addressing the PR objective to show the effective/default value when the resolved value is empty.
src/synthorg/core/company.py (2)
271-288: LGTM!Making
Department.headoptional withdefault=Nonecorrectly implements the PR objective to support headless departments. The docstring accurately describes that hierarchy resolution skips the team-lead-to-head link whenheadisNone.
341-361: LGTM!The
approval_timeoutfield addition withdefault_factory=WaitForeverConfigprovides a sensible default timeout policy. The docstring is properly updated to document the new attribute.src/synthorg/settings/subscribers/provider_subscriber.py (2)
82-91: LGTM! Correct namespace check added.The condition now properly validates both
namespace == "providers"andkey == "routing_strategy"before triggering a rebuild. This prevents accidental rebuilds if another namespace uses the same key name.
119-120: The bare-comma exception syntax is correct for Python 3.14.PEP 758 explicitly allows
except A, B:syntax (without parentheses) for catching multiple exceptions in Python 3.14. Since your code does not useas nameto bind the exception, the bare-comma syntax is valid and required per the coding guidelines.tests/unit/settings/test_provider_subscriber.py (2)
40-56: Good refactor centralizing mock setup.The
get_return_valueparameter and conditional mock setup reduces test boilerplate while preserving flexibility for custom mock configurations.
81-97: LGTM! Tests properly verify router swap and failure semantics.The routing strategy change test verifies the router is replaced, and the failure test correctly asserts that the old router remains in place when
UnknownStrategyErroris raised.
- CompanyDepartmentFormDialog: coerce head.value via ?? '' before .trim() to prevent TypeError when PrimeVue Select show-clear sets value to null - test_provider_subscriber: remove irrelevant get_return_value for advisory-only noop test (svc.get() is never called) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/components/company/CompanyDepartmentFormDialog.vue (1)
31-31:⚠️ Potential issue | 🟡 MinorType mismatch:
headref can receivenullfrom PrimeVue Select.The
headref is implicitly typed asRef<string>, but the Select withshow-clear(line 160) sets the model tonullwhen cleared. While the defensive handling at lines 119-121 correctly coerces the value, the ref declaration should reflect the actual runtime type.🔧 Proposed fix
// Form state const name = ref('') -const head = ref('') +const head = ref<string | null>('') const budgetPercent = ref<number | null>(null)This also makes line 119's null coercion self-documenting via the type system.
As per coding guidelines: "Vue 3 components must use TypeScript with type safety in the dashboard".
Also applies to: 119-121
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/company/CompanyDepartmentFormDialog.vue` at line 31, The ref "head" is typed as Ref<string> but PrimeVue Select (with show-clear) can set it to null; change its declaration to allow null (e.g., make head a ref<string | null>) and update any places that dereference it (including the existing null-coercion logic around the priorHead handling) so the type system reflects that head may be null; locate the symbol "head" and the null-coercion code around the previousHead/handleSubmit logic to ensure types compile and no unsafe assumptions remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@web/src/components/company/CompanyDepartmentFormDialog.vue`:
- Line 31: The ref "head" is typed as Ref<string> but PrimeVue Select (with
show-clear) can set it to null; change its declaration to allow null (e.g., make
head a ref<string | null>) and update any places that dereference it (including
the existing null-coercion logic around the priorHead handling) so the type
system reflects that head may be null; locate the symbol "head" and the
null-coercion code around the previousHead/handleSubmit logic to ensure types
compile and no unsafe assumptions remain.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3e706921-811b-4877-a267-6aeb2834719a
📒 Files selected for processing (2)
tests/unit/settings/test_provider_subscriber.pyweb/src/components/company/CompanyDepartmentFormDialog.vue
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Backend
- GitHub Check: Build Sandbox
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
web/src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Vue 3 components must use TypeScript with type safety in the dashboard
Files:
web/src/components/company/CompanyDepartmentFormDialog.vue
web/src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for Vue linting in the dashboard and run lint checks via
npm --prefix web run lint
Files:
web/src/components/company/CompanyDepartmentFormDialog.vue
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Nofrom __future__ import annotationsin Python code -- Python 3.14 has PEP 649 native lazy annotations
Useexcept A, B:syntax (no parentheses) for exception handling on Python 3.14 -- enforced by ruff
Line length must be 88 characters -- enforced by ruff
Files:
tests/unit/settings/test_provider_subscriber.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
tests/**/*.py: Use@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slowmarkers for tests
Use Hypothesis for property-based testing in Python with@given+@settingsdecorators. HYPOTHESIS_PROFILE env var controls examples (ci=50, dev=1000)
Never skip, dismiss, or ignore flaky tests -- always fix them fully. For timing-sensitive tests, mocktime.monotonic()andasyncio.sleep()instead of widening margins. Useasyncio.Event().wait()for indefinite blocking instead ofasyncio.sleep(large_number)
Prefer@pytest.mark.parametrizefor testing similar cases instead of writing multiple test functions
Files:
tests/unit/settings/test_provider_subscriber.py
🧠 Learnings (1)
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
web/src/components/company/CompanyDepartmentFormDialog.vue
🧬 Code graph analysis (1)
tests/unit/settings/test_provider_subscriber.py (1)
src/synthorg/settings/subscribers/provider_subscriber.py (2)
ProviderSettingsSubscriber(27-129)on_settings_changed(68-91)
🔇 Additional comments (8)
tests/unit/settings/test_provider_subscriber.py (4)
40-56: LGTM!The enhanced
_make_subscriber()helper cleanly separates two use cases: default mock setup viaget_return_valueparameter, and custom mock injection viasettings_serviceparameter. The conditional on line 49 correctly preserves any pre-configured behavior (likeside_effect) when a custom mock is passed.
81-85: LGTM!Clean simplification leveraging the helper's defaults. The test correctly verifies that a routing strategy change triggers a router rebuild.
99-104: LGTM!The explanatory comment on line 100 clearly documents that advisory keys never invoke
svc.get(), making theget_return_valueparameter irrelevant for this test. This addresses the previous review feedback.
106-114: LGTM!The test correctly demonstrates that when
SettingsService.get()fails, the existing router is preserved. The custom mock withside_effectis properly respected by the helper's conditional logic.web/src/components/company/CompanyDepartmentFormDialog.vue (4)
15-20: LGTM!The new
agentNamesprop is properly typed as optional and safely consumed with nullish coalescing at line 158.
140-142: LGTM!The required asterisk correctly reflects the validation logic in
canSave.
152-162: LGTM!The Select component is correctly configured with proper accessibility (
input-id), safe options handling, and clear UX withshow-clearand placeholder text.
194-214: LGTM!The helper text provides useful guidance for each JSON section with consistent styling. This improves the form's usability significantly.
PrimeVue Select with show-clear sets the model value to null when cleared. The runtime null-coercion was already in place; this aligns the TypeScript type so the compiler reflects reality. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/components/company/CompanyDepartmentFormDialog.vue`:
- Line 31: Normalize the head reactive state to use null instead of an empty
string: change the initial ref declaration of head to ref<string | null>(null)
and update any places that reset or clear head (e.g., the form reset/close logic
and any handlers that set head back to an unselected state) to assign null
rather than ''. Ensure all usages and bindings (Select components) expect string
| null so the unselected sentinel is consistently null across
CompanyDepartmentFormDialog.vue.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 5b7de968-aa41-4ccb-af0b-779206ac15ad
📒 Files selected for processing (1)
web/src/components/company/CompanyDepartmentFormDialog.vue
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build Web
- GitHub Check: Build Sandbox
- GitHub Check: Build Backend
- GitHub Check: Test (Python 3.14)
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
web/src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Vue 3 components must use TypeScript with type safety in the dashboard
Files:
web/src/components/company/CompanyDepartmentFormDialog.vue
web/src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for Vue linting in the dashboard and run lint checks via
npm --prefix web run lint
Files:
web/src/components/company/CompanyDepartmentFormDialog.vue
🧠 Learnings (1)
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
web/src/components/company/CompanyDepartmentFormDialog.vue
🔇 Additional comments (3)
web/src/components/company/CompanyDepartmentFormDialog.vue (3)
119-121: Good null-safe save path for optional head.Coercing
headbefore trim and only persisting non-empty values is a solid way to keepdept.headoptional without leaking empty strings.
19-20: Good constraint of head input to selectable agent names.Moving from free-text entry to a constrained selection reduces invalid values and better matches the optional-head workflow.
Also applies to: 152-162
140-142: UX copy improvements are clear and helpful.The required marker and JSON panel helper text improve form discoverability and reduce ambiguity for expected payload shapes.
Also applies to: 194-196, 203-205, 212-214
Use null consistently as the unselected sentinel for the head ref, matching budgetPercent and autonomyLevel. PrimeVue Select with show-clear produces null on clear, and the backend Department.head is NotBlankStr | None -- null is the correct unselected value. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/components/company/CompanyDepartmentFormDialog.vue (1)
111-118:⚠️ Potential issue | 🟡 MinorApply consistent null-to-undefined conversion for optional
autonomy_levelfield.Line 114 assigns
autonomyLevel.valuedirectly todept.autonomy_level. WhileDepartmentEntry.autonomy_levelacceptsnull, apply the same null-coalescing pattern used forbudget_percent(line 113) for consistency:- autonomy_level: autonomyLevel.value, + autonomy_level: autonomyLevel.value ?? undefined,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/company/CompanyDepartmentFormDialog.vue` around lines 111 - 118, The dept object assigns autonomy_level directly from autonomyLevel.value; update this to mirror the budget_percent pattern by converting null to undefined (i.e., set autonomy_level using the null-coalescing pattern like autonomyLevel.value ?? undefined) so DepartmentEntry.autonomy_level is consistently normalized; locate the object literal used to build dept in CompanyDepartmentFormDialog.vue and change the autonomy_level assignment accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@web/src/components/company/CompanyDepartmentFormDialog.vue`:
- Around line 111-118: The dept object assigns autonomy_level directly from
autonomyLevel.value; update this to mirror the budget_percent pattern by
converting null to undefined (i.e., set autonomy_level using the null-coalescing
pattern like autonomyLevel.value ?? undefined) so DepartmentEntry.autonomy_level
is consistently normalized; locate the object literal used to build dept in
CompanyDepartmentFormDialog.vue and change the autonomy_level assignment
accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7cba34ce-995e-4939-8aa7-c9ee635bc79e
📒 Files selected for processing (1)
web/src/components/company/CompanyDepartmentFormDialog.vue
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build Backend
- GitHub Check: Test (Python 3.14)
🧰 Additional context used
📓 Path-based instructions (2)
web/src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Vue 3 components must use TypeScript with type safety in the dashboard
Files:
web/src/components/company/CompanyDepartmentFormDialog.vue
web/src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for Vue linting in the dashboard and run lint checks via
npm --prefix web run lint
Files:
web/src/components/company/CompanyDepartmentFormDialog.vue
🧠 Learnings (1)
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
web/src/components/company/CompanyDepartmentFormDialog.vue
🔇 Additional comments (5)
web/src/components/company/CompanyDepartmentFormDialog.vue (5)
19-19: LGTM!headnormalization tonullis correctly implemented.The
agentNamesprop is properly typed as optional, and theheadstate is consistently initialized and reset tonullrather than empty string, aligning with PrimeVue Select'sshow-clearbehavior.Also applies to: 31-31, 46-46, 60-60
119-121: LGTM! Defensive handling of optionalheadfield.The nullish coalescing before trim correctly handles the
nullvalue from PrimeVue Select's clear action, and conditionally settingdept.headonly when non-empty aligns with the backend's optionalDepartment.head.
155-162: LGTM! Select component is properly configured.The
input-idcorrectly associates with the label'sforattribute,show-clearpairs well with thestring | nullv-model type, and theagentNames ?? []fallback gracefully handles undefined props.
194-214: LGTM! Helpful contextual hints for JSON accordion sections.The helper text additions provide clear, concise guidance for each JSON field, improving form usability as specified in the PR objectives.
140-142: LGTM! Required field indicator added for Name.The red asterisk clearly communicates that Name is mandatory, and the label styling is consistent with other form fields.
Use ?? undefined for autonomy_level, matching budget_percent, so null values are omitted from the JSON payload instead of sent as explicit nulls. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #712 +/- ##
=======================================
Coverage ? 92.32%
=======================================
Files ? 572
Lines ? 29474
Branches ? 2855
=======================================
Hits ? 27213
Misses ? 1786
Partials ? 475 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
🤖 I have created a release *beep* *boop* --- ## [0.4.7](v0.4.6...v0.4.7) (2026-03-22) ### Features * add system user for CLI-to-backend authentication ([#710](#710)) ([dc6bd3f](dc6bd3f)) * dev channel builds with incremental pre-releases between stable releases ([#715](#715)) ([0e8a714](0e8a714)) * replace hardcoded name pools with Faker multi-locale name generation ([#714](#714)) ([5edc6ec](5edc6ec)) ### Bug Fixes * dev-release tag creation, dependabot coverage, go -C cli convention ([#730](#730)) ([7634843](7634843)) * improve name generation step UX and fix sentinel expansion bug ([#739](#739)) ([f03fd05](f03fd05)) * settings page UX polish -- toggle bug, source badges, form improvements ([#712](#712)) ([d16a0ac](d16a0ac)) * switch dev tags to semver and use same release pipeline as stable ([#729](#729)) ([4df6b9b](4df6b9b)), closes [#713](#713) * unify CLI image discovery and standardize Go tooling ([#738](#738)) ([712a785](712a785)) * use PAT in dev-release workflow to trigger downstream pipelines ([#716](#716)) ([d767aa3](d767aa3)) ### CI/CD * bump astral-sh/setup-uv from 7.4.0 to 7.6.0 in /.github/actions/setup-python-uv in the minor-and-patch group ([#731](#731)) ([7887257](7887257)) * bump the minor-and-patch group with 3 updates ([#735](#735)) ([7cd253a](7cd253a)) * bump wrangler from 4.75.0 to 4.76.0 in /.github in the minor-and-patch group ([#732](#732)) ([a6cafc7](a6cafc7)) * clean up all dev releases and tags on stable release ([#737](#737)) ([8d90f5c](8d90f5c)) ### Maintenance * bump the minor-and-patch group across 2 directories with 2 updates ([#733](#733)) ([2b60069](2b60069)) * bump the minor-and-patch group with 3 updates ([#734](#734)) ([859bc25](859bc25)) * fix dependabot labels and add scope tags ([#736](#736)) ([677eb15](677eb15)) * remove redundant pytest.mark.timeout(30) markers ([#740](#740)) ([9ec2163](9ec2163)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Summary
outlinedinstead of invisibletext)SettingGroupRendererfor company General tab (grouped layout with section headers)setup_completefrom settings UI (ADVANCED level + HIDDEN_SETTINGS filter)default_providersetting (definition + subscriber + tests)Department.headoptional in backend model -- departments always show in Org Chart regardless, with "No head assigned" warning when missingTest plan
setup_completein API tab (basic mode)default_providersettingReview coverage
Pre-reviewed by 6 agents (docs-consistency, frontend-reviewer, conventions-enforcer, test-quality, code-reviewer, issue-verifier). 0 findings requiring fixes across all agents. Issue verifier flagged Department.head requirement as the root cause of Org Chart empty state -- addressed in second commit.
Closes #709
Generated with Claude Code