Skip to content

feat(web): SavedFilter model, uninstall purge, and OSearch favorites - #263

Merged
buke merged 28 commits into
mainfrom
feat/web-saved-filter
Aug 10, 2026
Merged

feat(web): SavedFilter model, uninstall purge, and OSearch favorites#263
buke merged 28 commits into
mainfrom
feat/web-saved-filter

Conversation

@buke

@buke buke commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

  • PR-SF-1: Declare modules/web entryPoints.service and add handwritten web.SavedFilter (effective ModelId, IsDefault exclusivity, SF11 shared write/delete). SF13 expects empty web_field_default / web_app_setting after install.
  • PR-SF-2: In module uninstall cleanModels, hard-delete web_saved_filter only when a logical model has no remaining live meta_model (IMD-safe; table missing = no-op).
  • PR-SF-3: Wire OSearch Favorites via useSavedFilters / Save dialog, merge defaults (private > shared > code), and stop Kanban/Chart from dropping first-frame filter applies.

Test plan

  • go test ./internal/module/lifecycle/ -run 'SavedFilter|PurgesSaved|KeepsSaved|MissingTable'
  • ./choysum test unit web --be --pattern 'SavedFilter|SF13|SF11'
  • ./choysum test unit web --fe --pattern 'savedFilterDefaults|OSearch'
  • ./choysum test typecheck web
  • Manual: upgrade/install web, confirm tables web_saved_filter + web_field_default + web_app_setting; save/apply a Favorite in List search

Made with Cursor


PR Type

Enhancement, Tests


Description

  • Go Core Changes: Add purgeSavedFiltersForGoneModels in uninstaller.go to purge web_saved_filter rows when no surviving meta_model remains upon module uninstallation.

  • TypeScript Module Changes (modules/web): Declare entryPoints.service and implement handwritten web.SavedFilter model featuring dynamic ModelId resolution, IsDefault exclusivity, and shared favorite ACLs (SF11/SF12/SF13).

  • Web UI & Search Component: Wire OSearch favorites with useSavedFilters, merging server-defined defaults over code presets, and fix Kanban and Chart views from dropping initial frame filter applies.

  • License & SPDX Compliance: All new TypeScript source files under modules/web/service/ and modules/web/web/composables/search/ include Apache-2.0 SPDX headers; new Go test file includes LGPL-3.0-or-later header.

  • Test Coverage: Added Go lifecycle uninstall tests (internal/module/lifecycle/uninstaller_saved_filter_test.go), TypeScript backend tests (modules/web/service/tests/saved_filter.test.ts), and Vitest frontend unit tests (savedFilterDefaults.test.ts).


File Walkthrough

Relevant files
Enhancement
13 files
uninstaller.go
Purge saved filter entries on module uninstall when models are removed
+49/-0   
i18n.ts
Add i18n translation helper for web service                           
+9/-0     
index.ts
Export web service model definitions                                         
+7/-0     
_resolve_effective_model.ts
Resolve effective MetaModel ID from application and model name
+110/-0 
index.ts
Re-export SavedFilter model in web service                             
+7/-0     
saved_filter.ts
Implement SavedFilter model with ACL and default exclusivity logic
+445/-0 
OChartView.vue
Pass applied search filters to chart controller                   
+1/-0     
OSearchView.vue
Load server-merged filter defaults before initial search emit
+73/-6   
OSearch.vue
Add favorites dropdown menu and save filter modal dialog 
+121/-2 
index.ts
Export saved filters composables and default filter helpers
+2/-0     
savedFilterDefaults.ts
Implement merge logic for private, shared, and code default filters
+58/-0   
useSavedFilters.ts
Add composable for managing saved favorites lifecycle       
+175/-0 
chartController.ts
Support appliedFilters parameter override in chart controller
+3/-0     
Tests
4 files
uninstaller_saved_filter_test.go
Add Go lifecycle tests for saved filter cleanup on uninstall
+204/-0 
backend.go
Ensure meta module installation during web backend tests 
+2/-1     
saved_filter.test.ts
Add TS backend unit tests for SavedFilter operations         
+255/-0 
savedFilterDefaults.test.ts
Add Vitest unit tests for saved filter default merging     
+53/-0   
Configuration changes
1 files
package.json
Register service entrypoint for web module                             
+2/-1     
Bug fix
1 files
OKanbanView.vue
Prevent Kanban view from ignoring first-frame search applies
+2/-5     

Summary by CodeRabbit

  • New Features
    • Save, apply, delete, and share favorite search filters, with private and shared defaults.
    • Private saved-filter defaults take priority over shared and built-in defaults.
    • Added --no-web options for installation and upgrades.
    • Module upgrades now install required web components automatically when needed.
  • Bug Fixes
    • Preserved explicitly cleared filters across view reloads.
    • Improved search initialization for Kanban and chart views.
    • Improved authentication, permission, and validation error reporting.
    • Removed saved filters when their associated models are fully uninstalled.
    • Improved cross-application data installation and company-switching reliability.

- Declare web service entry and handwritten SavedFilter with effective ModelId, IsDefault exclusivity, and SF11 shared ACL.

- Purge web_saved_filter on module uninstall only when no surviving MetaModel remains for the logical model (IMD-safe).

- Wire OSearch Favorites via useSavedFilters, merge server defaults over code presets, and apply first-frame filters on Kanban/Chart.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds saved-filter persistence and cleanup, web-shell planning controls, cross-application data loading, validation metadata propagation, bootstrap updates, and backend test identity support. It also updates search views, module dependencies, installation flows, and related tests.

Changes

Saved filter lifecycle and search integration

