Skip to content

Postmortems across every incident: a status for each postmortem, Incidents > Postmortems to view and filter them, and a simpler Postmortem page - #5171

Merged
simlarsen merged 19 commits into
masterfrom
claude/postmortem-reports
Oct 22, 2026
Merged

simlarsen merged 19 commits into
masterfrom
claude/postmortem-reports

Conversation

@simlarsen

@simlarsen simlarsen commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

The problem

A customer asked: "Is there any way I can view and filter Postmortem reports across all incidents? I am trying to filter by team/owner, severity, postmortem report status (not-started / draft / and a few custom statuses)." The maintainer asked to make postmortems a lot better overall: easy to use, easy to understand, the advanced things out of the way.

Before this PR a postmortem was a set of fields on the incident (note, attachments, Publish on Status Page), written on the incident's Postmortem page. There was no list across incidents, and a postmortem had no status of its own, so "which postmortems are still owed, by whom?" had no answer.

What changed (and why)

1. A postmortem status, with the fewest states that answer "which are still owed?"

  • New model IncidentPostmortemStatus (API /api/incident-postmortem-status, OpenAPI, MCP tools *_postmortem_status, CLI postmortem-status, Terraform oneuptime_postmortem_status, workflows, audit log), and Incident.postmortemStatusId (API, OpenAPI, Terraform postmortem_status_id).
  • Every project starts with four: Not Started, Draft, Completed, Not Needed. Not Started and Draft are owed; Completed and Not Needed are not.
  • OneUptime moves a postmortem by itself on three occasions only (Common/Utils/Incident/PostmortemStatus.ts, one rule for server, list and tests):
    • a new incident's postmortem starts in Not Started (Draft when declared with a note, Completed when declared with it published);
    • the first note of a postmortem that is not started moves it to Draft (a person, a template or the AI draft);
    • publishing it on a status page moves it to Completed, unless it is done already.
      It never moves back (clearing the note or unpublishing leaves it), and a status picked in the same save always stands. The move is a hook-free compare-and-set from the status it was in, so a status someone picked meanwhile is never overwritten.
  • Custom statuses (e.g. "In Review") live under Incidents > Settings > Postmortem Statuses, out of sight until a project wants one. It is a drag-ordered list like incident states (StateOrder): a new status goes just above Completed; where a status sits decides what it counts as (above Draft: not started; from Draft down: in progress; from Completed down: done). Not Started, Draft and Completed are built in: renamable, never deleted or archived, kept in order (the server says why it refuses a move). Statuses get Archive/Unarchive like every other value (archive-config-values), so a retired status is never picked again while old incidents keep it.
  • A postmortem status change someone makes is one line in the incident's feed ("Postmortem Status: In Review"), only when it really changed.
  • Status pages are unchanged: no status page read selects the postmortem's status.

