Skip to content

feat(settings): persist extension runtime settings - #637

Open
SantiagoDePolonia wants to merge 3 commits into
mainfrom
feat/runtime-extension-settings
Open

feat(settings): persist extension runtime settings#637
SantiagoDePolonia wants to merge 3 commits into
mainfrom
feat/runtime-extension-settings

Conversation

@SantiagoDePolonia

@SantiagoDePolonia SantiagoDePolonia commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a generic runtime-setting contract for extensions
  • persist deployment-wide values in SQLite, PostgreSQL, or MongoDB
  • expose validated GET/PUT admin endpoints and render registered settings in Dashboard → Settings
  • keep environment-managed settings visible but read-only

Why

GoModel Pro needs a deployment-wide prompt-compression level that can change at runtime without putting Pro-specific behavior into open core or browser-local storage.

Verification

  • go test ./...
  • npm test
  • npm run check
  • npm run build
  • pre-commit test-race, lint, dist-sync, and fix checks

Summary by CodeRabbit

  • New Features
    • Added a dashboard page for viewing and updating extension-provided runtime settings.
    • Settings support descriptions, selectable values, validation, persistence, and management status.
    • Added admin API support for listing and updating runtime settings.
    • Added SQL and MongoDB-backed setting storage.
    • Environment-managed settings are displayed as read-only and cannot be changed through the dashboard.
    • Settings synchronize across application instances and restore saved values automatically.

Copilot AI review requested due to automatic review settings August 3, 2026 10:09

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: defd8301-25c2-4639-bb7b-dff104cf0451

📥 Commits

Reviewing files that changed from the base of the PR and between c6e06a9 and 8b02639.

📒 Files selected for processing (3)
  • internal/runtimesettings/service_test.go
  • internal/runtimesettings/store_mongodb_test.go
  • internal/runtimesettings/sync.go

📝 Walkthrough

Walkthrough

The change adds extension-defined runtime settings. It introduces registry support, SQL and MongoDB persistence, synchronized validation and updates, admin API routes, application wiring, and a dashboard settings interface.

Changes

Runtime settings

