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, orshell_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 fromlibs/oshun/analytics/src/dashboards-service-health.ts; theshell.bootstrap.failedrate panel on the customer-KPI dashboard. - Synthetic probes:
probe.shell_web.bootstrapandprobe.shell_mobile.bootstrapin the synthetic-monitor suite. - Customer support inbox: spike on tickets tagged
support.case.tags.app_wont_loadorsupport.case.tags.blank_screen. - CDN: origin error ratio > 2% on
shell_webor asset 5xx > 1% over 5 min.
Initial triage (first 5 minutes)#
- Open the on-call rotation for
oshun-shell-web-oncall(or the matching shell-target on-call fromincident-ownership-manifest.ts) and confirm primary acknowledged. - Open
dashboards-service-health.tsshell panel — record the failing target, p99 latency, error ratio, and the active build/version per platform. - 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).
- Page
bff_consumerorbff_adminon-call (perincident-ownership-manifest.ts) if the BFF is implicated.
Diagnosis#
- Confirm the active release:
- Customer web: read
X-Oshun-Releaseheader from the CDN. - Mobile: check the active minimum-version row in the release-taxonomy manifest.
- Customer web: read
- Check recent deploys (last 60 min) — release-taxonomy emits
release.publish.completedandrelease.canary.advanced. Correlate against the bootstrap-success drop. - Inspect BFF bootstrap traces (OpenTelemetry span
bff.consumer.bootstrap) — look for the slowest downstream dependency span (Postgres, Redis, feature-flag, auth, evidence index). - Inspect CDN logs for origin error ratio per edge POP. If only one POP is bad, instruct CDN failover.
- Inspect service-worker telemetry (
pwa.sw.activated,pwa.sw.activation_failed) for stale or broken activation. - 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#
- 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
cleanupbuild that purges stale caches. - Kill-switch a recent flag: if a feature flag in
release-taxonomy.tswas 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. - CDN edge failover: instruct the CDN to fail over the affected POPs to a secondary; do not modify origins.
- Status banner: publish the
incident.customer.status_page.investigatingtemplate and theincident.customer.in_app.investigatingin-app banner with the canonicalbodyPlaceholdersfilled in (service, impact_summary, next_update_at). Banner copy is owned by the reliability lead; do not improvise. - 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.
- 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:
- Primary on-call (5 min)
- Secondary on-call (5 min)
- Engineering manager (15 min)
- Incident commander (30 min)
- 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_loadin the last 10 min. - Synthetic probes
probe.shell_*.bootstrapgreen 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.*andrelease-taxonomy.*events in the incident window. - Update
dashboards-service-health.tsif 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).