webview_backpressure_spec - mark-ik/graphshell GitHub Wiki
Date: 2026-03-12
Status: Canonical runtime policy contract
Priority: Immediate lifecycle/runtime traceability
Related docs:
node_lifecycle_and_runtime_reconcile_spec.mdwebview_lifecycle_and_crash_recovery_spec.mdarchived embedder decomposition plan../../technical_architecture/2026-03-12_specification_coverage_register.md
This spec defines the runtime admission, retry, timeout, and cooldown policy implemented by webview_backpressure.rs.
It governs:
- when webview creation is attempted,
- how provisional creation is confirmed,
- how retries and cooldown are applied,
- when a node becomes
RuntimeBlocked, - how blocked state is cleared,
- diagnostics and test obligations.
It does not govern:
- general lifecycle state semantics beyond the backpressure policy,
- crash recovery for already-attached webviews,
- viewer fallback rendering policy except where blocked state must be surfaced.
Webview backpressure is the admission-control policy for activating webview-backed nodes under unstable or overloaded runtime conditions.
Current product meaning:
- Servo webview creation is not directly fallible in the embedder API,
- Graphshell therefore infers success or failure from downstream evidence,
- repeated unconfirmed create attempts are bounded and eventually converted into explicit blocked state.
Normative rule:
- failed or unstable activation must become explicit runtime state,
- not an invisible retry loop.
Per-node tracked state:
retry_count-
pendingcreation probe cooldown_untilcooldown_step
Current meaning:
-
pendingmeans a create attempt has been issued and awaits confirmation, -
retry_countcounts creation attempts since the last confirmed success or cooldown reset, -
cooldown_untilprevents immediate reattempt after exhaustion, -
cooldown_stepdrives exponential cooldown backoff.
Normative rule:
- this state is runtime policy state, not canonical node/domain truth,
- it must remain per-node and bounded.
ensure_webview_for_node(...) may attempt creation only when:
- the node exists,
- the node lifecycle is
Active, - runtime has
viewer:webviewcapability, - there is no confirmed existing live/responsive mapped webview for that node,
- the node is not currently in cooldown,
- there is no pending unresolved probe for that node.
If the app still believes a node is mapped to a webview but the window no longer contains that webview:
- an explicit
UnmapWebviewruntime event is emitted, - backpressure state remains authoritative for the next attempt.
When a create attempt starts:
- a webview is created or finalized from a pending create request,
- node-to-webview mapping is emitted,
- the node is promoted toward active runtime use,
- a creation probe is armed,
-
retry_countincrements.
Normative rule:
- a create attempt is real only after a concrete host/webview creation path is taken and a probe is armed,
- merely desiring activation does not count as a retry.
Because creation is not synchronously fallible, confirmation is inferred.
Current confirmation signals:
- the webview emits a responsive semantic signal, or
- the window contains the webview and it remains live past the confirmation window.
Current timing constants:
- confirmation window: 2 seconds
- timeout window: 8 seconds
Outcome classification:
ConfirmedPendingTimedOut
Normative rule:
- a webview create attempt is considered successful only after one of the confirmation conditions is satisfied,
- not merely because a create call returned.
If a pending probe reaches timeout without confirmation:
- the webview is closed if still present,
- the mapping is explicitly unmapped,
- the pending probe is cleared,
- the node remains eligible for retry unless retry exhaustion is reached.
Current maximum retries before cooldown:
WEBVIEW_CREATION_MAX_RETRIES = 3
Normative rule:
- retry loops must be bounded,
- repeated unstable creation must not churn indefinitely in the hot path.
After retry exhaustion:
- exponential cooldown is armed,
-
RuntimeBlocked(CreateRetryExhausted)is emitted withretry_at, -
retry_countresets, - the node remains blocked until cooldown expires and a subsequent clear path runs.
Current cooldown behavior:
- exponential backoff,
- minimum 1 second,
- maximum 30 seconds,
- bounded step growth.
When cooldown has elapsed and reconcile revisits the node:
- cooldown is cleared,
- blocked state is explicitly cleared,
- retry budget is reset,
- normal create-attempt logic may resume.
Normative rule:
- cooldown expiry clears the blocked state explicitly; it is not merely implied by time passing.
This module is a canonical source of RuntimeBlocked(CreateRetryExhausted) for webview-backed activation failure.
Current meaning:
-
RuntimeBlockedis not a generic rendering hint here, - it specifically means repeated creation attempts failed to reach confirmed live state.
Required behavior:
- blocked state must be visible to lifecycle/viewer/compositor consumers,
- blocked state should carry a retry time when cooldown is active,
- success confirmation or cooldown-expiry clear path must emit
ClearRuntimeBlocked.
Normative rule:
- if a tile or node is shown as
RuntimeBlockedbecause of webview create exhaustion, this module must be traceable as the source of that state.
Backpressure does not replace lifecycle; it constrains activation.
Relationship to lifecycle specs:
- lifecycle still governs whether a node is eligible for activation at all,
- backpressure governs whether activation is presently admitted,
-
RuntimeBlockedpreserves explicit failure state without silently changing canonical node identity.
Current code behavior:
- only
Activenodes are considered for ensure/retry, - non-
Activenodes drop backpressure state.
Normative rule:
- backpressure state is subordinate to lifecycle eligibility,
- not an alternate lifecycle state machine.
Current diagnostic signals include:
- create attempt
- confirmation
- timeout
- cooldown
- span durations for ensure/reconcile
Required diagnostics semantics:
- create attempts are observable,
- confirmation latency is observable,
- timeout is observable,
- cooldown entry is observable,
- blocked/clear runtime events remain the user-visible lifecycle boundary.
Normative rule:
- diagnostics must make it possible to explain why a node became
RuntimeBlocked(CreateRetryExhausted).
Required coverage:
- probe confirms on responsive signal,
- probe confirms on stable live webview after confirmation window,
- probe times out without confirmation,
- cooldown delay is bounded and monotonic by step,
- cooldown arm updates deadline and step,
- timed-out probe closes/unmaps stale webview,
- retry exhaustion emits blocked state with retry time,
- cooldown expiry clears blocked state and resets retry budget,
- non-
Activenodes do not retain backpressure state, - source URL restoration for cold restore is deterministic.
- create confirmation remains explicit and inferential, not assumed from API success.
- retry loops remain bounded.
- cooldown policy remains explicit, exponential, and test-covered.
-
RuntimeBlocked(CreateRetryExhausted)remains traceable to this policy. - blocked-state clear paths are explicit and test-covered.
- lifecycle and compositor consumers can rely on this spec as the source for webview-create exhaustion semantics.