Skip to content

feat: feature paywall with free/enterprise tier enforcement - #575

Open
Harrio-6 wants to merge 12 commits into
mainfrom
harryyang2005/dev-1324-feature-paywall
Open

feat: feature paywall with free/enterprise tier enforcement#575
Harrio-6 wants to merge 12 commits into
mainfrom
harryyang2005/dev-1324-feature-paywall

Conversation

@Harrio-6

@Harrio-6 Harrio-6 commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Add plan_tier column to organizations (defaults to free)
Free tier limited to 1 seat (org creator only); enterprise unlimited
Invite button shows upgrade modal with cal.com booking link on free tier
Upgrade modal accessible from both Members tab and Overview settings
PATCH /api/orgs/plan route handles downgrade cleanup (revokes non-creator access, resets Casbin roles, expires invitations)
Paywall bypassed entirely when AURORA_ENV=dev

Summary by CodeRabbit

  • New Features

    • Added organization plan awareness across settings, overview, and member management, including free-tier upgrade prompts (hidden in dev).
    • Added an “Upgrade to Enterprise” modal with an enterprise features list and a direct meeting-booking link.
    • Introduced an API to update an org’s plan tier with enforced free↔enterprise rules.
  • Bug Fixes

    • Expanded invitation cleanup to prevent duplicate conflicts by removing accepted invitations during user re-invite.
    • Enforced free-plan seat limits and improved the hook wrapper’s behavior to avoid unintended error cascades.

@Harrio-6
Harrio-6 requested a review from a team as a code owner July 2, 2026 20:23
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

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

Adds org plan-tier storage and API support, enforces free-tier member limits, expands invitation cleanup, and wires the org UI to display and upgrade the current plan.

Changes

Plan tier & upgrade feature

Layer / File(s) Summary
Plan tier storage and org responses
server/utils/db/db_utils.py, server/routes/org_routes.py
Adds organizations.plan_tier, returns planTier from current-org responses, and standardizes missing-org errors.
Plan update and invitation cleanup
server/routes/admin_routes.py, server/routes/org_routes.py
Adds org plan updates with downgrade cleanup and expands invitation cleanup to include accepted rows.
Seat-limit hook enforcement
server/utils/hooks.py
Blocks free-tier member additions at the seat limit in non-dev and hardens hook fallback handling.
Org UI plan wiring
client/src/app/org/components/UpgradeModal.tsx, client/src/app/org/components/OrgOverview.tsx, client/src/app/org/components/OrgMembers.tsx, client/src/components/OrgSettings.tsx, client/src/components/SettingsModal.tsx
Propagates planTier, adds plan display and upgrade actions, gates member addition by tier, adds the upgrade modal, and adjusts organization tab padding.

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

Possibly related PRs

  • Arvo-AI/aurora#467: Modifies the shared hook fallback behavior in server/utils/hooks.py.
  • Arvo-AI/aurora#474: Adds the seat-limit hook plumbing that this change extends in server/utils/hooks.py.

Suggested reviewers: damianloch, arvo-ai-staging

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: a free/enterprise paywall with tier enforcement.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch harryyang2005/dev-1324-feature-paywall

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

arvo-ai-staging[bot]
arvo-ai-staging Bot previously approved these changes Jul 2, 2026

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review

Verdict: SAFE

No risks identified. This change looks safe to ship.


Aurora reviews PRs for incident prevention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 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 `@client/src/app/org/components/OrgMembers.tsx`:
- Around line 265-277: The `isFree` check in `OrgMembers` has the same
missing-default issue as `OrgOverview`: an undefined `planTier` is currently
treated as non-free, so the Add flow can bypass the upgrade gate. Update the
`isFree` logic in `OrgMembers` so unresolved tier data is handled as free/locked
by default, and ensure the Add button path continues to open `UpgradeModal`
until `planTier` is known rather than falling through to `AddUserDialog`.

In `@client/src/app/org/components/OrgOverview.tsx`:
- Around line 20-32: `OrgOverview` currently treats missing `planTier` as
non-free when computing `isFree`, which makes the plan label fallback and
upgrade gating inconsistent. Update the `isFree` derivation in `OrgOverview` to
use the same default as the displayed plan text (`free` when `planTier` is
undefined), and apply the same normalization in `OrgMembers` where the
`UpgradeModal` vs `AddUserDialog` choice is made. Keep the logic centralized or
mirrored so both components handle missing `planTier` consistently.