Layer / File(s) Summary
SavedFilter service and cleanup
modules/web/service/*, internal/module/lifecycle/uninstaller.go, modules/web/data/bootstrap.json
Adds the SavedFilter model, effective-model resolution, authorization rules, and cleanup after model removal.
Saved-filter search integration
modules/web/web/composables/search/*, modules/web/web/components/view/search/*, modules/web/web/components/view/OSearchView.vue
Adds loading, merging, applying, saving, deleting, and default handling for private and shared saved filters.
Search query and first-frame handling
modules/web/web/controllers/chartController.ts, modules/web/web/query/utils/filter/structures.ts, modules/web/web/components/view/OKanbanView.vue
Preserves applied filters, converts nested query trees, and coordinates initial search application.

Web-shell planning and lifecycle execution

Layer / File(s) Summary
Web-shell request options
cmd/cmd_install.go, cmd/cmd_upgrade.go, internal/module/lifecycle/*, internal/module/plan/options.go
Adds SkipWebShell to commands, lifecycle requests, operation contexts, and plan options.
Plan construction and ensured upgrades
internal/module/plan/planner.go, internal/module/artifact/pipeline/pipeline.go, internal/module/lifecycle/modulemanager.go
Resolves web-shell dependencies, fills ModuleOrder or EnsureOrder, and installs ensured modules before upgrades.
Planning and lifecycle validation
internal/module/plan/*_test.go, internal/module/artifact/pipeline/pipeline_test.go, internal/module/lifecycle/*_test.go
Covers shell inclusion, skip behavior, order merging, callbacks, progress, errors, and cancellation.

Platform data, validation, and test identity

Layer / File(s) Summary
Module data and dependencies
internal/module/evolution/data/*, modules/*/package.json, modules/README.md, .cursor/rules/module-data-seeds.mdc
Preserves explicit cross-application ownership and updates module dependency and seed conventions.
Validation error propagation
modules/core/service/runtime/validation/*, modules/core/service/orm/repository/validation/*
Preserves ChoysumError metadata, short-circuits later constraints, and selects status-bearing validation issues.
Bootstrap and backend identity
internal/bootstrap/service/*, internal/testing/backend/*, pkg/jsengine/scripts/choysumtest/*
Targets minimal installation at meta, resolves seeded test identities, and resets request identity between JavaScript tests.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OSearchView
  participant OSearch
  participant useSavedFilters
  participant SavedFilter
  User->>OSearchView: open search view
  OSearchView->>useSavedFilters: load saved-filter defaults
  useSavedFilters->>SavedFilter: query active private and shared defaults
  SavedFilter-->>useSavedFilters: saved-filter rows
  useSavedFilters-->>OSearchView: merged defaults
  OSearchView->>OSearch: provide defaults and await initial query
  User->>OSearch: save or apply favorite
  OSearch->>useSavedFilters: create, apply, or delete saved filter
Loading

Possibly related PRs

Suggested labels: Review effort 4/5

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.23% which is insufficient. The required threshold is 80.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 clearly identifies the main changes: the SavedFilter model, uninstall cleanup, and OSearch favorites.
Description check ✅ Passed The description is detailed, relevant, and includes objectives, implementation details, test coverage, and a test plan.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/web-saved-filter

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

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

PR Code Suggestions ✨

No code suggestions found for the PR.

@codecov

codecov Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (3)
modules/web/service/models/saved_filter.ts (1)

219-239: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy lift

Back the name uniqueness with a database constraint.

_assertUniqueName reads and then the caller writes. Two concurrent creates can both pass the check and insert the same name. The check also runs through this.Search, so record rules can hide a conflicting row and let a duplicate through.

Add a unique index on (Application, ModelName, UserId, Name) and keep this check for the friendly error message. Note that most engines treat NULL values as distinct in a unique index, so shared rows need a normalized sentinel or a partial index to stay covered.

🤖 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 `@modules/web/service/models/saved_filter.ts` around lines 219 - 239, Add a
database-level unique constraint for Application, ModelName, UserId, and Name,
using the project’s schema or migration mechanism. Ensure rows with null UserId
are covered by normalizing them to a shared sentinel or using an appropriate
partial-index strategy, while retaining _assertUniqueName for the friendly
AlreadyExists error.
modules/web/service/tests/saved_filter.test.ts (1)

168-201: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for cross-bucket defaults and for a foreign UserId.

Two behaviors of the model stay untested:

  1. _clearOtherDefaults scopes the clear to one user bucket. Create a shared default and a private default for the same Application/ModelName, then assert both keep IsDefault = true. Today only same-bucket exclusivity is asserted.
  2. Create accepts a caller-supplied UserId. Add a test that passes another user's id and asserts the expected outcome. This test locks in the fix for the authorization gap raised in modules/web/service/models/saved_filter.ts.
🤖 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 `@modules/web/service/tests/saved_filter.test.ts` around lines 168 - 201,
Extend the saved-filter tests to cover cross-bucket defaults by creating shared
and private defaults with the same Application and ModelName, then assert both
retain IsDefault = true after creation. Add a separate Create test supplying a
different user’s UserId and assert the authorization behavior expected by the
SavedFilter model.
modules/web/service/models/_resolve_effective_model.ts (1)

87-105: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add Id as a stable tiebreaker to the pagination order.

Search accepts an OrderBy array. Use UpdatedAt desc followed by Id desc to keep offset pages stable when rows share the same UpdatedAt.

🤖 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 `@modules/web/service/models/_resolve_effective_model.ts` around lines 87 -
105, Update the Search call in the pagination loop to use the supported OrderBy
array, ordering first by UpdatedAt descending and then by Id descending. Keep
the existing pageSize/offset pagination behavior unchanged.
🤖 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 `@internal/module/lifecycle/uninstaller.go`:
- Around line 128-130: Update the uninstaller cleanup flow around the
webSavedFilterTable check to use db.Migrator().GetTables(), propagate its
failure as a wrapped error, and return nil only when web_saved_filter is
confirmed absent. Preserve the existing cleanup behavior when the table exists.

In `@modules/web/service/models/saved_filter.ts`:
- Around line 329-333: Update the UserId normalization block in the saved-filter
update flow to enforce the same owner restriction as the create path before
accepting a caller-supplied value. Reject reassignment of a private favorite to
another user and reject promotion to a shared row, while preserving valid owner
assignments and the existing null/empty normalization.
- Around line 267-276: Unvalidated UserId values can let non-administrators
assign saved filters to other users. In
modules/web/service/models/saved_filter.ts#L267-L276 and `#L329-L333`, add one
shared owner-normalization helper that accepts null or the current actor,
permits other owner IDs only for system administrators, and use it in both
_prepareCreate and _prepareUpdate before assigning values.UserId; replace the
direct String(raw).trim() handling with this helper.
- Around line 419-430: The Delete method must delete only the rows validated by
_assertCanMutateShared: search with required fields overriding options.fields,
validate each returned row, then build a new condition using only their IDs and
the lowercase 'in' operator before calling super.Delete. Return 0 when no rows
pass validation, and avoid reusing the original condition for deletion.
- Around line 385-399: Update the static Update method’s pre-read call to Search
so it passes only the fixed fields selection { fields: ['Id'] }, without
spreading options. Preserve forwarding options to UpdateById for the actual
updates.

In `@modules/web/web/components/view/OKanbanView.vue`:
- Around line 444-449: Update OKanbanView’s onMounted/controller.apply flow to
wait for the first query-update payload whenever searchView is rendered,
ensuring SavedFilter defaults are applied before the initial query. Preserve
immediate mount-time application when no search view exists, and keep onSearch
responsible for recording the first payload without suppressing its emit.

In `@modules/web/web/components/view/search/OSearch.vue`:
- Around line 92-110: Update OSearch’s Favorites menu to expose an authorized
delete control for each favorite, wiring it to the remove operation from
useSavedFilters and reporting any removal failures through the component’s
existing error-handling mechanism. Preserve the current favorite application
behavior and only allow deletion when the user is authorized.

---

Nitpick comments:
In `@modules/web/service/models/_resolve_effective_model.ts`:
- Around line 87-105: Update the Search call in the pagination loop to use the
supported OrderBy array, ordering first by UpdatedAt descending and then by Id
descending. Keep the existing pageSize/offset pagination behavior unchanged.

In `@modules/web/service/models/saved_filter.ts`:
- Around line 219-239: Add a database-level unique constraint for Application,
ModelName, UserId, and Name, using the project’s schema or migration mechanism.
Ensure rows with null UserId are covered by normalizing them to a shared
sentinel or using an appropriate partial-index strategy, while retaining
_assertUniqueName for the friendly AlreadyExists error.

In `@modules/web/service/tests/saved_filter.test.ts`:
- Around line 168-201: Extend the saved-filter tests to cover cross-bucket
defaults by creating shared and private defaults with the same Application and
ModelName, then assert both retain IsDefault = true after creation. Add a
separate Create test supplying a different user’s UserId and assert the
authorization behavior expected by the SavedFilter model.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4fde628d-e510-4c88-aeed-70f6ca426244

📥 Commits

Reviewing files that changed from the base of the PR and between b1fc401 and d0a0272.

📒 Files selected for processing (19)
  • internal/module/lifecycle/uninstaller.go
  • internal/module/lifecycle/uninstaller_saved_filter_test.go
  • internal/testing/backend/backend.go
  • modules/web/package.json
  • modules/web/service/i18n.ts
  • modules/web/service/index.ts
  • modules/web/service/models/_resolve_effective_model.ts
  • modules/web/service/models/index.ts
  • modules/web/service/models/saved_filter.ts
  • modules/web/service/tests/saved_filter.test.ts
  • modules/web/web/components/view/OChartView.vue
  • modules/web/web/components/view/OKanbanView.vue
  • modules/web/web/components/view/OSearchView.vue
  • modules/web/web/components/view/search/OSearch.vue
  • modules/web/web/composables/search/index.ts
  • modules/web/web/composables/search/savedFilterDefaults.test.ts
  • modules/web/web/composables/search/savedFilterDefaults.ts
  • modules/web/web/composables/search/useSavedFilters.ts
  • modules/web/web/controllers/chartController.ts

Comment thread internal/module/lifecycle/uninstaller.go Outdated
Comment thread modules/web/service/models/saved_filter.ts Outdated
Comment thread modules/web/service/models/saved_filter.ts Outdated
Comment thread modules/web/service/models/saved_filter.ts Outdated
Comment thread modules/web/service/models/saved_filter.ts Outdated
Comment thread modules/web/web/components/view/OKanbanView.vue Outdated
Comment thread modules/web/web/components/view/search/OSearch.vue

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 19 files

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread modules/web/web/composables/search/useSavedFilters.ts Outdated
Comment thread modules/web/web/composables/search/useSavedFilters.ts Outdated
Comment thread modules/web/web/components/view/OSearchView.vue Outdated
Comment thread modules/web/web/components/view/search/OSearch.vue
Comment thread modules/web/service/models/saved_filter.ts Outdated
Comment thread modules/web/web/components/view/OKanbanView.vue Outdated
Comment thread modules/web/web/components/view/OChartView.vue Outdated
Comment thread modules/web/web/composables/search/savedFilterDefaults.ts Outdated
Comment thread modules/web/service/models/_resolve_effective_model.ts Outdated
Comment thread modules/web/web/components/view/search/OSearch.vue
- Keep SF11 write/delete ACL on Update/Delete overrides; use ctx.mode for create because Id is pre-assigned before validation.

- Relax ModelId/CreateUid kernel notNull so Constraint writeback can run after required checks.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread modules/web/service/models/saved_filter.ts
Comment thread modules/web/service/models/saved_filter.ts
Comment thread modules/web/service/tests/saved_filter.test.ts Outdated
…z seeds

- Auto-include the web SPA shell when planned modules declare entryPoints.web, with CLI --no-web to opt out.

- Allow cross-app data seeding so domain modules can own authz packs; keep platform FieldDefault/AppSetting logical defaults in auth and SavedFilter RR in web.

- Retarget bootstrap minimal install to meta, harden module depends (web→document/meta, partner*→auth, drop unused task→base), and stabilize unit/e2e harness identity and fixtures.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread internal/module/plan/planner.go Fixed
Comment thread internal/module/plan/planner.go Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
internal/module/evolution/data/loader.go (1)

231-234: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Store the trimmed explicit application value.

Line 231 trims rec.Application, but Lines 232-234 only assign the normalized value when it is empty. A record with "application": " auth " keeps the whitespace in ModelData.Application. This can create an invalid cross-application mapping.

Proposed fix
 app := strings.TrimSpace(rec.Application)
 if app == "" {
   rec.Application = rules.OwnerApp
+} else {
+  rec.Application = app
 }
🤖 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 `@internal/module/evolution/data/loader.go` around lines 231 - 234, Update the
application normalization in the record-loading flow to assign the trimmed app
value back to rec.Application when it is non-empty, while retaining
rules.OwnerApp as the fallback for empty values. Ensure ModelData.Application
receives the normalized value for explicit applications.
🧹 Nitpick comments (1)
modules/web/service/models/saved_filter.ts (1)

177-197: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

Uniqueness is enforced only in application code.

_assertUniqueName performs a read and then the write proceeds. Two concurrent creates with the same Application, ModelName, UserId, and Name can both pass the check. No database unique index backs the rule. Consider adding a unique index over the four columns so the database rejects the duplicate.

🤖 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 `@modules/web/service/models/saved_filter.ts` around lines 177 - 197, Add a
database-level unique index covering Application, ModelName, UserId, and Name
for SavedFilter, while retaining _assertUniqueName for user-facing validation.
Ensure the index migration/schema change is included so concurrent writes are
rejected by the database.
🤖 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 `@internal/module/artifact/pipeline/pipeline.go`:
- Around line 1065-1103: The ensure-install pipeline must preserve installed
EnsureOrder module names for post-install lifecycle finalization. In
internal/module/artifact/pipeline/pipeline.go lines 1065-1103, carry the ensured
names into the upgrade lifecycle state while retaining existing install
behavior; in internal/module/lifecycle/modulemanager.go lines 1559-1562, process
a stable, deduplicated EnsureOrder plus ModuleOrder sequence for phase-end hooks
and refreshModuleIndexForLocalModules. Add a lifecycle regression test
confirming an ensured module receives both operations.

In `@modules/auth/e2e/switch_company_scope_acceptance.spec.ts`:
- Around line 307-317: Update the polling callback around readAuthTokens and
extractCompanyScopeFromToken so it only succeeds when activeCompanyId is
non-empty and differs from scopeA.activeCompanyId. Preserve the existing
30-second timeout and ensure transient missing-token results do not satisfy the
poll.

In `@modules/auth/service/tests/bootstrap_gift_pack.test.ts`:
- Line 164: Remove the duplicate expected declaration in the bootstrap gift pack
test, keeping a single Array<{ name: string; model: string }> binding within the
block so the module compiles.

In `@pkg/jsengine/scripts/choysumtest/choysumtest.js`:
- Around line 452-490: Update applyDefaultUnitIdentity to assign jsCtx.req.depth
to 0 unconditionally, replacing the conditional numeric-preservation check so
every test starts with the default request depth. Extend
TestChoysumTestScriptReappliesDefaultUnitIdentity to set a nonzero depth in its
first case and assert depth is 0 in the second case.

---

Outside diff comments:
In `@internal/module/evolution/data/loader.go`:
- Around line 231-234: Update the application normalization in the
record-loading flow to assign the trimmed app value back to rec.Application when
it is non-empty, while retaining rules.OwnerApp as the fallback for empty
values. Ensure ModelData.Application receives the normalized value for explicit
applications.

---

Nitpick comments:
In `@modules/web/service/models/saved_filter.ts`:
- Around line 177-197: Add a database-level unique index covering Application,
ModelName, UserId, and Name for SavedFilter, while retaining _assertUniqueName
for user-facing validation. Ensure the index migration/schema change is included
so concurrent writes are rejected by the database.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c7cadf6-0193-4a3d-a58c-78d0dc3962f4

📥 Commits

Reviewing files that changed from the base of the PR and between d0a0272 and a457d7d.

📒 Files selected for processing (38)
  • .cursor/rules/module-data-seeds.mdc
  • AGENTS.md
  • cmd/cmd_install.go
  • cmd/cmd_upgrade.go
  • internal/bootstrap/service/coordinator.go
  • internal/module/artifact/pipeline/pipeline.go
  • internal/module/evolution/data/loader.go
  • internal/module/evolution/data/loader_test.go
  • internal/module/lifecycle/install_module.go
  • internal/module/lifecycle/install_prefetch.go
  • internal/module/lifecycle/modulemanager.go
  • internal/module/lifecycle/operation_options.go
  • internal/module/lifecycle/service.go
  • internal/module/plan/options.go
  • internal/module/plan/plan.go
  • internal/module/plan/planner.go
  • internal/module/plan/planner_test.go
  • internal/testing/backend/backend.go
  • internal/testing/backend/unit_identity.go
  • internal/testing/backend/unit_identity_test.go
  • internal/testing/e2e/runner.go
  • modules/README.md
  • modules/auth/e2e/switch_company_scope_acceptance.spec.ts
  • modules/auth/package.json
  • modules/auth/service/tests/bootstrap_gift_pack.test.ts
  • modules/base/demo/demo.json
  • modules/base/package.json
  • modules/meta/package.json
  • modules/partner/package.json
  • modules/partner_bank/package.json
  • modules/partner_commercial/package.json
  • modules/task/package.json
  • modules/web/data/bootstrap.json
  • modules/web/package.json
  • modules/web/service/models/saved_filter.ts
  • modules/web/service/tests/saved_filter.test.ts
  • pkg/jsengine/scripts/choysumtest/choysumtest.js
  • pkg/jsengine/scripts/choysumtest/script_test.go
💤 Files with no reviewable changes (1)
  • modules/meta/package.json

Comment thread internal/module/artifact/pipeline/pipeline.go
Comment thread modules/auth/e2e/switch_company_scope_acceptance.spec.ts
Comment thread modules/auth/service/tests/bootstrap_gift_pack.test.ts
Comment thread pkg/jsengine/scripts/choysumtest/choysumtest.js
- Restrict SavedFilter UserId to the actor or shared null, and preserve ChoysumError statuses from constraints.

- Resolve browser actor identity via auth store; convert nested QueryCondition favorites; include keyword metadata when saving.

- Wait for OSearchView defaults before Kanban first load, add favorite delete/retry UI, and harden related harness/e2e edge cases.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 49 files (changes from recent commits).

Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread modules/web/data/bootstrap.json
Comment thread internal/module/plan/planner.go Outdated
Comment thread modules/web/service/models/saved_filter.ts Outdated
Comment thread internal/module/lifecycle/modulemanager.go
Comment thread internal/module/lifecycle/modulemanager.go
Comment thread internal/module/lifecycle/install_prefetch.go
Comment thread internal/bootstrap/service/coordinator.go Outdated
Comment thread modules/web/web/components/view/OSearchView.vue Outdated
Comment thread internal/module/plan/options.go
Comment thread modules/web/service/tests/saved_filter.test.ts
…atus meta

- Run upgrade phase-end hooks and module-index refresh for EnsureOrder plus ModuleOrder.

- Keep repository validation_failed wrapping while storing ChoysumError cause/gRPC on constraint issues.

- Persist trimmed seed application values and avoid CodeQL len-sum allocation capacity.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 7 files (changes from recent commits).

You’re at about 92% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/core/service/runtime/validation/engine.ts">

<violation number="1" location="modules/core/service/runtime/validation/engine.ts:584">
P1: Domain constraint responses lose their intended gRPC status and cause code whenever a kernel/platform or earlier constraint issue precedes them. Consider selecting the first status-bearing issue when wrapping the pipeline (and preserving its cause metadata), rather than consulting only `primaryIssue`.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread modules/core/service/runtime/validation/engine.ts
Comment thread modules/core/service/orm/repository/validation/error_helpers.ts
Comment thread modules/core/service/runtime/validation/engine.ts
buke and others added 3 commits August 9, 2026 17:46
- Grant base.user RoleMethodAccess and RoleFieldRule for web.SavedFilter alongside existing record rules.

- Skip web-shell ensuring on uninstall; clear shared defaults without sudo and reject uncleared foreign defaults.

- Fix favorites delete ownership/confirm/a11y, refresh server default winner after mutations, and fail closed on unit-identity lookup errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace identity/ctx/req with fresh minimal objects so allowlists and other case-local fields cannot leak across tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ysumError

- Select the first error issue with meta.grpcCode when wrapping repository validation failures so Unauthenticated is not masked by earlier kernel errors.

- Break the constraint handler loop after recording a domain ChoysumError so later handlers cannot run side effects.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 25 files (changes from recent commits).

You’re at about 93% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread pkg/jsengine/scripts/choysumtest/choysumtest.js Outdated
Comment thread modules/web/service/models/saved_filter.ts
Comment thread modules/web/web/components/view/OKanbanView.vue Outdated
Comment thread internal/module/lifecycle/uninstaller.go Outdated
Comment thread modules/web/data/bootstrap.json Outdated
Comment thread internal/testing/backend/unit_identity.go Outdated
Comment thread modules/web/service/models/saved_filter.ts
Comment thread modules/web/web/components/view/search/OSearch.vue Outdated
Comment thread pkg/jsengine/scripts/choysumtest/choysumtest.js
Comment thread modules/web/web/components/view/OSearchView.vue Outdated
- Add unit tests for unit identity, web-shell planning, EnsureOrder pipeline, uninstall purge, and bootstrap meta install helpers.

- Cover useSavedFilters/OSearch/OSearchView/actorUserId and SavedFilter BE edge cases so Codecov patch lines are exercised.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
modules/web/service/models/_resolve_effective_model.test.ts (1)

7-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore the empty factory state.

When original is undefined, call an exported unregisterServiceFactory that removes meta.MetaModel from the registry.

🤖 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 `@modules/web/service/models/_resolve_effective_model.test.ts` around lines 7 -
12, Update withMockedMetaSearch to call the exported unregisterServiceFactory
for meta.MetaModel when original is undefined, while retaining the existing
registerServiceFactory restoration when original exists. Ensure the mock cleanup
restores the registry to its prior empty state.
internal/module/lifecycle/install_module_test.go (1)

89-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the SkipWebShell behavior observable.

Both tests pass for any failure. They can pass if SkipWebShell is lost and planning fails while resolving web.

  • internal/module/lifecycle/install_module_test.go#L89-L97: make web origin access observable, then assert that the install reaches the intended later failure without accessing web.
  • internal/module/lifecycle/service_skip_webshell_test.go#L15-L18: use an observable service or planner path and assert that each request preserves SkipWebShell.
🤖 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 `@internal/module/lifecycle/install_module_test.go` around lines 89 - 97, Make
SkipWebShell assertions observable in both affected tests: in
internal/module/lifecycle/install_module_test.go:89-97, instrument the web
origin access and assert it is not accessed while InstallModule reaches the
intended later failure; in
internal/module/lifecycle/service_skip_webshell_test.go:15-18, use an observable
service or planner path and assert every request preserves SkipWebShell. Do not
accept arbitrary failures as passing.
internal/bootstrap/service/coordinator_minimal_install_test.go (1)

43-61: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Make the expected failure deterministic.

This test calls the real defaultInstallMinimalModules and relies on the executor or the install failing in the harness. That failure is environment-dependent. If executor construction later succeeds, the test starts a real module install, waits for the install timeout, and then fails.

Override newMinimalInstallExecutor and installMinimalModulesFn with a stub that returns a fixed error, as TestDefaultInstallMinimalModulesClassifiesInstallError does. Keep the assertion on snap.StageDetail.

🤖 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 `@internal/bootstrap/service/coordinator_minimal_install_test.go` around lines
43 - 61, Make TestDefaultInstallMinimalModulesMarksMetaStage deterministic by
overriding newMinimalInstallExecutor and installMinimalModulesFn with a stub
that returns a fixed error, matching the setup used in
TestDefaultInstallMinimalModulesClassifiesInstallError. Ensure
defaultInstallMinimalModules receives the stubbed failure without running a real
install, while preserving the existing snap.StageDetail assertion.
modules/core/service/runtime/validation/engine.ts (1)

574-593: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated and unnarrowed ChoysumError handling in both constraint catch blocks. The static-handler and instance-handler catch blocks contain identical code. Both attach cause metadata and then break for every ChoysumError, although the comment states the intent is only domain auth/status failures. A plain domain InvalidArgument therefore hides the remaining constraint issues, and any future change must be applied twice.

  • modules/core/service/runtime/validation/engine.ts#L574-L593: extract a shared helper, for example buildConstraintFailureIssue(handler, error), that returns the issue and a stop flag. Set the stop flag only for GrpcCode.Unauthenticated and GrpcCode.PermissionDenied.
  • modules/core/service/runtime/validation/engine.ts#L636-L655: replace this block with a call to the same helper so both paths stay in sync.
🤖 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 `@modules/core/service/runtime/validation/engine.ts` around lines 574 - 593, In
modules/core/service/runtime/validation/engine.ts, extract the duplicated
failure construction from the constraint catch blocks at lines 574-593 and
636-655 into a shared helper such as buildConstraintFailureIssue(handler, error)
that returns the issue and stop flag. Preserve ChoysumError metadata, but set
the stop flag only for GrpcCode.Unauthenticated or GrpcCode.PermissionDenied;
plain domain errors must allow remaining handlers to run. Replace both
catch-block implementations with the shared helper.
🤖 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 `@modules/core/service/orm/repository/validation/error_helpers.ts`:
- Around line 9-29: Update issueGrpcCode so zero-valued grpcCode metadata is
treated as absent, allowing wrapRepositoryValidationError to fall back to
GrpcCode.InvalidArgument; continue accepting only finite, nonzero numeric status
codes.

In `@modules/web/service/tests/saved_filter.test.ts`:
- Around line 154-160: Update the error assertion helper around
collectErrorCodes so messageHint is checked only after the expected code is
present, never as an alternative. Require codes.includes(code) first, then
validate messageHint when provided, while preserving the existing failure
message for missing or mismatched errors.

---

Nitpick comments:
In `@internal/bootstrap/service/coordinator_minimal_install_test.go`:
- Around line 43-61: Make TestDefaultInstallMinimalModulesMarksMetaStage
deterministic by overriding newMinimalInstallExecutor and
installMinimalModulesFn with a stub that returns a fixed error, matching the
setup used in TestDefaultInstallMinimalModulesClassifiesInstallError. Ensure
defaultInstallMinimalModules receives the stubbed failure without running a real
install, while preserving the existing snap.StageDetail assertion.

In `@internal/module/lifecycle/install_module_test.go`:
- Around line 89-97: Make SkipWebShell assertions observable in both affected
tests: in internal/module/lifecycle/install_module_test.go:89-97, instrument the
web origin access and assert it is not accessed while InstallModule reaches the
intended later failure; in
internal/module/lifecycle/service_skip_webshell_test.go:15-18, use an observable
service or planner path and assert every request preserves SkipWebShell. Do not
accept arbitrary failures as passing.

In `@modules/core/service/runtime/validation/engine.ts`:
- Around line 574-593: In modules/core/service/runtime/validation/engine.ts,
extract the duplicated failure construction from the constraint catch blocks at
lines 574-593 and 636-655 into a shared helper such as
buildConstraintFailureIssue(handler, error) that returns the issue and stop
flag. Preserve ChoysumError metadata, but set the stop flag only for
GrpcCode.Unauthenticated or GrpcCode.PermissionDenied; plain domain errors must
allow remaining handlers to run. Replace both catch-block implementations with
the shared helper.

In `@modules/web/service/models/_resolve_effective_model.test.ts`:
- Around line 7-12: Update withMockedMetaSearch to call the exported
unregisterServiceFactory for meta.MetaModel when original is undefined, while
retaining the existing registerServiceFactory restoration when original exists.
Ensure the mock cleanup restores the registry to its prior empty state.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7b1f38ec-2471-41d0-9554-f503479c32cd

📥 Commits

Reviewing files that changed from the base of the PR and between a457d7d and a6d4917.

📒 Files selected for processing (54)
  • AGENTS.md
  • internal/bootstrap/service/coordinator.go
  • internal/bootstrap/service/coordinator_minimal_install_test.go
  • internal/module/artifact/pipeline/pipeline_test.go
  • internal/module/evolution/data/loader.go
  • internal/module/evolution/data/loader_test.go
  • internal/module/lifecycle/install_module_test.go
  • internal/module/lifecycle/merge_unique_module_names_test.go
  • internal/module/lifecycle/modulemanager.go
  • internal/module/lifecycle/modulemanager_logging_test.go
  • internal/module/lifecycle/operation_options_test.go
  • internal/module/lifecycle/service_skip_webshell_test.go
  • internal/module/lifecycle/uninstaller.go
  • internal/module/lifecycle/uninstaller_saved_filter_test.go
  • internal/module/plan/options_test.go
  • internal/module/plan/planner.go
  • internal/module/plan/planner_test.go
  • internal/testing/backend/backend.go
  • internal/testing/backend/unit_identity.go
  • internal/testing/backend/unit_identity_test.go
  • modules/auth/e2e/switch_company_scope_acceptance.spec.ts
  • modules/core/service/orm/repository/validation/bridge.ts
  • modules/core/service/orm/repository/validation/error_helpers.ts
  • modules/core/service/orm/repository/validation/index.ts
  • modules/core/service/orm/repository/validation/tests/error_helpers.test.ts
  • modules/core/service/runtime/validation/engine.test.ts
  • modules/core/service/runtime/validation/engine.ts
  • modules/web/data/bootstrap.json
  • modules/web/service/models/_resolve_effective_model.test.ts
  • modules/web/service/models/_resolve_effective_model.ts
  • modules/web/service/models/saved_filter.ts
  • modules/web/service/tests/saved_filter.test.ts
  • modules/web/web/components/view/OChartView.vue
  • modules/web/web/components/view/OKanbanView.firstframe.test.ts
  • modules/web/web/components/view/OKanbanView.readonly.test.ts
  • modules/web/web/components/view/OKanbanView.vue
  • modules/web/web/components/view/OSearchView.test.ts
  • modules/web/web/components/view/OSearchView.vue
  • modules/web/web/components/view/kanbanFirstFrame.test.ts
  • modules/web/web/components/view/kanbanFirstFrame.ts
  • modules/web/web/components/view/search/OSearch.behavior.test.ts
  • modules/web/web/components/view/search/OSearch.vue
  • modules/web/web/composables/search/actorUserId.test.ts
  • modules/web/web/composables/search/actorUserId.ts
  • modules/web/web/composables/search/savedFilterDefaults.test.ts
  • modules/web/web/composables/search/savedFilterDefaults.ts
  • modules/web/web/composables/search/useSavedFilters.test.ts
  • modules/web/web/composables/search/useSavedFilters.ts
  • modules/web/web/controllers/chartController.test.ts
  • modules/web/web/controllers/chartController.ts
  • modules/web/web/query/utils/filter/structures.test.ts
  • modules/web/web/query/utils/filter/structures.ts
  • pkg/jsengine/scripts/choysumtest/choysumtest.js
  • pkg/jsengine/scripts/choysumtest/script_test.go
🚧 Files skipped from review as they are similar to previous changes (17)
  • internal/module/lifecycle/uninstaller.go
  • modules/auth/e2e/switch_company_scope_acceptance.spec.ts
  • modules/web/service/models/_resolve_effective_model.ts
  • internal/testing/backend/unit_identity.go
  • AGENTS.md
  • pkg/jsengine/scripts/choysumtest/choysumtest.js
  • modules/web/web/composables/search/savedFilterDefaults.test.ts
  • internal/module/evolution/data/loader.go
  • modules/web/web/controllers/chartController.ts
  • modules/web/web/components/view/OSearchView.vue
  • modules/web/web/composables/search/savedFilterDefaults.ts
  • modules/web/web/components/view/OChartView.vue
  • internal/module/evolution/data/loader_test.go
  • modules/web/service/models/saved_filter.ts
  • modules/web/web/composables/search/useSavedFilters.ts
  • modules/web/web/components/view/search/OSearch.vue
  • pkg/jsengine/scripts/choysumtest/script_test.go

Comment thread modules/core/service/orm/repository/validation/error_helpers.ts
Comment thread modules/web/service/tests/saved_filter.test.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 31 files (changes from recent commits).

You’re at about 95% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread internal/bootstrap/service/coordinator_minimal_install_test.go
Comment thread internal/module/lifecycle/uninstaller.go
Comment thread internal/module/plan/planner.go
Comment thread internal/bootstrap/service/coordinator.go
Comment thread modules/web/web/components/view/search/OSearch.behavior.test.ts
Comment thread internal/module/lifecycle/service_skip_webshell_test.go Outdated
Comment thread internal/module/lifecycle/install_module_test.go
Comment thread internal/module/plan/planner_test.go Outdated
Comment thread internal/testing/backend/unit_identity_test.go Outdated
Comment thread modules/web/service/models/_resolve_effective_model.test.ts Outdated
buke and others added 2 commits August 9, 2026 19:14
- Always rebuild choysumtest identity/ctx for auth-free cases and drop dead Symbol cleanup.

- Preflight shared-default clear ACL, split SavedFilter RMAs by method, and treat missing auth.User as not found.

- Reject non-canonical meta.grpcCode for status selection; probe uninstall table existence without swallowing DB errors.

- Deduplicate Kanban first search, race-guard OSearchView default loads, reuse mergeSavedFilterDefaults, and style delete confirm as danger.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Stub minimal meta install stage marking and assert SkipWebShell skips web resolve.

- Require expectCode to match error codes before message hints; unregister mocked MetaModel factories.

- Key identity/company_main and planner ensure-load failures off intent, not call counts; assert OSearch codeDefaults shapes.

Co-authored-by: Cursor <cursoragent@cursor.com>
@deepsource-io

deepsource-io Bot commented Aug 9, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in b1fc401...386a402 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

PR Report Card

Overall Grade  

Focus Area: Reliability
Security  

Reliability  

Complexity  

Hygiene  

Feedback

Type looseness in tests

  • The any and non-null assertions are both ways the tests sidestep the type system, spread across a lot of files.
  • Because these tests sit around the new saved filter / search behavior, making them stricter would give you better confidence that the behavior holds up as the feature evolves.

Code Review Summary

Analyzer Status Updated (UTC) Details
Go Aug 10, 2026 4:20a.m. Review ↗
JavaScript Aug 10, 2026 4:20a.m. Review ↗
Python Aug 10, 2026 4:20a.m. Review ↗
Shell Aug 10, 2026 4:20a.m. Review ↗
Secrets Aug 10, 2026 4:20a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

- Require error code before message hints and throw descriptive failures (choysumtest expect ignores a second arg).

- Match SF11 stranger write/delete assertions to "violates record rule" instead of the old OR-hint "record_rule_denied".

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread internal/module/artifact/pipeline/pipeline_test.go Outdated
Comment thread internal/module/artifact/pipeline/pipeline_test.go Outdated
Comment thread internal/module/artifact/pipeline/pipeline_test.go Outdated
Comment thread internal/module/artifact/pipeline/pipeline_test.go Outdated
Comment thread internal/module/artifact/pipeline/pipeline_test.go Outdated
Comment thread internal/module/plan/planner_test.go Outdated
Comment thread internal/module/plan/planner_test.go Outdated
Comment thread internal/module/plan/planner_test.go Outdated
Comment thread internal/module/plan/planner_test.go Outdated
Comment thread internal/module/plan/planner_test.go Outdated
- Rename clear helper that shadowed the predeclared clear identifier.

- Mark unused callback parameters as blank identifiers in planner/pipeline EnsureOrder tests.

- Stop passing nil into WithOperationOptions while keeping an explicit nil FromContext contract check.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread internal/module/plan/planner_test.go Outdated
Comment thread internal/module/plan/planner_test.go Outdated
Comment thread internal/module/plan/planner_test.go Outdated
Comment thread internal/module/plan/planner_test.go Outdated
buke and others added 2 commits August 9, 2026 20:14
- Rename unused fakeResolver peek/load name parameters to _ in uninstall and dependency error cases.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Cover web_saved_filter probe/non-table DB errors and Upgrade SkipWebShell option wiring.

- Hit Upgrade module-index refresh failure, auth.User lookup wrap, and unit identity context errors in RunOneAppBackendTests.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread internal/module/lifecycle/module_index_sync_test.go Outdated
buke and others added 2 commits August 9, 2026 20:51
- Cover Kanban first-frame lastSearchPayload skip and falsy onSearch.

- Cover chartController appliedFilters clear-flag branch matrix.

- Extend SavedFilter BE cases for whitespace UserId, shared-default replace, and rename uniqueness.

- Fill OSearchView, OSearch, useSavedFilters, defaults, structures, and effective-model partials.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Stub clearOtherDefaults sudo paths and exercise constraint null defaults.

- Cover useSavedFilters/OSearch/OSearchView || and stale-gen arms.

- Yield before empty app/model clear so superseding loads are race-safe.

- Hit resolveEffectiveModel missing timestamps and null Search pages.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (5)
internal/module/lifecycle/service_upgrade_test.go (1)

17-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert that SkipWebShell reaches the operation context.

This test passes if Upgrade ignores SkipWebShell. The missing-module error does not expose the applied operation options. Capture the planner or lifecycle context and assert OperationOptions.SkipWebShell is true.

🤖 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 `@internal/module/lifecycle/service_upgrade_test.go` around lines 17 - 24,
Update the Upgrade test to capture the planner or lifecycle context used by
svc.Upgrade, then assert the captured OperationOptions.SkipWebShell value is
true. Preserve the existing missing-module failure assertion while ensuring the
test verifies that SkipWebShell reaches the operation context rather than merely
being accepted by the request.
modules/web/web/components/view/OSearchView.test.ts (1)

259-279: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make this race assertion discriminating.

Line 260 uses mockResolvedValue, so every load returns the same Keep row. The assertion at line 278 then passes in two different cases: the supersede guard skipped the empty-app clear, or the clear happened and the newer load re-fetched the identical row. The test cannot detect a regression in the guard.

Return a distinct row for the newer load, and assert that value.

♻️ Distinguish the two loads
-    sfSearch.mockResolvedValue([
-      { Id: 'p1', Name: 'Keep', Condition: {}, IsDefault: true, UserId: 'me' },
-    ]);
+    sfSearch.mockResolvedValueOnce([
+      { Id: 'p1', Name: 'Keep', Condition: {}, IsDefault: true, UserId: 'me' },
+    ]);
     const store = makeStore();
@@
     store.application = 'demo';
+    sfSearch.mockResolvedValueOnce([
+      { Id: 'p2', Name: 'Newer', Condition: {}, IsDefault: true, UserId: 'me' },
+    ]);
     await wrapper.find('.emit-defaults-ready').trigger('click');
     await flushPromises();
     await nextTick();
-    expect(JSON.parse(wrapper.find('.defaults').text())[0].name).toBe('Keep');
+    expect(JSON.parse(wrapper.find('.defaults').text())[0].name).toBe('Newer');
🤖 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 `@modules/web/web/components/view/OSearchView.test.ts` around lines 259 - 279,
Update the sfSearch mock in the “skips clearing defaults when a newer load
supersedes empty app/model” test to return the existing Keep row for the initial
load and a distinct row for the newer load, using sequential results or an
equivalent implementation. Change the final defaults assertion to require the
newer row’s distinct value, so the test fails if the empty-app clear is
incorrectly allowed to win.
modules/web/web/components/view/search/OSearch.behavior.test.ts (1)

624-643: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

This test cannot detect a swapped checkbox binding.

Lines 633-634 set both checkboxes to true, and line 638 asserts both isDefault and shared are true. If the template swaps the isDefault and shared bindings, the payload is identical and the test still passes. Line 632 also confirms only the count, not the identity, of each checkbox.

Toggle one checkbox at a time, or select each checkbox by a stable class instead of by index.

♻️ Assert each checkbox binding separately
     const checks = wrapper.findAll('input[type="checkbox"]');
     expect(checks.length).toBeGreaterThanOrEqual(2);
     await checks[0]!.setValue(true);
-    await checks[1]!.setValue(true);
     const saveBtn = wrapper.findAll('.el-btn').find(b => b.text() === 'Save');
     await saveBtn!.trigger('click');
     await flushPromises();
     expect(savedFiltersApi.saveCurrent).toHaveBeenCalledWith({
       name: 'SharedDef',
       isDefault: true,
-      shared: true,
+      shared: false,
     });

Add a second test that sets only checks[1] and asserts { isDefault: false, shared: true }.

🤖 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 `@modules/web/web/components/view/search/OSearch.behavior.test.ts` around lines
624 - 643, Strengthen the checkbox binding coverage in the test around “saves
with isDefault and shared checkboxes enabled” by adding a separate case that
enables only the second checkbox and expects the save payload to contain
isDefault: false and shared: true. Prefer stable checkbox selectors when
available, or otherwise preserve the existing checkbox targeting while ensuring
the test distinguishes the two bindings.
modules/web/web/components/view/OKanbanView.firstframe.test.ts (1)

150-204: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Unmount every wrapper returned by mount.

These tests leave four OKanbanView instances mounted. The third test also leaves awaitFieldSelectionMock pending indefinitely. Store each wrapper and call wrapper.unmount() after its assertions. beforeEach already resets deferState and clears the shared mocks.

🤖 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 `@modules/web/web/components/view/OKanbanView.firstframe.test.ts` around lines
150 - 204, Update the affected OKanbanView tests to retain each wrapper returned
by mount and call wrapper.unmount() after assertions, including the cases using
SyncEmitSearch and FalsyEmitSearch. Ensure the test with the indefinitely
pending awaitFieldSelectionMock is unmounted so its component instance and
pending work are cleaned up.
modules/web/service/tests/saved_filter.test.ts (1)

917-976: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Restore inherited static methods without binding them

sudo and Update are inherited from BaseModel. The bound-function assignments in finally create own properties on SavedFilter and pin this to SavedFilter. Preserve the original ownership state, then delete the stub properties when the methods were inherited.

🤖 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 `@modules/web/service/tests/saved_filter.test.ts` around lines 917 - 976,
Update the test’s cleanup around SavedFilter.sudo and SavedFilter.Update to
preserve whether each method was originally inherited from BaseModel rather than
binding inherited methods. Restore the original functions without binding, and
delete the temporary own-property stubs in finally when the methods were not
originally defined directly on SavedFilter.
🤖 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.

Nitpick comments:
In `@internal/module/lifecycle/service_upgrade_test.go`:
- Around line 17-24: Update the Upgrade test to capture the planner or lifecycle
context used by svc.Upgrade, then assert the captured
OperationOptions.SkipWebShell value is true. Preserve the existing
missing-module failure assertion while ensuring the test verifies that
SkipWebShell reaches the operation context rather than merely being accepted by
the request.

In `@modules/web/service/tests/saved_filter.test.ts`:
- Around line 917-976: Update the test’s cleanup around SavedFilter.sudo and
SavedFilter.Update to preserve whether each method was originally inherited from
BaseModel rather than binding inherited methods. Restore the original functions
without binding, and delete the temporary own-property stubs in finally when the
methods were not originally defined directly on SavedFilter.

In `@modules/web/web/components/view/OKanbanView.firstframe.test.ts`:
- Around line 150-204: Update the affected OKanbanView tests to retain each
wrapper returned by mount and call wrapper.unmount() after assertions, including
the cases using SyncEmitSearch and FalsyEmitSearch. Ensure the test with the
indefinitely pending awaitFieldSelectionMock is unmounted so its component
instance and pending work are cleaned up.

In `@modules/web/web/components/view/OSearchView.test.ts`:
- Around line 259-279: Update the sfSearch mock in the “skips clearing defaults
when a newer load supersedes empty app/model” test to return the existing Keep
row for the initial load and a distinct row for the newer load, using sequential
results or an equivalent implementation. Change the final defaults assertion to
require the newer row’s distinct value, so the test fails if the empty-app clear
is incorrectly allowed to win.

In `@modules/web/web/components/view/search/OSearch.behavior.test.ts`:
- Around line 624-643: Strengthen the checkbox binding coverage in the test
around “saves with isDefault and shared checkboxes enabled” by adding a separate
case that enables only the second checkbox and expects the save payload to
contain isDefault: false and shared: true. Prefer stable checkbox selectors when
available, or otherwise preserve the existing checkbox targeting while ensuring
the test distinguishes the two bindings.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6e680d2d-033f-4aa2-adba-abcae8c084c9

📥 Commits

Reviewing files that changed from the base of the PR and between 7657f53 and 3288179.

📒 Files selected for processing (16)
  • internal/module/lifecycle/module_index_sync_test.go
  • internal/module/lifecycle/service_upgrade_test.go
  • internal/module/lifecycle/uninstaller_saved_filter_test.go
  • internal/module/plan/planner_test.go
  • internal/testing/backend/backend_injected_test.go
  • internal/testing/backend/unit_identity_test.go
  • modules/web/service/models/_resolve_effective_model.test.ts
  • modules/web/service/tests/saved_filter.test.ts
  • modules/web/web/components/view/OKanbanView.firstframe.test.ts
  • modules/web/web/components/view/OSearchView.test.ts
  • modules/web/web/components/view/OSearchView.vue
  • modules/web/web/components/view/search/OSearch.behavior.test.ts
  • modules/web/web/composables/search/savedFilterDefaults.test.ts
  • modules/web/web/composables/search/useSavedFilters.test.ts
  • modules/web/web/controllers/chartController.test.ts
  • modules/web/web/query/utils/filter/structures.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • modules/web/web/query/utils/filter/structures.test.ts
  • modules/web/web/composables/search/savedFilterDefaults.test.ts
  • modules/web/web/components/view/OSearchView.vue
  • internal/module/lifecycle/uninstaller_saved_filter_test.go
  • internal/module/plan/planner_test.go
  • internal/testing/backend/unit_identity_test.go

buke and others added 2 commits August 9, 2026 21:26
- Exercise falsy create Id so currentId uses the empty-string fallback.

- Race empty-app defaults clear without awaiting the first click.

- Cover private canDelete with falsy non-null UserId via || ''.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Observe SkipWebShell on Upgrade Peek context instead of a vacuous miss.

- Tighten OSearchView stale-clear race and OSearch checkbox bindings.

- Unmount Kanban first-frame wrappers and restore SavedFilter stubs cleanly.

- Use 0750 for the module-index upgrade test mkdir DeepSource flagged.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread internal/module/lifecycle/service_upgrade_test.go Outdated
Comment thread internal/module/lifecycle/service_upgrade_test.go Outdated
Comment thread internal/module/lifecycle/service_upgrade_test.go Outdated
buke and others added 9 commits August 9, 2026 21:47
- Drop unused receiver names on stub OriginCoordinator methods.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Drop the lazy metaModelService wrapper; web already depends on meta.

- Use createServiceByModel<typeof MetaModel> at module scope like auth.

- Stub MetaModel.Search in unit tests instead of swapping the factory.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Drop the one-line _actorId helper; trim this.userId at call sites.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace Go LookupEffectiveModel with First by application+name at loader, bootstrap, and unit identity call sites.

- Inline MetaModel/MetaApplication Search limit 1 in auth ACL and SavedFilter; delete TS resolveEffective copies and pick-matrix tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Skip syncing draft active/enabled from JWT metadata while the switcher popover is open so refreshToken cannot clear a pending selection.

- Harden Apply readiness assertions in company-switch E2E helpers.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Add ScopeKey (normalized path) so Name uniqueness and IsDefault mutex are per route bucket.

- Prefill favorite Name from stable term src and filter list/create/defaults by current ScopeKey.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Cover normalizeScopeKey, default favorite name, and OSearch/OSearchView ScopeKey wiring.

- Add OSwitchCompany open-panel draft guard and method-access meta lookup edge cases.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Extract trySetupHook for full branch coverage and cover defaultFavoriteName ||/?? edges.

- Exercise SavedFilter empty-string owner bucket and ScopeKey merge on update.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Call _clearOtherDefaults with no identity userId so this.userId || '' is covered.

Co-authored-by: Cursor <cursoragent@cursor.com>
@buke
buke merged commit 218d1ff into main Aug 10, 2026
47 of 49 checks passed
@buke
buke deleted the feat/web-saved-filter branch August 10, 2026 04:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants