Skip to content

AI postmortems: Postmortem rules choose which resolved incidents get a draft, and its templates - #5071

Merged
simlarsen merged 14 commits into
masterfrom
claude/postmortem-draft-rules
Oct 19, 2026
Merged

simlarsen merged 14 commits into
masterfrom
claude/postmortem-draft-rules

Conversation

@simlarsen

@simlarsen simlarsen commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Problem

"Can you please create rules for these just like we have investigation rules in more options? The rules can contain which incidents can we draft a postmortem report for, and what templates can be used?"

With Draft a postmortem when an incident resolves on, OneUptime AI drafted a postmortem for every resolved incident, always in its standard outline. A project could not keep drafts to the incidents that need one, and could not have a draft follow its own postmortem templates.

What changes

Postmortem rules, a new table under Incidents → AI → Settings → More settings. It sits after Auto remediation rules and before Daily limits, matching the order of the switches above it. The alerts page does not get it, because alerts have no postmortem.

  • A rule asks the same two questions as the other incident rules:
    • Match: the shared conditions builder, starting on All incidents. The other choice is Only incidents that match conditions on monitors, severities, labels, monitor labels, title and description. These are the investigation rules' incident fields, read by the same IncidentAlertRuleMatcher.
    • Draft:
      • Templates: none means the standard outline. With one, the draft follows it. With several (at most 10), OneUptime AI picks the best fit.
      • Name: filled in from the templates ("Draft with Database outage", "Draft with the standard outline") until you type your own.
      • Enabled: on the edit form only. A new rule starts on.
      • Description: folded under More fields.
  • The table is drag-ordered (@ListOrderColumn) and shows Name, Match Criteria, Templates and Status. The folded header lists the card and counts enabled rules as a chip. The defaults line now says drafts happen too.
  • The draft job (IncidentPostmortemRunner) asks PostmortemRules.getIncidentDraftPlan before it waits on call transcripts:
    • No enabled rule: drafts as before.
    • Otherwise the first enabled rule that matches decides, from the top of the list. No match means no draft.
    • Rules or templates that cannot be read also mean no draft.
    • A draft that waited for its call's transcript reads the rules again when it is written.
    • The chosen template's outline goes into the existing generatePostmortemFromAI(template). The feed post says ", following the postmortem template Name".
  • Template pick (PostmortemTemplatePick): with several templates, one small LLM call (16 output tokens, feature "Incident Postmortem", logged in AI Logs) answers with a number. If it names none, or the call fails, the draft uses the first template by name. It is registered in the kill-switch and prompt-text guard registries.
  • Server checks (AIPostmortemRuleService): every template, monitor, severity and label a rule names must belong to the project. More than 10 templates is refused before any lookup. Only Project Owner and Project Admin can create, edit or delete rules; members and viewers can read them, the same as investigation rules.
  • Plans: postmortem templates need the Growth plan on OneUptime Cloud. For a project known to be below it, the dashboard hides the picker and the column and uses a card description without templates. The server ignores a rule's templates below the plan, so the draft follows the standard outline. The rule model itself has no plan gate.
  • Shared table change (BaseModelTable): on every drag-ordered table, someone without update permission now sees greyed-out grips with the Edit button's permission tooltip. Before, a viewer could drag a row, the server refused it, and the rows jumped back.
  • Migration 1804200000000-AddAIPostmortemRules adds AIPostmortemRule, its relation tables and the templates join table. It writes no rows.
  • Docs, in all 17 languages:
    • Postmortems has a new section, "Choose which incidents get a draft, and its template", and a troubleshooting reason.
    • AI SRE: Auto-postmortem describes the rules, and the Cost controls fold sentence names the third rules table.
    • Incident Settings names Postmortem Rules as a third table under More settings.

Decisions I made

  • The first match decides, in drag order. Matches are not pooled, because a rule's templates are what it is for. A narrow rule ("SEV1 database incidents use Database outage") above a broad one has to win.
  • No rule keeps today's behaviour; a match is required once rules exist. This works like investigation rules: with rules, only matching incidents get a draft.
  • Unreadable rules mean no draft (fail closed). Investigation rules fail open, but a draft writes to the incident and posts to its Slack or Teams channel, so it keeps to what the rules allow.
  • Several templates trigger a separate small pick call instead of putting every outline into the draft prompt. If the pick fails, the draft uses the first template by name and is still written.
  • A rule can name at most 10 templates.
  • The switch stays the only off switch. Rules only affect automatic drafts. Generate with AI still offers every outline.
  • Rules are not plan-gated; only templates are.
  • The incident lane's More settings now has six cards. The folded header names four of them and "2 more" (the shared FoldedSection rule). The alert lane is unchanged.

What changes for existing customers

Nothing changes until someone adds a rule. The migration writes no rows, and while the switch is on every resolved incident still gets a draft in the standard outline. On the incident AI settings page, folded More settings now shows four names plus "2 more" (it was four plus "1 more"), and the defaults line mentions postmortem drafts. On every drag-ordered table, people without edit rights now see disabled drag grips instead of grips that drag and then bounce back.

Left out

  • Postmortem rules for alerts and episodes. Alerts have no postmortem, and episodes are never drafted automatically.
  • Applying rules to Generate with AI: the manual dialog still offers every outline and template.
  • Running rules against incidents that already exist. Like Investigation and Auto Remediation rules, they cannot be run there.
  • Terraform: the provider is not regenerated here. The API resource is /api/ai-postmortem-rule.

Tests added and what each proves

Common:

  • Tests/Models/DatabaseModels/AIPostmortemRuleModel.test.ts: the model's route, columns, permissions, list-order column, relations and that it has no plan gate.
  • Tests/Types/AI/PostmortemRuleTemplates.test.ts: the template count, however the ids are written, and the 10-template limit.
  • Tests/Server/Services/AIPostmortemRuleService.test.ts: templates are project-scoped on create and update, more than 10 is refused before any lookup, and edits that leave templates alone are not judged on them.
  • Tests/Server/Utils/AI/PostmortemRules.test.ts: the matching itself. Covers no rule, first match wins by order, no match means no draft, disabled rules, unreadable rules or templates mean no draft, deleted or blank templates, project scoping, and the plan gate.
  • Tests/Server/Utils/AI/PostmortemTemplatePick.test.ts: none, one or several templates, the prompt, reading the answer (number or exact name), and the fallbacks.
  • Tests/App/Dashboard/AIPostmortemRulesTable.test.tsx: the real table renders. Covers the Match and Draft steps, name following the templates, order, permissions, the plan-hidden picker, and what is sent.
  • Updated:
    • IncidentPostmortemRunner.test.ts: the plan is read before the wait and again after it, the outline is passed, and the feed names the template.
    • AiWrittenTextInFeedsAndChats, AIKillSwitchBackstop and RecordTextInPromptsGuard: the new LLM caller is registered in each.
    • Rule-criteria registry, subject and migration suites; ListOrderColumnModels; RelationListReadCoverage.
    • MoreSettingsOneCard and ProjectAiSettingsSwitchPages.
    • BaseModelTableDragReorder: grips are disabled, with a tooltip, when the user cannot update.

App:

  • Tests/Dashboard/PostmortemRulesSettings.test.ts: the card is on the incident page and not the alert page, it counts on the folded header, the table wiring is right, and all 17 locales have the translations.
  • Updated AISettingsSwitchesFirst and AISettingsSeparation for the per-lane cards.
  • Docs:
    • CriteriaGroupsPostmortemsDocsFacts gets a new describe that holds the new section to the product (card title, criteria answers, fields, template pick, first match, roles, Growth plan).
    • MoreSettingsOneCardDocs and AutomaticRemediationSwitchDocs pin the new sentences.
    • The translation suites hold all 16 translations line for line.

E2E (offline fixture, real page bundled with esbuild): packages/E2E/PostmortemRules/PostmortemRules.spec.ts, 16 tests. They cover the switch and the fold, ordering, a viewer, creating a rule with and without templates, a typed name being kept, conditions, keyboard drag and a refused drop, below and on the Growth plan, phone, dark mode and German. npm run test-postmortem-rules-ui.