In `@client/src/app/org/components/UpgradeModal.tsx`:
- Around line 39-44: The external link opened from UpgradeModal’s Button click
handler should use safer window.open settings to prevent reverse-tabnabbing.
Update the onClick callback in UpgradeModal to open the Cal.com URL with the
same _blank target plus noopener,noreferrer in the window features, keeping the
existing Button behavior unchanged.

In `@server/routes/org_routes.py`:
- Around line 1203-1206: The downgrade cleanup in the org route is bypassing the
centralized token/secret lifecycle by deleting directly from user_tokens. Update
the org downgrade flow in the route handler to use the existing token management
helpers instead of ad-hoc SQL, so secret_ref cleanup and Vault secret handling
stay consistent. Locate the cleanup logic around the org downgrade path and
replace the direct DELETE with the centralized helper-based token removal path
used by store_tokens_in_db/get_token_data-related flows.
- Around line 1195-1202: The downgrade handling in org_routes should expire
every pending org invitation when moving from enterprise to free, not just those
matching existing non-creator users. Update the invitation cleanup logic around
the old_tier/new_tier check so the org_invitations update targets all pending
invites for the org, likely by filtering on pending status and org_id rather
than the current email subquery, while preserving the creator exclusion only
where needed. Use the existing org invitation expiration block in the route
handler to locate the change.
- Around line 1173-1232: The organization plan_tier update flow currently allows
any org-manage caller to set the tier to enterprise, which should not be
permitted from this route. Update the handler around the new_tier validation and
the old_tier/new_tier transition logic to reject enterprise upgrades here,
allowing only safe downgrades (for example enterprise to free) or gating
upgrades behind a trusted billing/internal path. Keep the existing downgrade
cleanup in the db_pool.get_admin_connection / organizations UPDATE path, but
prevent persisting enterprise from this endpoint.

In `@server/utils/db/db_utils.py`:
- Around line 3121-3123: `plan_tier` is currently added as a nullable, free-form
column, which lets NULL or unexpected values bypass the seat-limit enforcement
that only checks for `"free"`. Update the `ALTER TABLE organizations` migration
in `db_utils.py` to make `plan_tier` non-null and constrained to the allowed set
(at minimum including `"free"`), while keeping the default consistent. Make sure
the `plan_tier` schema change in the organizations table enforces this at the
database boundary so downstream hooks cannot receive invalid values.

In `@server/utils/hooks.py`:
- Around line 127-133: The default fallback in the hook dispatch is failing
open, which can bypass seat-limit enforcement when `before_add_member` errors.
Update the `server/utils/hooks.py` hook invocation path around
`_HOOK_REGISTRY[name]` so that if the default DB-backed check raises, it returns
a denial result instead of `(True, None)`, and keep the behavior specific to
access-control hooks like `before_add_member` while preserving the existing
exception logging.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 623e9f00-fa7d-45f4-98bc-1beedf257b0d

📥 Commits

Reviewing files that changed from the base of the PR and between 48d9489 and 56f061c.

📒 Files selected for processing (9)
  • client/src/app/org/components/OrgMembers.tsx
  • client/src/app/org/components/OrgOverview.tsx
  • client/src/app/org/components/UpgradeModal.tsx
  • client/src/components/OrgSettings.tsx
  • client/src/components/SettingsModal.tsx
  • server/routes/admin_routes.py
  • server/routes/org_routes.py
  • server/utils/db/db_utils.py
  • server/utils/hooks.py

Comment thread client/src/app/org/components/OrgMembers.tsx Outdated
Comment thread client/src/app/org/components/OrgOverview.tsx
Comment thread client/src/app/org/components/UpgradeModal.tsx Outdated
Comment thread server/routes/org_routes.py
Comment thread server/routes/org_routes.py Outdated
Comment thread server/routes/org_routes.py Outdated
Comment thread server/utils/db/db_utils.py
Comment thread server/utils/hooks.py Outdated
Comment thread client/src/app/org/components/UpgradeModal.tsx Fixed

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
client/src/app/org/components/UpgradeModal.tsx (1)

41-41: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

noreferrer still missing from window.open.

Prior feedback asked for noopener,noreferrer; only noopener was added. noopener covers the main reverse-tabnabbing risk, so this is low severity, but consider adding noreferrer too for completeness.

