Disciplines · Runbooks

Runbook — Shell Outage

Use this runbook when the shell itself — not a single domain or assistant — is the failure boundary.

10sections5 minread

On this page

Customer or admin shell is unreachable, unable to bootstrap, or returning 5xx on critical routes. Affects shell_web, shell_pwa, shell_mobile, shell_admin_web, or shell_admin_mobile.

Scope#

Use this runbook when the shell itself — not a single domain or assistant — is the failure boundary. Examples:

  • HTML/CSS/JS bundle 5xx from the CDN or origin.
  • BFF bootstrap (/api/bff/bootstrap) returns 5xx, times out, or returns malformed JSON.
  • Service worker fails to register or returns stale assets in a release window.
  • Auth session cookie cannot be issued or refreshed.
  • Mobile shell cannot reach update manifest and falls below the minimum supported build.

If only a single domain card (Tara/Veritas/etc.) is broken, use the matching domain runbook instead. If the assistant is the failure boundary, use assistant-failure.md.

Severity classification#

Sev Condition Targets
sev1 >5% of customer sessions cannot bootstrap for >5 min, OR admin shell unreachable during an active incident. shell_*, bff_consumer, bff_admin
sev2 Bootstrap success ratio 95–99% for >10 min, OR PWA stuck on stale bundle for >15 min. shell_*, cdn, bff_consumer
sev3 Single platform regression (e.g., iOS-only) below 99% bootstrap, OR home rail render-error rate above budget. shell_mobile, shell_pwa

The ratio is count(shell.bootstrap.completed{success=true}) / count(shell.bootstrap.started) per the customer taxonomy.

Detection signals#

  • Alerts: any service.shell_* health-target alert from libs/oshun/analytics/src/dashboards-service-health.ts; the shell.bootstrap.failed rate panel on the customer-KPI dashboard.
  • Synthetic probes: probe.shell_web.bootstrap and probe.shell_mobile.bootstrap in the synthetic-monitor suite.
  • Customer support inbox: spike on tickets tagged support.case.tags.app_wont_load or support.case.tags.blank_screen.
  • CDN: origin error ratio > 2% on shell_web or asset 5xx > 1% over 5 min.

Initial triage (first 5 minutes)#

  1. Open the on-call rotation for oshun-shell-web-oncall (or the matching shell-target on-call from incident-ownership-manifest.ts) and confirm primary acknowledged.
  2. Open dashboards-service-health.ts shell panel — record the failing target, p99 latency, error ratio, and the active build/version per platform.
  3. Decide blast radius:
    • One platform (e.g., only iOS) → suspect a platform release.
    • All platforms, one region → suspect CDN/edge or regional dependency.
    • All platforms, all regions → suspect BFF bootstrap or shared dependency (auth, config service, Postgres primary).
  4. Page bff_consumer or bff_admin on-call (per incident-ownership-manifest.ts) if the BFF is implicated.

Diagnosis#

  1. Confirm the active release:
    • Customer web: read X-Oshun-Release header from the CDN.
    • Mobile: check the active minimum-version row in the release-taxonomy manifest.
  2. Check recent deploys (last 60 min) — release-taxonomy emits release.publish.completed and release.canary.advanced. Correlate against the bootstrap-success drop.
  3. Inspect BFF bootstrap traces (OpenTelemetry span bff.consumer.bootstrap) — look for the slowest downstream dependency span (Postgres, Redis, feature-flag, auth, evidence index).
  4. Inspect CDN logs for origin error ratio per edge POP. If only one POP is bad, instruct CDN failover.
  5. Inspect service-worker telemetry (pwa.sw.activated, pwa.sw.activation_failed) for stale or broken activation.
  6. Read the most recent change-management entries in release-taxonomy.ts — kill-switch state, config flags toggled, and tenant rollout cohorts. A misconfigured flag is the most common shell outage cause.

Mitigation#

  1. Rollback (default mitigation). Use the matching release-taxonomy rollback hook for the affected target: web canary → previous stable build; mobile → revert minimum-version row; PWA → publish service-worker cleanup build that purges stale caches.
  2. Kill-switch a recent flag: if a feature flag in release-taxonomy.ts was advanced in the last hour, set its cohort to 0% via the flag-admin API and observe bootstrap recovery. Document the flag ID and operator in the incident log.
  3. CDN edge failover: instruct the CDN to fail over the affected POPs to a secondary; do not modify origins.
  4. Status banner: publish the incident.customer.status_page.investigating template and the incident.customer.in_app.investigating in-app banner with the canonical bodyPlaceholders filled in (service, impact_summary, next_update_at). Banner copy is owned by the reliability lead; do not improvise.
  5. Mobile minimum-version path: if the rollback also raises the minimum supported build, schedule the forced-update banner via the release-taxonomy minimum-version event and verify the in-app forced-update path renders.
  6. Auth-session preservation: never invalidate sessions during a shell outage. If a config push must clear sessions, capture the customer-impact estimate first and reclassify to a sev1.

Communication cadence#

Phase Template ID Audience Cadence
Investigating incident.customer.status_page.investigating status_page within 5 min
Investigating incident.customer.in_app.investigating customer within 5 min
Internal incident.internal.slack.investigating internal within 2 min
Identified incident.customer.status_page.identified status_page within 30 min
Mitigating incident.customer.status_page.mitigating status_page every 30 min
Monitoring incident.customer.status_page.monitoring status_page when mitigated
Resolved incident.customer.status_page.resolved + .email.resolved both within 60 min
Postmortem incident.customer.status_page.postmortem status_page within 5 biz day

Use the canonical template IDs from libs/oshun/analytics/src/incident-ownership-manifest.ts — do not invent ad-hoc copy.

Escalation#

Standard escalation from incident-ownership-manifest.ts applies:

  1. Primary on-call (5 min)
  2. Secondary on-call (5 min)
  3. Engineering manager (15 min)
  4. Incident commander (30 min)
  5. Executive on-call (60 min)

A sev1 declared at minute 0 reaches incident commander by minute 25.

Recovery verification#

The incident is monitoring once:

  • Bootstrap success ratio is ≥ 99.5% across all platforms for 15 min.
  • CDN origin error ratio is < 0.5% for 15 min.
  • No new customer support tickets tagged app_wont_load in the last 10 min.
  • Synthetic probes probe.shell_*.bootstrap green across all regions.

It is resolved once the above hold for 60 min and the canary advances back to baseline.

Post-incident#

  • File postmortem in docs/incidents/ within 5 business days; link the incident ID, all release-taxonomy and flag-admin actions taken, the affected cohort estimate, and remediation owners.
  • Attach the audit export of all release.* and release-taxonomy.* events in the incident window.
  • Update dashboards-service-health.ts if a new signal is needed.
  • Convert any improvised commands into release-taxonomy rollback hooks.
  • If a feature flag was implicated, raise a rollout-policy ticket (cohort size, ramp speed, kill-switch criteria).