What ran

  • Common: tsc --noEmit, npm run compile-tests, npx jest Guard (149 suites), and the 19 changed or added suites. All pass; the one skip is the existing Postgres-gated rule criteria test.
  • Dashboard tsc --noEmit; App tsc --noEmit (8 GB heap); --listFiles shows nothing outside App and Common.
  • App root-level tests (17 suites), the changed App suites, the drafting worker suites, npx jest Tests/FeatureSet/Docs/Docs and every suite that reads the three changed pages (about 100 suites). All pass.
  • npm run docs:check-anchors, npm run i18n:validate, npm run docs:localize-anchors -- --apply on the three pages.
  • New suites run again with ee/ moved aside: pass.
  • E2E npm run compile; npm run test-postmortem-rules-ui: 16 passed (about 36 s, after merging master).
  • Migrations run from scratch on a throwaway Postgres 15, ending with master's 1804150000000 and then this branch's 1804200000000. CheckSchemaDrift.sh reports no drift.
  • Ops tests that read test.app.yaml (E2ESuitesRunInCi and three others): pass.
  • The regex timing checker, prettier --check and eslint on changed code files: clean. The E2E fixture .js files show the same project-service parse error as every sibling fixture. The docs .md files are not prettier-formatted on master either.
  • Not run: the full Common, App or E2E test folders, the live stack E2E, and Firefox (the suite is Chromium only).

CI

test-postmortem-rules-ui joins Dashboard Offline UI group 6, which took 15.3 to 20.5 minutes on 2026-10-19's runs. That adds about 2 minutes. Its screenshots and traces go up with the group's artifact.

UI review

A second agent reviewed every surface of this change in a real browser and polished it before merging.

What I looked at

  • Incidents → AI → Settings, rendered from this branch inside the Dashboard's real frame (Page + the Incidents side menu), with Inter and Tailwind as production loads them. Widths: 390, 1024, 1152, 1280, 1366, 1440, 1536 and 1920px. Light and dark. English, German, Japanese and French.
  • Folded More settings: no rules, rules counted as a chip, phone width.
  • The Postmortem rules card: empty; one, three and five rules; a disabled rule; a long hand-typed name; a rule with five templates; a project with no templates; a project below the Growth plan; a viewer (greyed grips, disabled Create and Edit); the row ⋯ menu and the Delete dialog.
  • Create and Edit dialogs: Match with and without conditions; Draft with none, two and five templates; the Edit dialog's Enabled switch; the template picker opened; with no templates; below the plan; on a phone.
  • The feed and chat post for an AI draft (", following the postmortem template Database outage"). I read it as the incident's feed and its Slack or Teams channel show it, and left it as it is.