🔧 Suggested tweak
-            onClick={() => window.open("https://cal.com/arvo-ai?ref=999998", "_blank", "noopener")}
+            onClick={() => window.open("https://cal.com/arvo-ai?ref=999998", "_blank", "noopener,noreferrer")}
🤖 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 `@client/src/app/org/components/UpgradeModal.tsx` at line 41, The
`UpgradeModal` link opener still only passes `noopener`, so update the
`window.open` call in the click handler to include `noreferrer` as well, using
the existing Cal.com URL and `_blank` target. Keep the change localized to the
`onClick` handler in `UpgradeModal.tsx` so the popup behavior remains the same
while adding the missing referrer protection.
🤖 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.

Duplicate comments:
In `@client/src/app/org/components/UpgradeModal.tsx`:
- Line 41: The `UpgradeModal` link opener still only passes `noopener`, so
update the `window.open` call in the click handler to include `noreferrer` as
well, using the existing Cal.com URL and `_blank` target. Keep the change
localized to the `onClick` handler in `UpgradeModal.tsx` so the popup behavior
remains the same while adding the missing referrer protection.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 38906f56-0df3-41fc-bd05-9a9a0dc7a634

📥 Commits

Reviewing files that changed from the base of the PR and between 56f061c and 9e5e64f.

📒 Files selected for processing (5)
  • client/src/app/org/components/OrgMembers.tsx
  • client/src/app/org/components/OrgOverview.tsx
  • client/src/app/org/components/UpgradeModal.tsx
  • server/routes/org_routes.py
  • server/utils/hooks.py

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
server/routes/org_routes.py (1)

1239-1252: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Post-commit side effects can mask a successful downgrade with a 500.

The transaction commits at Line 1237, but record_audit_event(...) (Line 1246) runs inside the outer try. If audit logging raises, the handler falls through to the except and returns 500, even though the plan change and destructive cleanup already committed. The client sees a failure for an operation that actually succeeded. Consider isolating post-commit work so it can't invert the response status.

♻️ Isolate post-commit audit from the request result
         record_audit_event(org_id, user_id, "update_plan", "organization", org_id,
-                           {"old_tier": old_tier, "new_tier": new_tier}, request)
+                           {"old_tier": old_tier, "new_tier": new_tier}, request)

Wrap the audit call (and, as already done for Casbin, treat it as best-effort):

        try:
            record_audit_event(org_id, user_id, "update_plan", "organization", org_id,
                               {"old_tier": old_tier, "new_tier": new_tier}, request)
        except Exception as e:
            logger.warning("Failed to record plan-update audit event: %s", e)