2. Incidents > Postmortems: every incident's postmortem in one list

  • New side-menu entry under Overview (and a Search entry): Postmortems.
  • Columns: Incident, Title, Postmortem Status (a pill that moves the postmortem in place), Severity, Owners, Declared (Labels from Columns).
  • Filter chips: Owner (user or team), Postmortem Status, Severity, Incident State, Labels, Affected Resources, plus Declared date / number / title filters and search. Saved views, URL state.
  • A tile per status above the list counts its postmortems; a click filters the list to them, a second click clears it.
  • Bulk actions: Change Postmortem Status (e.g. mark many Not Needed), Add Owner / Remove Owner. No Delete (each row is an incident; ListDeletePolicy records why).
  • Private incidents follow the incident privacy rules (a member sees a private incident's postmortem only when they own it).

3. The incident's Postmortem page, simpler

  • One card, Postmortem: Status (the same pill) and Owners (the incident's owners, with a Change owners link) side by side at the top; then the note, attachments and status page section.
  • Nothing written yet: an empty state with one obvious next step, Write Postmortem, with Start from Template (only when the project has a template) and Generate with AI (only while AI is on) beside it.
  • Written: Edit Postmortem Note, with Apply Template and Generate with AI folded into the card's ⋯ (they replace the note, which a written postmortem rarely needs). Publishing on the status page stays the editor's second step.

4. Existing data

  • Schema migrations 1805900000000-AddIncidentPostmortemStatus (new table + a nullable column on Incident, no rewrite) and 1805910000000-AddIncidentPostmortemStatusIndexesAndKey (the Incident indexes and key built online through OnlineDdl, outside a transaction). Generated, not hand-written.
  • Data migration AddDefaultPostmortemStatusesToExistingProjects: gives every existing project the four statuses (idempotent), then backfills every existing incident, in batches of 5,000: Completed when its postmortem is published (switch on and a non-blank note), Draft when it has a note, Not Started otherwise. Nobody is given Not Needed: that is the team's call, from the list.

What changes for existing customers

  • Every project gets four postmortem statuses, and every existing incident gets the status its postmortem is in by its fields (see above). Teams with many old incidents will see them as Not Started until they mark them Not Needed (bulk action) - that is the honest answer to "what is still owed".
  • The incident's Postmortem card is titled Postmortem (was "Postmortem Note"), shows status and owners, and offers Write Postmortem while empty; Apply Template / Generate with AI moved into the ⋯ once written.
  • Two new side menu entries: Incidents > Postmortems and Incidents > Settings > Postmortem Statuses. New permissions Create/Read/Edit/Delete Postmortem Status (owners, admins and incident admins manage statuses; everyone who reads incidents reads them; moving a postmortem takes the incident's edit permission).
  • Status pages, subscriber notifications and the AI postmortem rules behave exactly as before.

Deliberately left out

  • Episode postmortems have no status and are not in the list (an episode's postmortem is a note only). The episode Postmortem page keeps its current buttons; bringing it to the incident page's empty-state/⋯ layout is a follow-up.
  • No "postmortem due date" / reminders and no per-postmortem owner separate from the incident's owners: the incident's owners already own its postmortem, and a second owner concept would be one more thing to explain.
  • Tiles count the whole project per status (not narrowed by the other chips), as the Incidents list's tiles do.

Tests

  • Rules - Common/Tests/Utils/Incident/PostmortemStatus.test.ts: starting status, progress by position, owed/done ids, every automatic move and every non-move (picked status stands, no moving back, unknown status left alone).
  • Model / registries - IncidentPostmortemStatusModel.test.ts, ArchivableValueModels, ListOrderColumnModels, RelationListReadCoverage, ArchivableValues(+ApiAndTerraform), StateOrder.
  • Service - IncidentPostmortemStatusService.test.ts (guards, project statuses, backfill loop), IncidentPostmortemStatusOnCreate.test.ts (where a new incident's postmortem starts, a picked status stands, a failed read never blocks declaring), IncidentPostmortemStatusMoves.test.ts (writing/publishing moves through the real update hooks, compare-and-set from the status it was in), UpdatedFeedRealChanges, PostmortemNotifyOnPublish, StateListServicesOrder, ProjectServiceDefaultPostmortemStatuses (+ project-create suites).
  • API - Common/Tests/Server/API/PostmortemsListThroughTheApi.test.ts (new, 27 tests): the list and tile counts through BaseAPI and the real permission layer - held to the caller's project whatever project the query names, every chip reaches the database, private incidents follow the privacy rule, viewers/incident viewers/members read, someone without incident read is refused, who may add a status (owner/admin/incident admin/Create Postmortem Status) and who may move one (members, incident members, Edit+Read Incident; viewers and Edit-alone refused).
  • Status page unchanged - StatusPagePostmortemVisibility.test.ts: the overview, the incident list and an incident's page never select the postmortem's status.
  • Migrations - AddIncidentPostmortemStatusMigration.test.ts (new, 24 tests: every column/index/key under TypeORM's names, no rewrite, online indexes and key, down() undoes all) and AddArchiveToValuesMigration.test.ts (the statuses table is created archivable by its own migration).
  • On real Postgres - IncidentPostmortemStatusPostgres.test.ts (new, opt-in RUN_POSTGRES_POSTMORTEM_STATUS_TESTS, wired into the Postgres Schema Drift workflow): the migrations on a copy of the migrated incidents table holding incidents (no table rewrite - same relfilenode, indexes valid, key validated and NO ACTION, safe to run twice, a status in use can't be deleted), the backfill on real rows (each case above, whitespace-only notes, batching, first built-in status by order, deleted statuses and projects without statuses left alone, idempotent), and the list's reads through the incident service. ArchivableValuesPostgres now leaves the statuses table to its own migration.
  • Data migration - App/Tests/Workers/DataMigrations/AddDefaultPostmortemStatusesToExistingProjects.test.ts.
  • Dashboard - PostmortemsList.test.tsx (tiles, chips, row pills, bulk move), IncidentPostmortemPage.test.tsx (status + owners, empty state vs. written, folded ⋯, permissions), IncidentsSideMenu.test.tsx, PostmortemStatusChoices.test.ts, PostmortemStatusTiles.test.ts, ArchivedValuePickersGuard, ListDeletePolicy, SettingsPathsInCopy, MCP ArchivableValueTools.
  • Offline browser suite - packages/E2E/Postmortems (21 specs after the UI review, Chromium, ~42 s locally, ~1.5 min with its bundle): the list (tiles filter, row move, refused move put back, bulk move, viewer, empty project), the incident page (written / empty / no template and no AI / moving the status), the statuses settings (counts as, archived folded), at 1280 and 390 px, dark mode and German. Added to Dashboard Offline UI group 9 (about 18.5 min with it).
  • Docs - incidents/postmortems, incidents/settings, incidents/index, ai/mcp-server, cli/command-reference, configuration/audit-logs in all 17 languages; CriteriaGroupsPostmortemsDocsFacts, AiDocsFacts, CliDocsFacts updated.

What I ran locally

  • npm run compile in Common, App and E2E; npm run compile-tests in Common; tsc --noEmit --listFiles in all three (nothing outside each package and Common).
  • Every Common and App suite that names a changed file by basename or reads the incident service, the postmortem pages, project creation defaults, the Incidents side menu, or walks every page/permission/model (722 Common + 190 App suites). They found three suites this branch had broken - CreatedClosedNoAutomations (incident creates now read the project's statuses), SettingsPathsInCopy and ListDeletePolicy - fixed here.
  • Common's guard suites (npx jest Guard plus UpdateChecksReadHeldRows, DeleteChecksReadHeldRows, HookWritesCallersMayMake, ListOrderColumnModels, PermissionCatalogueCoverage, RequiredColumnsWithDefaults, RelationListReadCoverage, RelationListPermission, PlanGatedTableLeftovers: 168 suites), App's root-level tests and its Guard/Covers/Locale/ShortDescriptions/WrongComponentKey/RelationSelectColumns suites (101), the MCP tests (53), Common's Locale suites (37); my suites with billing on and off, and with ee/ hidden.
  • The new Postgres suite and ArchivableValuesPostgres against a throwaway Postgres migrated to head (container removed).
  • The offline Postmortems browser suite after the last master merge (17/17, 39 s).
  • Docs: the 94 suites that read the changed pages plus the general Docs suites, and all 46 *DocsTranslations suites; docs:check-anchors, i18n:validate, i18n:check.
  • Ops: PostgresSuitesRunInCi, E2ESuitesRunInCi, CommonTestSetup, DockerHubMirrorCoverage, EnterpriseEditionBuild.
  • Prettier and ESLint over every changed code file; the ReDoS checker (no new patterns).
  • Not run: the full-stack deployed E2E suites (no deployed spec touches the postmortem page or the Incidents menu - grepped packages/E2E/Tests), the whole App/Common suites.

Master failure seen that is not this PR's: App/Tests/Dashboard/CardDescriptionBoilerplateGuard fails on SecurityEvents/ThreatIntelSourcesCopy.ts ("List of indicators", from #5165).

UI review

A second agent reviewed and polished every surface before merging.

What I looked at. Every surface rendered for real in the offline fixture (the production pages beside the real side menus, Inter, Tailwind, Theme.css), at 390, 768, 1024, 1280, 1440 and 1920 px, light and dark, in English, German, French, Spanish, Russian and Japanese. I checked them as a project owner and as a viewer, with an empty project and a full one, with the project's own statuses and an archived one, and with a move the server refuses. The pages:

  • Incidents > Postmortems: tiles, every chip and its dropdown, rows, the row status menu, a refused move, Bulk Actions > Change Postmortem Status, the empty list.
  • The incident's Postmortem card: empty, written and published; the ⋯ menu; the Write Postmortem dialog; a viewer.
  • Incidents > Settings > Postmortem Statuses: the table, Create/Edit dialog, row menus (built-in and custom), the Archive dialog, the archived section, phone cards.
  • The feed line "📘 Postmortem Status: ", converted with the real Slack and Microsoft Teams converters. It reads as the severity line does: no change needed.

What I changed, and why:

  1. Empty Postmortem card. Start from Template and Generate with AI used the OUTLINE button style, which draws bare words with an icon, so they read as text beside the primary button. They are now white bordered buttons (NORMAL) on Write Postmortem's line, stacked at full width on a phone. This is the list empty states' pattern (TableEmptyState), and Button's dialog-footer margin is cleared.
  2. A viewer on the empty card saw three locked buttons, and only the primary one looked locked. They now see Write Postmortem alone, dimmed, with the permission reason under it, as a list's locked Create does.
  3. Owners. The Change owners / Add owners link now shows only to someone who may add an owner to the incident.
  4. Tiles. The grid went to four columns from md. At 768 px, beside the side menu, that made each tile about 105 px wide, and the captions ran out of the tiles. Columns now start at lg (3/5/6 tiles too). Captions are clamped at three lines with the whole text on hover, so a project's long description keeps the tiles level, and they are hidden on a phone, where they pushed the list below the fold.
  5. The list's width at 1280 px. Declared now shows the date (FieldType.Date). With the time, German ran 57 px past the card and the dates sat under the sticky "Ansehen". German, French and Spanish now fit at 1280 px. The Incident column names its own floor (min-w-[4rem]), so the table's spare room goes to the title. Before, the first column took that room as the row's name: it stood 184 px wide around "INC-101" while titles wrapped to three lines. They now wrap to one or two.
  6. A refused move's reason now wraps inside its row (13rem). On one line it pushed the Postmortem Status column ~200 px wider, under the sticky View.
  7. The empty list used the incident's warning-triangle icon. It now uses a write-up's icon (DocumentText, as in the side menu). Its copy "Every incident has a postmortem to write…" was not true once Not Needed exists. It now reads "When an incident is declared, its postmortem shows up here." The key is renamed in place in all 17 locales, so no translation is lost.
  8. The Write Postmortem dialog. The note hint read "…follow-up actions.." because MarkdownUtil.getMarkdownCheatsheet appends its own full stop, and it was never translated. It is now a plain description, translated into 16 languages.
  9. Built-in tags on the settings pages. On Postmortem Statuses (and the six other state pages, which share the cell), the Built-in tag stayed on the name's line for short names only. "Not Started" and "Completed" wrapped and "Draft" did not, so the built-in rows of one page had two heights. The name cell no longer wraps from md, where rows are a table.

Tests added or changed in the review:

  • Offline browser suite: 17 → 21 specs, ~42 s locally, about +5 s on CI group 9. New specs: a tablet (two tiles to a line, each caption whole and inside its tile); the title taking a fitting table's room; a viewer on the empty card; the three buttons stacked on a phone.
  • New checks in existing specs: the German list fits its card; the empty card's two buttons are white, 1 px bordered and on the primary's line; a refused move's reason stays ≤ 13rem with the table inside its card; Built-in tags on their name's line (the four-status page and the custom one); no captions on a phone.
  • Each new check was proven against the break it guards: I reverted each fix on its own, and the matching spec failed for all 8 breaks.
  • Unit tests:
    • PostmortemsList: Declared is a date; the empty state's icon and words; the Incident column's floor, never a cap, and not the filling column; caption clamp, hover text and max-sm:hidden (never the bare hidden); no md: columns.
    • IncidentPostmortemPage: the viewer's single locked button and its note; button styles and the phone column; no Change owners for a viewer; the note hint with one full stop.
    • IncidentStatesPageTable: the name cell keeps one line from md.
    • PostmortemStatusTiles: the lg grid, and no md: columns at any count.
    • CriteriaGroupsPostmortemsDocsFacts follows the new source.

Left as follow-ups:

  • Russian still scrolls 45 px inside the card at 1280 px ("Серьёзность", "Просмотр"). It fits from ~1330 px.
  • The shared state settings form shows the models' generic field descriptions ("Any friendly name of this object") on every state page.
  • Episode postmortems, as the builder noted.

A bug the review found and fixed: CI would have failed. The builder placed the data migration AddDefaultPostmortemStatusesToExistingProjects between RemoveRunbookCredentials and the last slot, AddAuditLogMcpClientColumns. That broke RemoveRunbookCredentials.test.ts and MoveRunbookApprovalsBeforeTheirSteps.test.ts, which assert each neighbour. The migration has no ordering requirement among data migrations, so it now sits above the runbook moves, where AddProcessColumnsToSecurityEvent sits. Its own suite now pins that place.

What the review ran (after merging master at a082b72; the conflicts were the migrations index and the Dashboard locales):

  • Offline browser suites:
    • Postmortems: 21/21 in 39 s.
    • ArchivableValues: 14/14. It renders the state pages that share the Built-in name cell.
  • Common:
    • The suites that read the changed files: PostmortemsList, IncidentPostmortemPage, IncidentStatesPageTable, StateSettingsPages, EpisodePostmortemPage, PostmortemPageParts, SuggestionRulesGuard, IncidentsSideMenu, PageSearchIndexCovers*, RarelyUsed/AdvancedMenuSectionsCollapsed.
    • The page suites again with BILLING_ENABLED=true.
    • npx jest Guard with UpdateChecksReadHeldRows, DeleteChecksReadHeldRows, HookWritesCallersMayMake, ListOrderColumnModels and PermissionCatalogueCoverage: 166 suites.
    • Locale: 37 suites.
    • Every suite that reads the schema migrations index (150), or the models, services or BaseAPI index (269; 92 of them are opt-in Postgres suites and skip).
  • App:
    • The suites that read the changed files.
    • Root-level tests, Dashboard guards, and the Locale, ShortDescriptions, RelationSelectColumns, TableEmptyStateWiring and MCP suites: 84 suites.
    • All 51 DataMigrations suites.
    • Every suite that reads the migration or registry indexes: 50 + 38.
    • The 99 docs suites that read the changed and merged pages, plus the general Docs suites.
  • ee/ hidden: every suite the review added or changed, run once.
  • Builds and type checks: npm run compile in Common, App and E2E; compile-tests in Common; tsc --listFiles in each, which lists nothing outside the package and Common.
  • i18n: i18n:extract (no change after the review's keys) and i18n:check (every locale sound, no translation lost).
  • Lint: prettier --check and eslint over every file the branch changes; eslint's only errors are the fixture .js files, which eslint.config.js ignores, as for every fixture.
  • ReDoS checker: no new pattern in product code.
  • Not run: the deployed full-stack E2E suites. No deployed spec touches these pages; I grepped packages/E2E/Tests for every changed label and test id.
  • Master failures seen: none. CardDescriptionBoilerplateGuard, noted above as failing on master, passes on the merged tree.

🤖 Generated with Claude Code

valeriamustafaeva and others added 16 commits October 22, 2026 01:36
…t's status, the moves OneUptime makes and the backfill

Every incident's postmortem is in one of its project's postmortem statuses
(IncidentPostmortemStatus): Not Started, Draft, Completed and Not Needed by
default, drag-ordered like incident states, with the not started, draft and
completed statuses built in. A new incident's postmortem starts not started,
writing its first note moves it to draft and publishing it on a status page
to completed (Common/Utils/Incident/PostmortemStatus). Existing projects get
the defaults and existing incidents the status their postmortem is in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and a postmortem card with its status and owners

Incidents > Postmortems lists every incident's postmortem with counts per
status, Owner, Labels, Postmortem Status, Severity, Incident State and
Affected Resources chips, a status pill to move each one, and Change
Postmortem Status for many at once. Incidents > Settings > Postmortem
Statuses manages the statuses (drag order, archive). An incident's
Postmortem page shows its status and owners, offers Write Postmortem while
nothing is written, and folds Apply Template and Generate with AI into a
menu once it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ard, the list fits beside the side menu

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…age hold the statuses, the summary and the folded menu

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…new postmortem starts, what writing and publishing move, and the project's defaults

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pills and the bulk move - the statuses as the Dashboard offers them, and the backfill

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tem card in 16 languages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…one list, the statuses settings and the card's new buttons, in 17 languages

The MCP server, the CLI and the audit log list Postmortem Status too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tings in a browser, offline; a status is named in the reader's language in the tiles' and the pill's labels too

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

# Conflicts:
#	packages/Common/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts
…ed Postgres; the archive migrations' suites leave the statuses table, created archivable, to its own

The table migration creates every column, index and key the model declares under TypeORM's names, and adds the incident's column without rewriting the table; the indexes and key are built online and safe to build again; the database refuses to delete a status incidents are in. The backfill gives each incident the status its postmortem is in, a batch at a time, the project's first built-in status of each kind, deleted ones and projects with none left alone. Wired into the Postgres Schema Drift workflow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ped, every chip, private incidents, who may read, add and move - and status pages never read where a postmortem stands

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a project with no postmortem statuses yet; the tiles test types its facet calls; the spec escapes a tile's name

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… incident's page offers a template only when there is one, and postmortem statuses are archived over MCP

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

# Conflicts:
#	packages/App/FeatureSet/Dashboard/src/Locales/da.json
#	packages/App/FeatureSet/Dashboard/src/Locales/de.json
#	packages/App/FeatureSet/Dashboard/src/Locales/en.json
#	packages/App/FeatureSet/Dashboard/src/Locales/es.json
#	packages/App/FeatureSet/Dashboard/src/Locales/fa.json
#	packages/App/FeatureSet/Dashboard/src/Locales/fr.json
#	packages/App/FeatureSet/Dashboard/src/Locales/hi.json
#	packages/App/FeatureSet/Dashboard/src/Locales/it.json
#	packages/App/FeatureSet/Dashboard/src/Locales/ja.json
#	packages/App/FeatureSet/Dashboard/src/Locales/ko.json
#	packages/App/FeatureSet/Dashboard/src/Locales/nl.json
#	packages/App/FeatureSet/Dashboard/src/Locales/no.json
#	packages/App/FeatureSet/Dashboard/src/Locales/pt.json
#	packages/App/FeatureSet/Dashboard/src/Locales/ru.json
#	packages/App/FeatureSet/Dashboard/src/Locales/sv.json
#	packages/App/FeatureSet/Dashboard/src/Locales/zh-CN.json
#	packages/App/FeatureSet/Dashboard/src/Locales/zh-TW.json
…ts type-check (jest-mock types, a typed requireActual), and the docs facts read a label's declaration however it wraps

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

simlarsen commented Oct 22, 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 22, 2026 05:27
…iles that fit a tablet, a list that fits in German, Built-in tags on their name's line

- The empty Postmortem card's Start from Template and Generate with AI are
  white bordered buttons beside the primary Write Postmortem (they were the
  outline style, which drew bare words with an icon), stacked full width on
  a phone, like a list's empty state. A viewer finds Write Postmortem alone,
  dimmed, with why under it, not three locked buttons.
- The Owners field offers Change owners only to someone who may add an
  owner to the incident.
- The Postmortems tiles are two to a line below lg (four in the ~480px a
  tablet leaves beside the side menu were ~105px each and their captions
  ran out of the tiles); captions are clamped at three lines, whole on
  hover, and left out on a phone.
- The list's Declared column is the date (German ran 57px past the card at
  1280px, the dates under the sticky View), and the Incident column names
  its own floor so a fitting table's spare room goes to the title, not to
  "INC-101" (titles wrapped to three lines at 1280px).
- A refused move's reason wraps inside its row instead of pushing the
  status column ~200px wider.
- The empty list shows a write-up's icon and plain words: "When an
  incident is declared, its postmortem shows up here." (renamed in place in
  all 17 locales).
- The Write Postmortem dialog's note hint ends in one full stop and is
  translated (the Markdown cheatsheet helper added a second one).
- State settings pages keep the Built-in tag on the name's line in a table
  row (it wrapped under the longer names only).

Tests: offline browser suite +4 specs and new checks (tablet tiles, German
fit, title room, refused-move width, button look and phone stack, viewer,
Built-in tag line), each proven against the break it guards; list, page,
state table and tiles unit tests updated; docs facts follow the source.

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

Conflicts: the migrations index (master's 1805830000000 and 1805840000000 first, then this branch's 1805900000000 and 1805910000000) and the Dashboard locales (merged by i18n:extract).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… moves, which keep their places before the last slot

Placed between RemoveRunbookCredentials and AddAuditLogMcpClientColumns, it
broke RemoveRunbookCredentials and MoveRunbookApprovalsBeforeTheirSteps,
whose suites assert each neighbour. It has no ordering requirement among
data migrations (they run after every schema migration), so it sits where
AddProcessColumnsToSecurityEvent does, and its own suite now pins that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simlarsen
simlarsen merged commit aeea62e into master Oct 22, 2026
6 of 67 checks passed
@simlarsen
simlarsen deleted the claude/postmortem-reports branch October 22, 2026 05:58
simlarsen pushed a commit that referenced this pull request Oct 22, 2026
…he CLI README lists postmortem-status

Two more reds on master aeea62e:

- Common Test (1/8): VMwareHostPage's Network tile read 23.5 MB/s, not
  31.5. The test built each series row with its own minutesAgo(2), so a
  millisecond tick between two rows split one aggregate bucket in two -
  the host's own total in one, a NIC in the other - and the page, rightly,
  averaged the two buckets of the recent window. The aggregate returns
  every row of a bucket with that bucket's exact time; the test's rows now
  read the clock once. With a tick forced between rows, the old test reads
  24.3 MB/s; with one clock read it passes, every time.
- CLI Test: #5171 made postmortem statuses a CLI resource
  (postmortem-status), and ReadmeResources requires the README's records
  table to list every resource command. It is in the Incidents row.

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