Layer / File(s) Summary
Setting contracts and registry
ext/ext.go, ext/registry.go, ext/registry_test.go
Adds setting descriptors, options, the RuntimeSetting interface, synchronized registration, defensive snapshots, and registry tests.
Persistence and setting service
internal/runtimesettings/*
Adds SQL and MongoDB stores plus a service that restores, validates, updates, persists, synchronizes, rolls back, locks, lists, and closes runtime settings.
Application and admin integration
internal/app/app.go, internal/admin/...
Initializes the service, injects it into admin handlers, exposes listing and update routes, maps errors, and tests the API flow.
Dashboard settings interface
web/dashboard/src/pages/settings/RuntimeSettings.svelte, web/dashboard/src/pages/settings/SettingsPage.svelte
Adds runtime setting loading, editing, saving, error handling, lock indicators, responsive styling, and settings-panel integration.

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

Sequence Diagram(s)

sequenceDiagram
  participant Dashboard
  participant AdminHandler
  participant RuntimeSettingsService
  participant RuntimeSettingsStore
  Dashboard->>AdminHandler: Request runtime setting descriptors
  AdminHandler->>RuntimeSettingsService: List settings
  RuntimeSettingsService-->>AdminHandler: Ordered descriptors
  AdminHandler-->>Dashboard: Settings response
  Dashboard->>AdminHandler: Update setting key and value
  AdminHandler->>RuntimeSettingsService: Validate and apply update
  RuntimeSettingsService->>RuntimeSettingsStore: Persist value
  RuntimeSettingsStore-->>RuntimeSettingsService: Save result
  RuntimeSettingsService-->>AdminHandler: Updated descriptor
  AdminHandler-->>Dashboard: Update response
Loading

Possibly related PRs

  • ENTERPILOT/GoModel#186: Both modify internal/admin/handler.go and internal/app/app.go to expose and wire dashboard-wide runtime configuration.
  • ENTERPILOT/GoModel#454: Both add deployment-wide dashboard-managed runtime settings with persistence and managed-state handling.

Suggested reviewers: copilot

Poem

A rabbit tunes the settings bright,
With stored values set just right.
Locked fields rest, unchanged and still,
While dashboards hop across the hill.
The registry keeps each choice in sight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% 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 and concisely describes the main change: persisting extension runtime settings.
Description check ✅ Passed The description explains the changes, motivation, and verification steps, although it uses Summary instead of the template's Description heading.
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/runtime-extension-settings

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.

@codecov-commenter

codecov-commenter commented Aug 3, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 61.75115% with 83 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/runtimesettings/service.go 60.71% 18 Missing and 15 partials ⚠️
internal/runtimesettings/store_mongodb.go 16.66% 15 Missing ⚠️
internal/runtimesettings/sync.go 68.88% 12 Missing and 2 partials ⚠️
internal/app/app.go 20.00% 5 Missing and 3 partials ⚠️
internal/runtimesettings/store_sql.go 63.63% 4 Missing and 4 partials ⚠️
internal/admin/handler_runtime_settings.go 83.33% 3 Missing and 1 partial ⚠️
ext/registry.go 88.88% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Aug 3, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex attempted to run the PostgreSQL/MongoDB multi-instance path but could not proceed because required services and tools were unavailable.
  • T-Rex produced a proof for the posted P1 finding.
  • The PostgreSQL/MongoDB service-backed path is blocked because psql, mongosh, docker, and necessary sockets are missing, with the divergence supported by code and by the SQLite analogue.
  • Remaining work is to rerun the harness against two independently constructed services sharing a real PostgreSQL or MongoDB backend, capture a fresh before/after, and replace the stale after log.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (1)

  1. General comment

    P1 Runtime-setting updates do not synchronize live state to already-running instances

    • Bug
      • At internal/runtimesettings/service.go:101-104, Update applies the selected value to the local RuntimeSetting instance and then persists it. Existing peer Service instances do not read again from the store and there is no notification/polling mechanism, so they continue serving their prior in-memory setting until reinitialization/restart.
    • Cause
      • Runtime settings are loaded from storage only during New (internal/runtimesettings/service.go:60-68). Store.Set in the SQL and Mongo stores only writes persistence; neither backend implementation emits a cross-instance invalidation or invokes peer Apply methods.
    • Fix
      • Add an explicit cross-instance synchronization mechanism (for example, database notifications/change streams or a shared pub/sub channel) that causes each instance to validate and call Apply after successful updates; alternatively define settings as restart-only and return that behavior explicitly. Preserve local rollback behavior when persistence/synchronization fails.

    T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "feat(settings): persist extension runtim..." | Re-trigger Greptile

Comment on lines +101 to +104
if err := setting.Apply(value); err != nil {
return ext.SettingDescriptor{}, fmt.Errorf("%w: %v", ErrInvalid, err)
}
if err := s.store.Set(ctx, key, setting.Descriptor().Value); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Runtime state diverges across instances

Update invokes Apply only on the RuntimeSetting held by the process that received the admin request, then persists the selected value. Already-running peers sharing the same PostgreSQL or MongoDB backend do not reload the stored value and have no invalidation or notification path, so they continue serving the old live setting until restart. In a multi-instance deployment, requests can therefore receive different behavior depending on which instance handles them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in c6e06a9. Runtime settings now reconcile from the shared backend every two seconds on each instance, outside the request path. Reconciliation compares the stored and live values before Apply, so unchanged values do not reset compaction epochs. Added a two-service shared-SQLite convergence test and deduplicated repeated sync errors.

@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: 5

🤖 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/admin/handler_runtime_settings_test.go`:
- Around line 60-99: Add test cases alongside TestRuntimeSettingsListAndUpdate
and TestRuntimeSettingManagedByEnvironmentIsReadOnly covering unknown-key PUTs
returning 404 with runtime_setting_not_found, invalid option values returning
400, and GET/PUT requests on a handler without WithRuntimeSettings returning the
feature-unavailable response. Reuse the existing Echo route setup and runtime
settings test helpers, and verify the setting remains unchanged where
applicable.

In `@internal/runtimesettings/service_test.go`:
- Around line 48-104: Add a test alongside TestServicePersistsAndRestoresSetting
that uses a stub Store whose Set method returns an error, then calls
Service.Update and verifies the setting’s value is restored to its previous
state via Apply. Assert the update returns the store error while preserving the
existing locked and persistence test coverage.

In `@internal/runtimesettings/service.go`:
- Around line 31-72: Reject non-locked settings with empty Options during
registration in Service.New, returning a startup error immediately after the
descriptor.Locked check; update ext/ext.go documentation for
SettingDescriptor/RuntimeSetting to state that Options must include every
accepted value and that empty Options makes an unlocked setting non-editable.
Apply the service.go change at lines 31-72 and the documentation change in
ext/ext.go at lines 84-113.
- Around line 87-111: Update the Service.Update method to add the same
nil-receiver guard used by List and Close before accessing s.mu or other fields.
Return the established nil-service error consistently, while preserving the
existing update behavior for non-nil receivers.

In `@web/dashboard/src/pages/settings/RuntimeSettings.svelte`:
- Around line 37-38: Update the select disabled-state logic in the settings UI
so every select is disabled whenever any save is in flight, not only when
savingKey matches that setting. Keep locked settings disabled as before, and
ensure the save guard in save remains consistent with this global in-flight
behavior.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cf009c00-ad9d-474f-8eb7-4cc190dd07f7

📥 Commits

Reviewing files that changed from the base of the PR and between 9d54827 and 6fc6415.

⛔ Files ignored due to path filters (4)
  • internal/admin/dashboard/static/dist/assets/index-6sHfhgfb.js is excluded by !**/dist/**
  • internal/admin/dashboard/static/dist/assets/index-B-Rv4AUL.js is excluded by !**/dist/**
  • internal/admin/dashboard/static/dist/assets/index-B_MQg975.css is excluded by !**/dist/**
  • internal/admin/dashboard/static/dist/index.html is excluded by !**/dist/**
📒 Files selected for processing (16)
  • ext/ext.go
  • ext/registry.go
  • ext/registry_test.go
  • internal/admin/handler.go
  • internal/admin/handler_runtime_settings.go
  • internal/admin/handler_runtime_settings_test.go
  • internal/admin/routes.go
  • internal/admin/routes_test.go
  • internal/app/app.go
  • internal/runtimesettings/service.go
  • internal/runtimesettings/service_test.go
  • internal/runtimesettings/store.go
  • internal/runtimesettings/store_mongodb.go
  • internal/runtimesettings/store_sql.go
  • web/dashboard/src/pages/settings/RuntimeSettings.svelte
  • web/dashboard/src/pages/settings/SettingsPage.svelte

Comment thread internal/admin/handler_runtime_settings_test.go
Comment thread internal/runtimesettings/service_test.go Outdated
Comment thread internal/runtimesettings/service.go
Comment thread internal/runtimesettings/service.go
Comment thread web/dashboard/src/pages/settings/RuntimeSettings.svelte
Copilot AI review requested due to automatic review settings August 3, 2026 13:13

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@internal/runtimesettings/store_mongodb_test.go`:
- Around line 11-29: Extend TestMongoDBStoreRoundTrip with a nil-database call
to NewMongoDBStore and assert that it returns an error, covering the
constructor’s nil-database rejection while preserving the existing
mongotest-backed round-trip checks.

In `@internal/runtimesettings/sync.go`:
- Around line 39-71: Update Service.sync to continue iterating through all keys
after store.Get or setting.Apply fails, while recording each failure and
returning an aggregate error after the loop. Preserve the existing invalid-value
handling and successful application behavior, and include each failure’s setting
key and underlying error in the aggregate.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 004930c0-6783-4be5-8804-c045f4be5749

📥 Commits

Reviewing files that changed from the base of the PR and between 6fc6415 and c6e06a9.

⛔ Files ignored due to path filters (2)
  • internal/admin/dashboard/static/dist/assets/index-D6HB9TkL.js is excluded by !**/dist/**
  • internal/admin/dashboard/static/dist/index.html is excluded by !**/dist/**
📒 Files selected for processing (11)
  • ext/ext.go
  • internal/admin/handler_runtime_settings.go
  • internal/admin/handler_runtime_settings_test.go
  • internal/runtimesettings/service.go
  • internal/runtimesettings/service_test.go
  • internal/runtimesettings/store.go
  • internal/runtimesettings/store_mongodb.go
  • internal/runtimesettings/store_mongodb_test.go
  • internal/runtimesettings/store_sql.go
  • internal/runtimesettings/sync.go
  • web/dashboard/src/pages/settings/RuntimeSettings.svelte

Comment thread internal/runtimesettings/store_mongodb_test.go
Comment thread internal/runtimesettings/sync.go
Copilot AI review requested due to automatic review settings August 3, 2026 13:30

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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