🤖 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 `@server/routes/org_routes.py` around lines 1239 - 1252, The plan update
handler in org_routes.py is letting post-commit audit failures turn a successful
downgrade into a 500 response. Move the record_audit_event call in the
update_plan flow out of the outer failure path by wrapping it in its own
best-effort try/except, similar to the existing Casbin cleanup around
get_user_roles_in_org/remove_role_from_user, and log a warning instead of
propagating so the committed plan change still returns success.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@server/routes/org_routes.py`:
- Around line 1239-1252: The plan update handler in org_routes.py is letting
post-commit audit failures turn a successful downgrade into a 500 response. Move
the record_audit_event call in the update_plan flow out of the outer failure
path by wrapping it in its own best-effort try/except, similar to the existing
Casbin cleanup around get_user_roles_in_org/remove_role_from_user, and log a
warning instead of propagating so the committed plan change still returns
success.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e73d0887-9ab1-49e8-a80d-dfafb106214a

📥 Commits

Reviewing files that changed from the base of the PR and between 9e5e64f and 9f34edc.

📒 Files selected for processing (4)
  • client/src/app/org/components/OrgMembers.tsx
  • client/src/app/org/components/OrgOverview.tsx
  • client/src/app/org/components/UpgradeModal.tsx
  • server/routes/org_routes.py

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: RISKY

Reviewed the latest changes. This single-file diff introduces a SQL UPDATE that references organizations.plan_tier, a column for which no migration exists anywhere in the repository — two independent code searches returned zero results. Deploying this to production will cause a column "plan_tier" does not exist PostgreSQL error on every call to GET /api/orgs/invitations, breaking invitation management for all organizations. A secondary concern is that this destructive write (bulk-expiring all pending invitations for free-tier orgs) fires on every read of the invitations list, not just on plan-change events.

Findings

# Severity File Finding
1 HIGH server/routes/org_routes.py:663 SQL references `organizations.plan_tier` column that has no migration in the repo
2 MEDIUM server/routes/org_routes.py:663 Destructive bulk-expiry of pending invitations fires on every GET /invitations read

Aurora reviews PRs for incident prevention. This is advisory only and does not block merge.

Comment thread server/routes/org_routes.py
Comment thread server/routes/org_routes.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
server/routes/org_routes.py (2)

1247-1262: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Post-commit audit failure returns 500 for an already-applied change.

conn.commit() at Line 1247 persists the tier change, but record_audit_event at Line 1256 runs unguarded inside the same try. If it raises, the handler returns 500 "Failed to update plan" (and logs an exception) even though the downgrade already succeeded, misleading the caller. Guard the audit call like the Casbin cleanup already is.

Proposed fix
-        record_audit_event(org_id, user_id, "update_plan", "organization", org_id,
-                           {"old_tier": old_tier, "new_tier": new_tier}, request)
+        try:
+            record_audit_event(org_id, user_id, "update_plan", "organization", org_id,
+                               {"old_tier": old_tier, "new_tier": new_tier}, request)
+        except Exception as e:
+            logger.warning("Failed to record plan-update audit event for org %s: %s", org_id, e)
🤖 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 `@server/routes/org_routes.py` around lines 1247 - 1262, The plan update flow
in update_plan currently treats record_audit_event as part of the main success
path, so an audit failure after conn.commit() makes the endpoint return a 500
even though the tier change already succeeded. Move the audit call out of the
main failure path or wrap it in its own try/except, similar to the Casbin
cleanup loop, so the response still returns the updated planTier when the commit
succeeds. Use the update_plan handler and record_audit_event call as the key
places to adjust.

1176-1241: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Restrict plan downgrades to the creator or preserve the caller

@require_permission("org", "manage") lets any org admin reach this path, but the cleanup only exempts creator_id. A non-creator admin who downgrades the org will be removed from the org and have their tokens/connections purged, which effectively locks them out. Gate this on user_id == creator_id or change the cleanup to preserve the actor instead of hardcoding the creator.

🤖 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 `@server/routes/org_routes.py` around lines 1176 - 1241, The downgrade flow in
update_plan currently preserves only creator_id, which can purge the acting
admin if they are not the creator. Update the enterprise-to-free cleanup in
org_routes.update_plan to either require user_id == creator_id before allowing
the downgrade or treat the caller as the preserved account when deleting org
data, and make sure the user/token/connection cleanup queries and the final
role/org_id updates use that preserved actor consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@server/routes/org_routes.py`:
- Around line 1247-1262: The plan update flow in update_plan currently treats
record_audit_event as part of the main success path, so an audit failure after
conn.commit() makes the endpoint return a 500 even though the tier change
already succeeded. Move the audit call out of the main failure path or wrap it
in its own try/except, similar to the Casbin cleanup loop, so the response still
returns the updated planTier when the commit succeeds. Use the update_plan
handler and record_audit_event call as the key places to adjust.
- Around line 1176-1241: The downgrade flow in update_plan currently preserves
only creator_id, which can purge the acting admin if they are not the creator.
Update the enterprise-to-free cleanup in org_routes.update_plan to either
require user_id == creator_id before allowing the downgrade or treat the caller
as the preserved account when deleting org data, and make sure the
user/token/connection cleanup queries and the final role/org_id updates use that
preserved actor consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 26c213ca-acd2-46c6-8bf7-18d65cdd9203

📥 Commits

Reviewing files that changed from the base of the PR and between 9f34edc and 40f3603.

📒 Files selected for processing (1)
  • server/routes/org_routes.py

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@server/routes/org_routes.py`:
- Around line 1183-1210: The downgrade cleanup in the org removal flow does not
handle a missing creator because the queries in the member-purge path use
creator_id from the created_by field, so NULL makes the filters skip all rows.
Update the org downgrade logic around the cleanup helper used by this route to
either reject the free-tier downgrade when organizations.created_by is absent or
fall back to purging all non-owner members, and make sure the DELETE/UPDATE
statements and _purge_vault_secrets handling still target the correct users.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8e79ecc1-4fb7-4330-be50-96b45fef87ff

📥 Commits

Reviewing files that changed from the base of the PR and between 40f3603 and a64decd.

📒 Files selected for processing (1)
  • server/routes/org_routes.py

Comment thread server/routes/org_routes.py
Comment thread client/src/app/org/components/OrgMembers.tsx
Comment thread client/src/app/org/components/UpgradeModal.tsx Outdated
Comment thread server/routes/org_routes.py
Comment thread server/utils/hooks.py
Comment thread server/utils/hooks.py

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@sonarqubecloud

sonarqubecloud Bot commented Jul 4, 2026

Copy link
Copy Markdown

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.

3 participants