Skip to content

feat(settings): configurable EC2 RI OfferingClass (closes #694) - #847

Merged
cristim merged 11 commits into
mainfrom
fix/694-wave14
Jul 17, 2026
Merged

feat(settings): configurable EC2 RI OfferingClass (closes #694)#847
cristim merged 11 commits into
mainfrom
fix/694-wave14

Conversation

@cristim

@cristim cristim commented May 28, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds a GlobalConfig.OfferingClass setting ("convertible" | "standard") that controls which EC2 Reserved Instance class is purchased; empty / absent values default to "convertible" preserving pre-694 behaviour
  • Migration 000064 adds offering_class TEXT NOT NULL DEFAULT 'convertible' to global_config
  • Frontend: new fieldset in Settings with a dropdown; load, save, and reset wired; <select> values hardcoded in HTML so no innerHTML XSS surface
  • Unknown DB values fail loudly at purchase time (resolveOfferingClassType returns an explicit error) per feedback_empty_string_vs_error.md

Test plan

  • go build ./... clean
  • go test github.com/LeanerCloud/CUDly/providers/aws/services/ec2/... github.com/LeanerCloud/CUDly/internal/config/... -- 601 passed
  • npx tsc --noEmit -- no errors
  • npx jest -- 2142 passed, 0 failed
  • Migration 000064 confirmed present (up + down)
  • resolveOfferingClassType("") returns OfferingClassTypeConvertible, nil
  • resolveOfferingClassType("unknown") returns "", error
  • saveGlobalSettings test updated to assert offering_class: 'convertible' in payload

Summary by CodeRabbit

  • New Features

    • Added a new EC2 Reserved Instance class setting, letting users choose between Convertible and Standard purchases.
    • The selected class is saved and restored in settings, with Convertible as the default.
  • Bug Fixes

    • Improved purchase processing so missing configuration no longer silently falls back during execution.
    • Added stronger validation and clearer handling for invalid class values.
  • Tests

    • Updated and expanded coverage for settings persistence, configuration validation, database storage, and purchase behavior.

@cristim cristim added triaged Item has been triaged priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/eventually No deadline impact/few Limited audience effort/m Days type/feat New capability labels May 28, 2026
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 40a8ae47-ed18-4460-800d-ecbed008812d

📥 Commits

Reviewing files that changed from the base of the PR and between a069a07 and d8ded22.

📒 Files selected for processing (13)
  • frontend/src/__tests__/settings.test.ts
  • frontend/src/api/types.ts
  • frontend/src/index.html
  • frontend/src/settings.ts
  • frontend/src/types.ts
  • internal/config/store_postgres.go
  • internal/config/store_postgres_coverage_test.go
  • internal/config/store_postgres_pgxmock_test.go
  • internal/config/types.go
  • internal/config/validation.go
  • internal/config/validation_test.go
  • internal/database/postgres/migrations/000090_ec2_ri_offering_class.down.sql
  • internal/database/postgres/migrations/000090_ec2_ri_offering_class.up.sql
📝 Walkthrough

Walkthrough

Adds EC2 Reserved Instance offering-class selection across the admin UI, typed configuration, PostgreSQL persistence, validation, purchase execution, and AWS offering lookup. Convertible remains the default; standard is accepted as an alternative.

Changes

Offering Class Feature

Layer / File(s) Summary
Frontend settings UI and payload wiring
frontend/src/index.html, frontend/src/api/types.ts, frontend/src/types.ts, frontend/src/settings.ts, frontend/src/__tests__/settings.test.ts
Adds the Convertible/Standard setting, loads and normalizes its value, includes it in configuration updates, resets it to Convertible, and updates the settings test expectation.
Config model, validation, migrations, and Postgres persistence
internal/config/*, internal/database/postgres/migrations/*
Adds OfferingClass to backend configuration, validates accepted values, creates the global_config column with a Convertible default, persists and reads it, and updates database coverage.
Purchase execution error flow and option propagation
pkg/common/types.go, internal/purchase/execution.go, internal/purchase/*_test.go
Adds PurchaseOptions.OfferingClass, loads the runtime configuration before recommendation processing, propagates the value, and returns fatal configuration-load errors without starting provider calls.
EC2 offering-class resolution and SDK request mapping
providers/aws/services/ec2/client.go, providers/aws/services/ec2/client_test.go
Resolves Convertible and Standard values, passes the resolved class to EC2 offering queries, preserves Convertible defaults for non-purchase paths, and tests request propagation.

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

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant SettingsAPI
  participant ConfigStore
  participant PurchaseExecution
  participant EC2Client
  Admin->>SettingsAPI: save offering_class
  SettingsAPI->>ConfigStore: persist GlobalConfig
  PurchaseExecution->>ConfigStore: load GlobalConfig
  ConfigStore-->>PurchaseExecution: OfferingClass
  PurchaseExecution->>EC2Client: pass PurchaseOptions.OfferingClass
  EC2Client->>EC2Client: resolve offering class
  EC2Client-->>PurchaseExecution: DescribeReservedInstancesOfferings result
Loading

Possibly related PRs

  • LeanerCloud/CUDly#690: Refactors the EC2 offering lookup path that this change extends with configurable offering-class propagation.
  • LeanerCloud/CUDly#1355: Updates related global configuration persistence and merge paths.

Suggested labels: priority/p2, severity/medium, urgency/this-sprint, impact/many

🚥 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 clearly summarizes the main change: adding configurable EC2 RI OfferingClass settings.
Docstring Coverage ✅ Passed Docstring coverage is 89.29% which is sufficient. The required threshold is 80.00%.
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 fix/694-wave14

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

@cristim

cristim commented May 28, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 30, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@cristim

cristim commented Jun 3, 2026

Copy link
Copy Markdown
Member Author

pr-iterate: CR appears to be blocked by org-level usage limits (BILLING_BLOCKED marker set in ~/.claude/agent-comms/cr-rate-limit-deadline.txt); this PR is otherwise merge-ready (mergeStateStatus=CLEAN, CI=5/5 green, all triage labels mirrored). Re-invoke /pr-iterate 847 after the org's CR billing is topped up to get a substantive CR pass. To clear after billing is fixed: rm ~/.claude/agent-comms/cr-rate-limit-deadline.txt.

@cristim

cristim commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Rate Limit Exceeded

@cristim have exceeded the limit for the number of chat messages per hour. Please wait 37 minutes and 41 seconds before sending another message.

@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

Rebased on feat/multicloud-web-frontend. Resolved additive conflict in providers/aws/services/ec2/client_test.go (kept both HEAD's Name-tag tests and PR's OfferingClass tests).

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

@cristim, kicking off a review of the rebased PR now.


🧠 Learnings used
Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-05-05T15:44:54.463Z
Learning: In the LeanerCloud/CUDly repository, when a CodeRabbit review flags something as "outside-diff" that was already implemented in an earlier commit of the same PR, it is likely a stale-snapshot artifact where the review diff was generated against a pre-fix view. The inline comment convention `(CR pass on PR #<number> Finding N)` is used by the maintainer (cristim) to mark lines that were changed in direct response to a prior CodeRabbit review pass.
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@cristim

cristim commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

cristim added a commit that referenced this pull request Jun 8, 2026
PR #808 keeps 000068 and PR #847 takes 000069; bump this branch's
purchase_history_revocation migration to 000070 to avoid conflicts
on feat/multicloud-web-frontend.
cristim added a commit that referenced this pull request Jun 8, 2026
PR #808 keeps 000068 and PR #847 takes 000069; bump this branch's
purchase_history_revocation migration to 000070 to avoid conflicts
on feat/multicloud-web-frontend.
@cristim

cristim commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🧹 Nitpick comments (1)
internal/database/postgres/migrations/000078_ec2_ri_offering_class.up.sql (1)

5-6: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

Optional: consider a CHECK constraint for defense-in-depth.

The column currently has no DB-level constraint on allowed values, relying entirely on app-layer validation (validateOfferingClass). A direct UPDATE global_config SET offering_class = 'foo' via psql would silently persist an invalid value that only surfaces as an error later at purchase time (per resolveOfferingClassType).

🛡️ Optional CHECK constraint
 ALTER TABLE global_config
   ADD COLUMN IF NOT EXISTS offering_class TEXT NOT NULL DEFAULT 'convertible';
+
+ALTER TABLE global_config
+  ADD CONSTRAINT global_config_offering_class_check
+  CHECK (offering_class IN ('convertible', 'standard'));

Skip if the team intends to keep the value set open-ended without a migration for future classes.

🤖 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/database/postgres/migrations/000078_ec2_ri_offering_class.up.sql`
around lines 5 - 6, Add a DB-level CHECK constraint for
global_config.offering_class in this migration so only the supported offering
class values can be stored, instead of relying solely on validateOfferingClass
and resolveOfferingClassType. Update the migration that alters global_config to
include the constraint alongside the existing offering_class column definition,
using the same allowed values enforced by the app.
🤖 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/database/postgres/migrations/000078_ec2_ri_offering_class.up.sql`:
- Around line 5-6: Add a DB-level CHECK constraint for
global_config.offering_class in this migration so only the supported offering
class values can be stored, instead of relying solely on validateOfferingClass
and resolveOfferingClassType. Update the migration that alters global_config to
include the constraint alongside the existing offering_class column definition,
using the same allowed values enforced by the app.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b979982a-e00d-4265-bddd-753143d78382

📥 Commits

Reviewing files that changed from the base of the PR and between 1f83f43 and a069a07.

📒 Files selected for processing (19)
  • frontend/src/__tests__/settings.test.ts
  • frontend/src/api/types.ts
  • frontend/src/index.html
  • frontend/src/settings.ts
  • frontend/src/types.ts
  • internal/config/store_postgres.go
  • internal/config/store_postgres_coverage_test.go
  • internal/config/store_postgres_pgxmock_test.go
  • internal/config/types.go
  • internal/config/validation.go
  • internal/config/validation_test.go
  • internal/database/postgres/migrations/000078_ec2_ri_offering_class.down.sql
  • internal/database/postgres/migrations/000078_ec2_ri_offering_class.up.sql
  • internal/purchase/execution.go
  • internal/purchase/execution_test.go
  • internal/purchase/money_path_regression_test.go
  • pkg/common/types.go
  • providers/aws/services/ec2/client.go
  • providers/aws/services/ec2/client_test.go
💤 Files with no reviewable changes (2)
  • providers/aws/services/ec2/client.go
  • providers/aws/services/ec2/client_test.go
✅ Files skipped from review due to trivial changes (2)
  • frontend/src/types.ts
  • frontend/src/index.html
🚧 Files skipped from review as they are similar to previous changes (11)
  • internal/purchase/money_path_regression_test.go
  • internal/config/validation_test.go
  • internal/purchase/execution_test.go
  • internal/config/types.go
  • pkg/common/types.go
  • frontend/src/settings.ts
  • internal/config/validation.go
  • frontend/src/api/types.ts
  • frontend/src/tests/settings.test.ts
  • internal/config/store_postgres.go
  • internal/purchase/execution.go

@cristim

cristim commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

cristim added 11 commits July 17, 2026 19:39
Add a GlobalConfig.OfferingClass field ("convertible" | "standard") that
controls which EC2 Reserved Instance offering class is purchased. Empty /
absent values default to "convertible" to preserve pre-694 behaviour.

Backend:
- pkg/common/types.go: OfferingClass field on PurchaseOptions
- internal/config/types.go: OfferingClass on GlobalConfig
- internal/config/store_postgres.go: read/write offering_class column ($20)
- internal/purchase/execution.go: load GlobalConfig and propagate
  OfferingClass into PurchaseOptions before the fan-out
- providers/aws/services/ec2/client.go: resolveOfferingClassType() fails
  loudly on unknown values (feedback_empty_string_vs_error.md); empty
  string maps to convertible so the DB default is safe
- internal/database/postgres/migrations/000064_ec2_ri_offering_class: ADD
  COLUMN offering_class TEXT NOT NULL DEFAULT 'convertible'

Frontend:
- frontend/src/index.html: fieldset with <select> (Convertible / Standard)
- frontend/src/settings.ts: load, save, and reset handlers
- frontend/src/api/types.ts + types.ts: offering_class optional field

Tests:
- TestResolveOfferingClassType: unknown values error, "" = convertible
- TestDescribeInputFromQuery_OfferingClass: empty / explicit convertible / standard
- All findOfferingID call sites updated to 4-arg signature
- store_postgres_pgxmock_test.go: +offering_class column in mock rows
- settings.test.ts: offering_class: 'convertible' in saveGlobalSettings
  expected payload
…EC2 SDK call (refs #694)

- Add validateOfferingClass() to GlobalConfig.Validate() so an invalid
  offering_class is rejected at PUT time with a clear error rather than
  silently persisting and only failing at purchase time. Accepts "" |
  "convertible" | "standard" (case-sensitive, matching resolveOfferingClassType).
- Add ValidOfferingClasses exported var for reference/documentation.
- Add six table-driven test cases in TestGlobalConfig_Validate covering
  empty (valid), both valid values, wrong-case "Convertible", "STANDARD",
  and an unknown value.
- Add capturingMockEC2Client embedding MockEC2Client that records the last
  DescribeReservedInstancesOfferingsInput to enable SDK-level assertions.
- Add TestFindOfferingID_OfferingClassReachesSDKCall: three subtests
  ("", "convertible", "standard") each calling findOfferingID and asserting
  that the captured OfferingClass on the outbound SDK call equals the
  expected types.OfferingClassType. This test fails if the wiring from
  offeringClassStr through resolveOfferingClassType to describeInputFromQuery
  regresses.
…cyclomatic complexity

Validate had complexity 11 after adding the OfferingClass check in #694.
Extract the CollectionSchedule + NotificationDaysBefore + GracePeriodDays
checks into validateScheduleAndNotifications, keeping Validate under 10.
…sSDKCall

Construct capturingMockEC2Client directly instead of copying *MockEC2Client
to silence the go vet copylocks warning (MockEC2Client embeds mock.Mock
which contains sync.Mutex).
… defaulting OfferingClass

When GetGlobalConfig returns an error, the old code logged it and continued
with an empty OfferingClass, which resolveOfferingClassType maps to
"convertible". This caused a transient DB failure to silently buy the wrong
(and more expensive, irreversible) RI class instead of the operator-configured
"standard". Violates the no-silent-fallbacks-on-money-paths rule.

Fix: change processPurchaseRecommendations to return (float64, float64, []string, error)
and propagate a hard error on GetGlobalConfig failure. Both call sites
(executeSingleAccount and executeForAccount) check the new error return and
abort without making any cloud purchase.

Regression test (HOLE 1): TestProcessPurchaseRecommendations_GlobalConfigError_FailsInsteadOfDefaulting
confirms the function returns an error and never calls the provider factory
when GetGlobalConfig fails. Verified red on pre-fix code, green after.

Also add TestSaveGlobalConfig_OfferingClassBindsAt21 (HOLE 2): a pgxmock test
against the real PostgresStore.SaveGlobalConfig verifying offering_class binds
as the 21st positional arg. The hand-maintained testablePostgresStore in
store_postgres_mock_test.go omits this field entirely, so no fast test
previously guarded the 21-placeholder write query.
…ount below gocyclo 10

The gocyclo pre-commit hook (-over 10) failed: executeForAccount was at
cyclomatic complexity 11. Extract the per-account status-resolution switch
(partially_completed / failed / completed stamping, #642) and the committed
gate (#1014) into a cohesive applyAccountOutcome helper, dropping the function
below the threshold without a //nolint or a threshold bump.

Behavior is unchanged: same status transitions, same error-note appending, same
committed semantics (anyRecPurchased is now evaluated once and reused for the
partial flag). The OfferingClass typed-enum validation and no-silent-fallback
behavior are untouched.
Rebasing onto main added laddering_enabled as $21 in global_config INSERT,
shifting offering_class from $21 to $22. Update the pgxmock and coverage
tests to reflect the new column count and binding positions.
Resolve the three golangci-lint findings that --new-from-rev=origin/main
attributes to the #694 OfferingClass changes:

- errcheck: replace the silent `_ =` discard of SavePurchaseExecution on
  the processPurchaseRecommendations error path with the existing
  saveExecutionStatusBestEffort helper, which persists and logs the
  audit-save failure instead of dropping it.
- gocritic unnamedResult: name the four results of
  processPurchaseRecommendations (its return set grew to include error);
  switch the trailing assignment from := to = accordingly.
- misspell: pre-694 behaviour -> behavior in the ValidOfferingClasses doc.

No behavior change to the purchase path; base-debt Lint/Security failures
are pre-existing on main and out of scope.
Migration 000078 collided with PR #828. Main's highest is 000081;
#1277 reserves 000082; 000083 is the next free slot for this PR.

Renamed via git mv (up + down); no Go code referenced the number directly.
Migration 000083 is now taken by ladder_execution_enabled (merged to main
while this PR was in review). Next free slot after 000089_rename_cancelled_to_canceled
is 000090.
…uard test

Two issues introduced when rebasing onto main (which added ladder_execution_enabled
in parallel):

1. saveExecutionStatusBestEffort helper was dropped during conflict resolution of
   the applyAccountOutcome refactor commit; restored from the pre-rebase branch.

2. TestSaveGlobalConfig_OfferingClassBindsAt22 expected 22 args; with
   ladder_execution_enabled now at $22, offering_class moved to $23. Renamed
   the test to TestSaveGlobalConfig_OfferingClassBindsAt23 and added the
   $22 AnyArg placeholder.
@cristim

cristim commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
cristim merged commit bc4d3ae into main Jul 17, 2026
20 checks passed
@cristim
cristim deleted the fix/694-wave14 branch July 27, 2026 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/few Limited audience priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/feat New capability urgency/eventually No deadline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant