Repository navigation
AI rules: a rule with no Runner of its own shows the Global Runner, where OneUptime AI runs no Bash commands - #5252
Merged
Merged
Conversation
…r, and says no Bash command runs there - A rule that picks none reads Global Runner wherever the project uses global Runners and the server has one, as a runbook step and a code repository do; picking it stores none, so nothing changes for a rule that saved No Runner. OneUptime AI still runs no Bash commands for it: a shell is never run on a host every project shares. - The line under the picker says so, with the way on: pick one of your Runners, or add one under Runbooks > Runners where the project has none. - No Runner stays where there is no Global Runner to show (global Runners off, a server with none) and for an older rule that composes commands on its Command Runners. - A rule's choices read the global Runners and the project's switch, each on its own; the field's line no longer says inside your network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er, where OneUptime AI runs no Bash commands, in 17 languages - AI SRE: the rule's Runner lists your Runners and Global Runner; a new rule starts on the project's default, else Global Runner; no Bash command runs there; No Runner where the project or server has no global Runner. - Upgrading: the rule Runner note says what a rule that picked none reads. - Runbooks > Runners: the Global Runner table gains a row for OneUptime AI's Bash commands (never on a global Runner). - The docs facts suites pin the new sentences and the table row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…at 1280px and 390px, light and dark, in German and Persian - The AI rules fixture serves the global Runners from their own route and the project's switch (?globalRunners=0|disconnected, ?useGlobalRunners=0), and Persian right to left (?lang=fa). - The Runner tests follow the Global Runner default: going back to none is picking it (null saved), global Runners off reads No Runner and clears, no Runners shows the Global Runner with where to add one. - Prettier and the loop tests read module state through functions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, light and dark - Global Runners: in a project with no Runner of its own, the JavaScript step's field on Global Runner and the Bash step's 'needs a Runner of your own' line, with the open menu on the screen, at both widths and both themes. - Code: a repository's Runner field on Global Runner in dark mode, at a laptop's and a phone's width (the suite's two projects). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ngine never asks for a global Runner A rule that saved no Runner - shown as Global Runner in its form - is read as none: OneUptime AI picks a runbook as before, composes no Bash commands, and the engine reads no global Runner at all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
…, and the Global Runner reads right to left in Persian
UI review of the AI rule's Runner field on the Global Runner:
- The line under the box ("OneUptime AI runs no Bash commands on the
Global Runner, ...") was the size of the field's own description, with a
bold link, under three pickers whose hints are small (Code Repositories,
MCP Servers, LLM Provider). It is now drawn as they are: text-xs, close
under its box, a field's gap before the next field, its Runbooks ›
Runners link underlined only. Steps and code repositories keep theirs.
- In Persian the box laid "Runner سراسری · متصل" out left to right, the
shared Dropdown reading a picked label by its first, Latin, letter
(dir="auto", #5145), so "Runner" came after "Connected". DropdownOption
gains isInPageDirection, an opt-in for a label of the product's own
words: the box lays it out the page's way. Every Runner picker sets it on
the Global Runner; a Runner's own name keeps dir="auto".
Tests: the Dropdown flag; every picker's Global Runner in the page's
direction and a Runner's name in its own; each picker's line size; the
rule's lines in each state; offline browser checks that the line has the
Code Repositories hint's size and colour at 1280 and 390, light and dark,
and sits under its own box, and that the Persian box reads right to left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n the product's own words
"A Runner you do not have access to" and a step's "Unknown Runner (id)"
are the product's words as well: in Persian they start with a Latin word
("Runnerی که به آن دسترسی ندارید"), and the box drew them left to right.
They take isInPageDirection like the Global Runner; a Runner's own name
keeps reading its own direction.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, in a phone, dark mode, German and Persian Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lt-global-ui-review
…n like the hints, and the Persian box reads from the right Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 25, 2026
Merged
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
The maintainer, on an AI rule's Runner field that read No Runner with "Add a Runner under Runbooks › Runners for OneUptime AI to run commands on, then pick it here.":
Runbook steps (#5154) and Code repositories (#5062) already open on the Global Runner when nothing else is picked. An AI rule was the one Runner field that did not: a rule that picked none read No Runner, and a project without its own Runners got a nudge to install one.
What I changed, and why
An AI rule that picks no Runner now shows the Global Runner. This happens wherever the project uses global Runners and the server has one, which covers every new Cloud project. The field now works like the step and repository pickers, and like the rule's own LLM Provider field, which shows the global provider when the project has none of its own.
"global"or as a Runner id. The server already refuses a rule that names another project's Runner or a global one, so a rule still stores only its own project's Runner, or none.What the Global Runner runs for a rule, and what it never runs. A global Runner runs JavaScript steps in a sandbox that every project shares. A shell cannot be kept apart from other projects on that host, so OneUptime AI's Bash commands never run there.
For a rule on the Global Runner:
I did not weaken any layer that keeps a shell off a global Runner. A new guard block now pins every one of them (details under Tests).
A rule never follows the project's default Runner on its own. Picking a Runner in a rule is the consent for OneUptime AI's commands to run there. Making a Runner the default for runbook steps is not that consent. So:
Every other Runner field:
These already behaved as the maintainer asks. A new cross-picker test now pins all of them (details under Tests).
What changes for existing customers
Follow-up I recommend (not built here)
OneUptime AI composing JavaScript for the Global Runner. This would let a rule do real work there: calling a public API with a secret the project lets global Runners use. Examples are purging a CDN, toggling a feature flag, or scaling a SaaS service.
It needs its own design and security review before anyone builds it:
A sandbox for shell commands on shared Runners is a much larger isolation project (one VM per job). Until that exists, a shell stays on a Runner of the project's own.
Right-to-left labels in the picker box (already there before this PR, and in every Runner picker). In Persian, the box shows "Runner سراسری · متصل" laid out left to right, so a right-to-left reader meets the words in the wrong order. The open menu is correct.
The cause is the shared Dropdown's value label: it uses
dir="auto"(#5145), so an English record name keeps its start in view. A translated label that begins with a Latin word therefore takes the left-to-right direction.Recommended fix for the right-to-left lane: draw translated or composed labels in the page's direction, and keep
dir="auto"for record names.Fixed for every Runner picker in the UI review below: an opt-in
isInPageDirectionon the Dropdown's options lays the Global Runner's label out the page's way. Other dropdowns whose translated labels start with a Latin word are left for the right-to-left lane.Docs (17 languages)
Tests
Common/Tests/App/Dashboard/RunnerPickerModel.test.ts"global", the line kind (getRuleRunnerLine), the folded value, and older rules.Common/Tests/App/Dashboard/AutoRemediationRuleFields.test.tsxCommon/Tests/App/Dashboard/RunnerPicker.test.tsx: in a project with no Runner of its own, each Runner field rendered:Common/Tests/App/Dashboard/AiRulesTable.test.tsx: the field's new line, and that the field passesisGlobalRunnerShown(false only for an older commands rule) and passes null through for the Global Runner.Common/Tests/Server/Utils/Runner/GlobalRunnerChoiceGuard.test.ts: the rule's choices now read the global Runners. A new block, OneUptime AI's commands never run on a global Runner, whatever a rule shows, reads the source of each layer:canRunAiCommands.canRunAiCommands: false; the global claim serves runbook-origin jobs only.Common/Tests/Server/Services/AutoRemediationDecisionRecording.test.ts: a rule that saved no Runner (shown as Global Runner) still picks a runbook, composes no commands, and the engine never reads a global Runner (hasGlobalRunnerForRunbooksandfindGlobalRunnersare not called).AutomaticFixPullRequestsDocsandAutomaticRemediationSwitchDocspin the new sentences, and that each translation bolds its Dashboard's "Global Runner".GlobalRunnersDocsFactspins the new table row.packages/E2E/AutoRemediationRules?globalRunners=0|disconnected,?useGlobalRunners=0) and Persian (?lang=fa, right to left).packages/E2E/GlobalRunners: in a project with no Runner of its own, a JavaScript step's field on the Global Runner and a Bash step's "needs a Runner of your own" line, at 1280px and 390px, light and dark, with the menu open.packages/E2E/Code: a repository's Runner field on the Global Runner in dark mode, at both of that suite's widths. Light was already covered.What I ran
I ran all of this locally, before and after merging master (#5248). Everything passed.
Common (jest)
npx jest GuardandLocale, plus UpdateChecksReadHeldRows, DeleteChecksReadHeldRows, HookWritesCallersMayMake, ListOrderColumnModels, PermissionCatalogueCoverage, SchemaMigrationsOnlineDdl, TestSendRoutesAskTheRule and AnalyticsSortKeyPageBoundScope (214 suites).npm run compile-tests(all three programs).App (jest)
Tests/Dashboard/*Guardsuite, RunnersLiveUnderRunbooks, RunnerUi, the AI settings wiring suites, StepExecutorsGlobalRunner,Locale, and every root-levelTests/*.test.ts(55 suites).Tests/FeatureSet/Docs/Docs*suites;*Translationssuite;npm run compile.Dashboard and i18n
tsc --noEmiton the Dashboard.i18n:checkandi18n:extract: 0 new keys, no translation lost.npm run i18n:validate.Docs tooling:
docs:localize-anchorson the three pages (0 changes) anddocs:check-anchors.Lint and checks
npx prettier --checkandnpx eslint --no-ignoreon every changed file.npm run compilein packages/E2E.Offline browser suites, in Chromium, with
CI=1on ports of my owntest-auto-remediation-rules-ui(CI group 7)test-global-runners-ui, new describetest-code-ui, "a repository's Runner"Group 7 was about 16.5 minutes on master, so this takes it to about 17.5, under the 22-minute line. I did not change any workflow file.
Not run
Master failures I saw: none.
Surfaces for the UI review
cd packages/E2E && CI=1 npm run test-auto-remediation-rules-ui, ornode AutoRemediationRules/Fixture/server.js.?runners=0,?defaultRunner=prod,?globalRunners=0|disconnected,?useGlobalRunners=0,?rules=saved(the edit dialogs),?lang=de|fa,?theme=dark.output/playwright/auto-remediation-rules-ui/(runner-global-*,no-runners-global-runner,runner-global-runners-off,runner-global-deandrunner-global-fa).npm run test-global-runners-ui, screenshotssteps-no-runners-*.npm run test-code-ui, screenshotcode-repository-runner-global-dark-*.UI review
What I looked at. The AI rule's Runner field in the create and edit dialogs (Incidents and Alerts → AI → Settings → More settings → AI rules, Fix step, More fields), rendered from this PR's offline fixture with the Dashboard's Inter font at 2x. I checked it at 1280, 1024, 768 and 390px, in light and dark, and in English, German and Persian, with the menu open, in every state the fixture steers:
For comparison I also rendered master's field, the runbook step and code repository Runner pickers, and the three docs changes.
What I changed, and why
The line under the box now reads like its neighbours' hints. It was the size of the field's own description (
text-sm), with a bold link. The three pickers above it in the same fold (Code Repositories, MCP Servers, LLM Provider) have small hints, so the Runner's line read as a second description. An AI rule's line is now drawn as those hints are:text-xs;mt-1.5), with a field's gap before the next field (mb-2);A runbook step keeps the step editor's size. The code repository's Edit Settings form keeps its form-size lines: its one field has no hints beside it.
Persian: the box now reads right to left. Before, it laid "Runner سراسری · متصل" out left to right, so a reader met "Runner" after "Connected". This is what the builder's follow-up below describes.
dir="auto", Custom Ping Monitor Template Not Available During Network Device Import #5145). That is right for a record name, and wrong for the product's own words when the translation starts with a Latin loanword.DropdownOptiongains an opt-inisInPageDirection. RunnerPicker sets it on the Global Runner (open or not), on a pick the reader cannot see ("A Runner you do not have access to") and on a step's "Unknown Runner (id)".dir="auto", and no other dropdown changes.The copy is unchanged. I read every sentence against the screenshots and kept the builder's words. The line under the box stands on its own (people read it without the field's description), and every locale already carries it.
Tests I added or changed
Common/Tests/UI/Components/Dropdown.test.tsx: a label withisInPageDirectionhas nodirand still truncates. Left out, or false, the label keepsdir="auto".Common/Tests/App/Dashboard/RunnerPicker.test.tsx, new block what a Runner field shows, and its line:dir="auto";Common/Tests/App/Dashboard/AutoRemediationRuleFields.test.tsx:dir, and a picked Runner keepsdir="auto".This replaces the builder's
text-smpin.packages/E2E/AutoRemediationRules/AutoRemediationRules.spec.ts:rtland that its words follow each other from the right (German: from the left).Each new check fails on the branch as the builder left it (12 jest tests, 5 browser tests and the "one look" test) and passes now.
Screenshots (in
.github/pr-assets/runner-default-global/; its README says how they were made)German: after-de.png. The whole Fix step with More fields open, so the Runner's line can be seen beside the other hints: after-more-fields.png.
What I ran after merging master (3388931)
Everything passed.
npx jest GuardandLocale, plus UpdateChecksReadHeldRows, DeleteChecksReadHeldRows, HookWritesCallersMayMake, ListOrderColumnModels, PermissionCatalogueCoverage, SchemaMigrationsOnlineDdl, TestSendRoutesAskTheRule and AnalyticsSortKeyPageBoundScope (214 suites, 8,080 tests);ee/moved aside.Tests/Dashboard/*Guardsuite, the Runner and AI settings suites,Locale, every root-level test, and the six docs suites that read the Runner picker (61 suites, 2,293 tests).tsc --noEmitin Common, the Dashboard, App and E2E;npm run compile-tests;--listFilesin Common, App and E2E: nothing outside each package and Common.CI=1, my own ports):test-auto-remediation-rules-ui: 103 passed in 6.4 minutes. My checks add no test, only a few reads inside existing ones, so CI group 7 keeps the builder's estimate.test-global-runners-ui: 52 passed.test-code-ui, "a repository's Runner": 17 passed, plus the phone skip that was already there.npx prettier --checkandnpx eslint --no-ignoreon every file the branch changes.Not run
Master failures I saw: none.
Left alone
isInPageDirectionon each such label.🤖 Generated with Claude Code