What I changed, and why

  • The rules table no longer scrolls sideways at 1280px. Beside the side menu the card is about 940px wide, and the table has seven columns. Each rule's templates were one line of comma-joined names. That made the table 1212px wide, so it scrolled sideways inside the card, and Status ended up under the row's buttons: a disabled rule looked like an enabled one. It also cut every name short ("Draft with Database...").
    • Templates are now drawn like every other list of records in a table (TableColumnListComponent, in the new PostmortemRuleTemplates). Each template is on its own line, the first three are shown, and a 2 more templates button shows the rest. In a row, a long name is cut short with its full name on hover; in a phone's card, it wraps. The column is capped at 11rem, or 18rem from 1536px, through wrapMaxWidthClassName. That is the only width cap TableWrapContentInvariants allows.
    • Name wraps onto more lines instead of being cut, because the name is what tells rules apart.
    • Measured: from 1280px up, the table fits its card in English. Columns at 1280px: Name 199, Match Criteria 199, Templates 200, Status 105.
  • A disabled rule now says Disabled on a phone. This was a shared regression from the table redesign (Tables: a calmer, easier, more modern table everywhere #4958). A phone's card dropped any yes/no column whose value was false, even when the column draws its own element. A disabled rule therefore had no Status at all on a phone. The same happened to every rules table, to two-factor setups ("Setup incomplete") and to team invitations ("Invitation Sent"). TableRow now draws the element. A plain yes/no field that is "no" is still left out, as before.
  • TableColumnListComponent (shared, additive):
    • A new getMoreText(count) lets a page word "2 more templates" with its language's plural forms.
    • moreText is now looked up in the reader's language. The locale files already had "weitere Ressourcen" and the other translations, but they were never shown.
  • The card's description was 252 characters. ShortDescriptionsGuard allows a card description at most 210, so CI would have failed on it. It now reads: "With no rule, OneUptime AI drafts a postmortem for every resolved incident. Add rules to draft only for matching incidents, in the templates you choose. The first rule that matches decides - drag to reorder." That is 207 characters and two lines at 1280px. The locale key is renamed in place in all 17 files, each with its own new words, so no translation is lost and the key count and order stay the same.
  • Below the Growth plan, the rule's Name field showed the column description "Name of this postmortem rule." as its help. That help is now hidden (hideColumnDescription).
  • Two suites the new card broke, which the builder had not run:
    • RuleCriteriaModelTable now counts 72 rule forms with a Match step.
    • AIInvestigationSettingsLimits now expects the incident page's new defaults line; the alerts line is unchanged.
  • New strings: {{count}} more templates and its _one form, translated in all 16 locales. Only these two keys were added: i18n:extract also picked up 35 keys from other merged features (SCIM, Vercel, SSO), and I left those out.

Tests added or changed in the review

  • Common/Tests/UI/Components/Table/TableCardBooleanElement.test.tsx (new): a phone's card shows "Disabled" as well as "Enabled". A column that draws nothing is still left out, and so is a plain "no". 2 of its 5 tests fail on master's TableRow.
  • Common/Tests/UI/Components/TableColumnList.test.tsx (+3): getMoreText, and moreText looked up in German. 2 fail on master's component.
  • Common/Tests/App/Dashboard/PostmortemRuleTemplates.test.tsx (new): the cell inside a real TableBody with the real German locale. One template per line, cut short in a row and wrapped in a card, "2 weitere Vorlagen" and its singular, and "Standardgliederung" in grey.
  • Common/Tests/App/Dashboard/AIPostmortemRulesTable.test.tsx: the column shapes (Name wraps, Templates capped through the wrap option), the list, sorting and blanks, the more button and its singular, the standard outline, and the hidden Name help.
  • App/Tests/Dashboard/PostmortemRulesSettings.test.ts: the table wiring, and the new plural in all 17 locales.
  • E2E PostmortemRules (18 tests, was 16):
    • The fixture gained a layout=page mode: the page inside Common's Page and SideMenu, as wide as a person sees it.
    • It also gained a fourth rule (disabled, hand-named, five templates) and two more templates.
    • New: at 1280px every column is in sight, Status included, and every name reads in full, and on a phone a turned-off rule says Disabled. Both fail on the code before the review.
    • Two existing assertions now read the templates cell itself. Before, they passed because the rule's name contains the same words.
    • The suite takes about 39s, about 3s more than before.

Left as follow-ups

  • The Match Criteria column is the shared rule-criteria summary. It says "Incident Labels has any of 1 selected value" without naming the label, and its conditions are English in every language. This is the same on every rules table.
  • In German and French at exactly 1280px, the table is still 22 to 36px too wide: their Edit buttons, Status pills and the Match Criteria header are wider. It fits from about 1320px. In English it fits with room for a Windows scrollbar.
  • With no postmortem template in the project, the picker says "No options." and does not link to Postmortem Templates. The shared dropdown has no per-field empty message.

What the review ran

  • Type checks, all passing: Common tsc --noEmit and npm run compile-tests (the app, ui and rest programs); the Dashboard's tsc --noEmit -p tsconfig.json; App tsc --noEmit (8 GB heap); and E2E npm run compile. --listFiles for App, E2E and Common lists nothing outside the package and Common.
  • The suites I added or changed, run normally and again with ee/ moved aside: TableCardBooleanElement, TableColumnList, PostmortemRuleTemplates, AIPostmortemRulesTable, PostmortemRulesSettings, RuleCriteriaModelTable and AIInvestigationSettingsLimits.
  • Every suite in Common, App and ee/Tests that names a source file this branch changes. That is 201 suites (152 Common, 48 App, 1 ee), now all passing. The Common half found the two failures fixed above.
  • Sweeps and guards:
    • Common npx jest Guard (149 suites); the Common table, list and detail component suites (22); and Common's model, schema, Terraform, API reference and infrastructure suites.
    • App's 17 root-level suites; the App Dashboard guards that walk every page, including ShortDescriptionsGuard (which found the 252-character description), TableWrapContentInvariants, ListDeletePolicy, DragOrderedListsGuard, SettingsFormsOwnWordsGuard and NoAlwaysOnInfoBannersGuard; Common DeleteConsequences and ListDeleteEveryList.
    • Every locale suite: npx jest Locale in Common (30) and App (9). npm run i18n:check reports every locale file sound and no translation lost. i18n:hardcoded on Components/AISettings finds 0.
  • Offline browser suite test-postmortem-rules-ui: 18 passed in about 40s. The two new tests fail against the builder's table and master's TableRow.
  • Mutation checks: master's TableRow fails 2 of the 5 TableCardBooleanElement tests, and master's TableColumnListComponent fails 2 of the 5 TableColumnList tests.
  • Lint: prettier --check on every code file the branch changes (73), and eslint on its .ts, .tsx and .js files. Both are clean, apart from the fixture .js parse error that every sibling fixture shows. The regex timing checker finds nothing new.
  • Unrelated local failure: Common's ExpoPushReceiptQueueValkey needs a running Valkey server and fails here with "Connection is closed". This branch does not touch it.
  • Not run: the whole Common or App test folders, the docs suites (this review changed no docs page, and master has not moved since the builder ran them), the live-stack E2E, and Firefox.

🤖 Generated with Claude Code

valeriamustafaeva and others added 11 commits October 19, 2026 18:00
…, and its templates

AIPostmortemRule (drag-ordered, incident conditions as investigation rules
have, and the postmortem templates a draft may follow), its service (at most
10 templates, every reference the project's own), the migration, and the
drafting job reading them: no rule = every resolved incident, standard
outline; with rules the first match decides, and OneUptime AI picks the best
fit when a rule names several templates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ore settings

A drag-ordered table beside Investigation rules and Auto remediation rules:
Match (All incidents / Only incidents that match conditions) then Draft (the
templates a draft may follow, the name filled in from them). The folded
header counts its rules; its summary and description say drafts too. Plan
below Growth on Cloud: no template picker, and the server follows the
standard outline. Strings in all 17 locales.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hey cannot edit

PostmortemRules fixture renders the real Incidents -> AI -> Settings page:
folded More settings, the rules table in its order, the Match and Draft steps
(name following the templates), a keyboard drag and a refused one, a viewer,
a project below the Growth plan, phone, dark and German.

BaseModelTable: a drag-ordered table greys its grips out, saying why, for
someone who may not edit its rows - the server refused their drop anyway.
A project below the template plan gets a card description without templates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… drafting job, table and pages

New: AIPostmortemRuleModel, PostmortemRuleTemplates, AIPostmortemRuleService,
PostmortemRules (no rule = every incident; first match decides; templates
the project's own, by name; below Growth none; unreadable = no draft),
PostmortemTemplatePick (none/one/several; failures take the first),
AIPostmortemRulesTable (Match then Draft, name follows templates, drag order,
plan gate, rule count). Runner suite: rules decide before any wait, the
template is filled in and named in the feed. Guards updated for the new rule
model, drag list, prompt builder and call site; the folded header names four
of six cards; viewers' grips are off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The incident lane's More settings names five cards now, the alert lane's
four; the summary waits for the postmortem rules to read on incidents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…plates

Postmortems gets a section on the rules under More settings: what a rule
matches, its templates (none, one, or the best fit of several, named in
the feed), first match wins by drag order, no match means no draft, the
switch stays the only off switch, Owner/Admin and the Growth plan. AI SRE
names them in Auto-postmortem and in the Cost controls fold; Incident
Settings names the third table under More settings. In all 17 languages,
with the facts suite holding the English page to the product.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…raft-rules

The postmortem rules migration moves to 1804200000000, after master's
1804150000000-AddIncidentVideoCallCalendarEvent; the Dashboard locales take
master's keys, with this branch's appended after them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oup 6

Group 6 was the lightest of the groups holding several suites on
2026-10-19's runs (15.3 to 20.5 minutes); the suite adds about 2. Its
screenshots and traces go up with the group's artifact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…raft-rules

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simlarsen

simlarsen commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

valeriamustafaeva and others added 3 commits October 19, 2026 20:43
…disabled rule says so on a phone

UI review of the Postmortem rules card (Incidents > AI > Settings > More
settings), looked at in the real page beside the side menu at 1280, 1440,
1536 and 1920px, on a phone, in dark mode and in German and Japanese:

- At 1280px the card is about 940px wide for seven columns. A rule's
  templates were one line of names, which pushed the table to 1212px: the
  rows scrolled sideways, Status sat under the row's buttons (a disabled
  rule looked like the rest), and every name was cut to "Draft with
  Database...". Templates are now the list every table draws records
  with - one a line, the first three, then "2 more templates" which shows
  the rest (PostmortemRuleTemplates) - capped at 11rem (18rem from
  1536px) through wrapMaxWidthClassName, and a rule's name runs onto more
  lines instead of being cut. The table fits from 1280px up in English.
- A phone's card left out a yes/no column whose value was false even
  when the column draws its own element, so a disabled rule had no
  Status at all (the same for every rules table, two-factor setups and
  team invitations since the table redesign). TableRow now draws the
  element; a plain yes/no field that is no is still left out.
- TableColumnListComponent: getMoreText lets a page word "2 more
  templates" with its locale's plural forms; moreText is looked up in the
  reader's language (the locale files had "weitere Ressourcen" and the
  others, never shown).
- Below the Growth plan the rule's Name showed the column description
  "Name of this postmortem rule." as its help: hidden.

Tests: TableCardBooleanElement (phone card, fails on master's TableRow),
TableColumnList (+3, two fail on master's list), PostmortemRuleTemplates
(real TableBody in German, desktop and phone), AIPostmortemRulesTable
(column shapes, list, singular, standard outline, Name help),
PostmortemRulesSettings (wiring and the new plural in 17 locales), and the
offline E2E suite: a layout=page fixture mode beside a real SideMenu, a
1280px fit test and a phone Disabled test (both fail on the old code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ttier wraps it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es the card's arrival changed

- The card's description was 252 characters; ShortDescriptionsGuard holds a
  card description to 210 (two lines beside its title). Now: "With no rule,
  OneUptime AI drafts a postmortem for every resolved incident. Add rules
  to draft only for matching incidents, in the templates you choose. The
  first rule that matches decides - drag to reorder." (207). The locale key
  is renamed in place in all 17 files, with new words in each: no
  translation lost, key count and order unchanged.
- RuleCriteriaModelTable counts the Dashboard's rule forms with a Match
  step: 72 with the postmortem rules (no help panel, as the investigation
  rules).
- AIInvestigationSettingsLimits: folded More settings on the incident page
  now also says a resolved incident is given a postmortem draft; the
  alerts' words are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simlarsen
simlarsen merged commit 5b58d03 into master Oct 19, 2026
25 of 65 checks passed
@simlarsen
simlarsen deleted the claude/postmortem-draft-rules branch October 19, 2026 21:20
simlarsen pushed a commit that referenced this pull request Oct 19, 2026
…red list

#5071 added AIPostmortemRule, a list put in order by dragging
(@ListOrderColumn), without adding its service to NormalizeListOrder. That
migration's suite holds it to exactly the drag-ordered lists ("a list
added later without being added here would never be healed"), and failed
on the 14.0.78 gate (App Test 2/3): AIPostmortemRule expected, not covered.

AIPostmortemRuleService joins the rule lists. Its rows were numbered from
the start, so on an install where the migration has yet to run it finds
nothing to renumber; NormalizeListOrder.test passes (6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simlarsen pushed a commit that referenced this pull request Oct 19, 2026
…phone too, since phone cards draw a yes/no column's element for no

The 14.0.78 gate's Common Test 2/8 failed on StatusPageMonitorRuleForm:
"says Disabled on a phone too" still showed why its Status column is an
Element, by rendering the same column typed Boolean and expecting the
disabled rule's status to be missing on a phone. #5071 fixed that in the
shared table: a phone's card now draws a yes/no column's own element for no
as well (Disabled, Setup incomplete, Invitation Sent; a plain yes/no column
still leaves no out), pinned by TableCardBooleanElement.test.

The test now expects Disabled from the Boolean-typed column too, and says
why the column became an Element. StatusPageMonitorRuleForm (15) and the
table and detail layout suites (27, 734 tests) pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant