docs/waves/resilience_work_items.md
Waves Failure Containment and Recovery Work Items
Purpose: track the additive browser, Tauri-host, and engine resilience work found by the 2026-07-29 current-main failure-containment audit.
Audit base: origin/main 6cf1682a (planning sync 2026-07-30).
Status keys:
todoin-progressblockeddone
Product Requirement
One malformed request, response, deck, script, timer event, or host/engine failure must not freeze or crash Waves, create an uncontrolled network storm, corrupt navigation/history state, or prevent the user from loading a known-good deck. Failures must terminate predictably, expose a useful typed error, preserve usable state where appropriate, and leave an explicit recovery path.
Scope and Ownership
- Browser-owned containment stays in
browser/frontend: navigation admission, failed-intent quarantine, recovery UI, history, and diagnostic projections. - Host/IPC containment stays in
browser/src-tauri: request validation, cancellation/concurrency, typed errors, and transactional engine command adaptation. - Runtime work/output limits stay in
engine-wasm: layout/render budgets and native/WASM parity. - WBXML decoding, transport retry semantics, and network policy stay in
transport-rust. - The separately owned public service/deployment/examples work does not satisfy or replace these client-side containment items.
- Coordinate
browser-presenter.tswork through one active presenter/history owner; these tickets change behavior and data handling, not styling.
Immediate Containment Gate
The P1 containment gate is closed: RSL-01 quarantines terminal external-intent failures,
RSL-02 bounds and cancels navigation work, RSL-03 makes mutating frame commands transactional,
and RSL-04 bounds single-pass render output. RSL-05 closes malformed IPC admission and typed
host failures, RSL-06 closes diagnostic/export redaction, and RSL-07 closes bounded
presenter/history state.
Lane A: Navigation Containment
RSL-01 Terminal external-intent failure quarantine
Issue: #510Status:donePriority:P1release blocker; treat asP0for a distributed build exposed to uncontrolled public contentDepends On: noneFiles:
browser/frontend/src/app/navigation-state.tsbrowser/frontend/src/app/engine-timer-runtime.tsbrowser/frontend/src/app/browser-controller.ts- focused tests for those modules
Build:
- Quarantine a terminally failed external intent by request identity plus engine/navigation generation.
- Preserve the invoking engine state and pending intent; do not weaken WML-205 rollback behavior by clearing engine state.
- Permit a new automatic follow only when intent identity changes, or one explicit attempt when the user chooses Reload/retry.
Tests:
- A
WBXML_DECODE_FAILEDtarget followed by 50 timer ticks produces one automatic target fetch. - Explicit Reload causes exactly one new attempt.
- A known-good URL or local deck loads afterward and stops the failed-intent loop.
- The invoking deck, card, history, focus, variables, and pending engine intent remain intact.
Accept:
- Terminal failure produces one bounded outcome and one useful error surface.
- No timer-driven automatic replay occurs without a changed intent or explicit user action.
Resolution:
- Browser navigation now quarantines terminally failed external intents by resolved request identity and navigation generation without clearing engine state. Timer snapshots suppress the same quarantined intent, while explicit Reload/Go and changed intents receive one fresh attempt.
- Focused controller coverage proves one WBXML decode failure plus 50 timer ticks issues one target fetch, preserves the invoking state, deduplicates the failure notification, permits one explicit retry, and recovers through a changed known-good target.
RSL-02 Cancellable and admission-controlled navigation
Issue: #509Status:donePriority:P1Depends On:RSL-01Files:
browser/frontend/src/app/navigation-state.tsbrowser/frontend/src/app/browser-controller.tsbrowser/frontend/src/app/shell-event-bindings.tsbrowser/src-tauri/src/lib.rs- fetch command/client contracts and focused tests
Build:
- Admit or coalesce one logical navigation operation instead of starting an independent fetch for every rapid action.
- Add a cancellable host fetch contract and stop superseded attempts/retries.
- Bound concurrent native fetch tasks while keeping generation checks as the final state-integrity guard.
Tests:
- Eight rapid identical actions produce at most one active fetch.
- Back or a new URL stops superseded work and cannot receive a stale toast, transport-panel update, or history mutation.
- A hung response can be cancelled and followed by a successful known-good load.
Accept:
- Both active work and committed state remain bounded under conflicting navigation.
Resolution:
- Browser navigation now coalesces identical active request identities, assigns each admitted operation a cancellable request ID, and cancels superseded work for changed URLs, Back, Stop, mode changes, and disposal before admitting replacement transport work.
- The generated Tauri contract exposes
cancel_fetch; the host admits at most two native fetch tasks so one cancelled request still blocked in kernel I/O cannot prevent its replacement. The shared transport cancellation token prevents cancelled responses, retries, and gateway fallback from continuing after the active blocking call returns. - Focused frontend and host/transport tests cover eight-way coalescing, stale projection suppression, Back/Stop cancellation, hung-request recovery, bounded admission, and retry cancellation. Navigation generation checks remain the final frontend state-integrity guard.
Lane B: Engine and Frame Resource Safety
RSL-03 Transactional frame commands and viewport validation
Issue: #508Status:donePriority:P1Depends On: noneFiles:
browser/frontend/src/app/browser-controller.tsbrowser/src-tauri/src/contract_types.rsbrowser/src-tauri/src/engine_bridge/engine_adapter.rsengine-wasm/engine/src/engine_public_api.rs- native/WASM/Tauri boundary tests
Build:
- Define and validate one shared viewport range before engine mutation.
- Make every mutating frame command transactional: construct a valid candidate frame before commit or restore the exact previous engine state when frame construction fails.
- Return a typed invalid-input or resource error rather than a generic parse string.
Tests:
u32::MAX + 1fails before mutation.- Forced frame failure after load, input/key, timer, Back, edit, and clear-intent preserves the complete previous state.
- A valid viewport and known-good deck succeed after each failure.
Accept:
- No failed frame command leaves engine and frontend state out of sync.
Resolution:
- Shared viewport bounds now reject out-of-range values with a typed error before mutation.
- Every mutating frame adapter builds the candidate result against a cloned engine and commits only after frame construction succeeds; focused tests cover load, key/input/action, timer, Back, external-intent, input-edit, and select-edit failure paths plus successful recovery.
RSL-04 Bounded, single-pass render output
Issue: #505Status:donePriority:P1Depends On:RSL-03Files:
engine-wasm/engine/src/layout/flow_layout.rsengine-wasm/engine/src/engine_public_api.rsbrowser/src-tauri/src/engine_bridge/engine_adapter.rsbrowser/frontend/src/app/browser-presenter.ts- native/WASM/Tauri/frontend tests
Build:
- Bound layout rows, segments, draw commands, and serialized frame bytes in the engine.
- Return a typed resource-limit failure with no partial state/presentation commit.
- Derive legacy render and presentation output from one layout pass during migration.
- Retain a defensive frontend output cap before HTML/DOM work.
Tests:
- Native and WASM fixtures exactly at and one unit above each output limit.
- Rejected pathological output leaves the last good frame visible and a small deck renders next.
- Tauri frame construction proves one layout pass and native/WASM frame parity remains stable.
Accept:
- Any accepted deck has a deterministic upper bound on render work and host-visible output.
Resolution:
- The engine now stops layout at 4,096 rows, 4,096 segments, and 4,096 legacy draw commands, and
caps the combined legacy/presentation JSON projection at 2 MiB. Rust-generated
EngineRenderError/ENGINE_RENDER_LIMITScontracts keep native, WASM, Tauri, and frontend enforcement aligned. - The Tauri compatibility frame consumes one engine
render_output()result, so legacy and presentation projections share one instrumented layout pass. Candidate mutation still commits only after bounded frame construction succeeds; focused host tests preserve the last good frame and render a small replacement immediately after rejection. - Exact-limit and one-over-limit native/WASM tests cover every budget, the presenter rejects
oversized host output before cloning or canvas work, and the
RSL-04wrapping story remains navigable through the generated example corpus.
Lane C: IPC Contract Hardening
RSL-05 Bounded request ingress and typed host errors
Issue: #507Status:donePriority:P2Depends On: none; thewapcurlstream is landed, but its CLI behavior remains out of scopeFiles:
transport-rust/src/lib.rstransport-rust/src/request_serialization.rsbrowser/src-tauri/src/lib.rsbrowser/src-tauri/src/contract_types.rs- generated host contracts
browser/frontend/src/app/tauri-invoke-guard.ts
Build:
- Define aggregate limits for request headers, IDs, POST fields, encoded request bodies, card IDs, and edit drafts at their owning Rust boundaries.
- Reject before transport/spawn work and never echo sensitive payloads in error details.
- Generate a typed host error envelope and validate non-null IPC responses structurally without hand-copying contract schemas.
Tests:
- One-over-limit tests for every bounded field and aggregate.
- Invalid request, cancellation, spawn/join, mutex, engine resource, and response-shape failures remain distinguishable and recoverable.
- Contract-generation and drift checks pass.
Accept:
- Malformed IPC terminates predictably before expensive work and all commands remain usable.
Coordination:
- Do not change
transport-rust/src/request_meta.rs, transport retry semantics, orwapcurlCLI exit diagnostics as part of this item.
Resolution:
- Rust-owned request and host ingress budgets are generated into the TypeScript contracts. Every ticketed field and aggregate has a one-over test, with command-level coverage proving rejection precedes fetch registration, task admission, transport execution, and engine locking.
- RSL-05 transport and engine host commands return the generated
HostCommandErrortaxonomy; the generated invoke client derives runtime validators from the same Rust-projected declarations. Invalid non-null response shapes fail closed, opaque failures are redacted, and recovery tests call commands successfully after boundary, mutex, and malformed-response failures. - Evidence:
make lint-rust-transport,make test-rust-transport, browser-hostcargo clippyand serializedcargo test, frontend test/lint/typecheck/format checks,contracts:check,tauri:schemas:check, andgit diff --checkpass.
Lane D: Diagnostic and UI State Bounds
RSL-06 Redacted developer and timeline projections
Issue: #506Status:donePriority:P2securityDepends On: noneFiles:
browser/frontend/src/session-history.tsbrowser/frontend/src/app/timeline.tsbrowser/frontend/src/app/browser-presenter.ts- associated history/timeline/presenter tests
Build:
- Keep exact internal request identity for WML history replay.
- Build explicit allowlisted/redacted developer-panel and export DTOs.
- Redact secret headers, legacy payloads, and typed form values while retaining safe method/count/ content-type/length metadata.
Tests:
- PIN/password, Authorization, Cookie, Proxy-Authorization, legacy payload, and typed post-field values never appear in panel/export JSON.
- Internal Back still replays the byte-exact original POST.
Accept:
- Diagnostic artifacts are useful without disclosing replay credentials.
Resolution:
- Timeline entries are projected into a fixed allowlisted DTO when produced, while host history continues to retain the exact request identity needed for standards-compatible Back replay.
- Drawer, detached diagnostic, and version 2 timeline-export serialization all consume the same projection. URL userinfo and credential-like query values are removed, request bodies and typed post-field values become count/length metadata, secret header values and arbitrary error details are omitted, and decoded/source payloads do not enter diagnostic state.
- Focused frontend coverage exercises secret canaries, near-miss query names, raw transport/runtime failures, producer-boundary projection, deterministic metadata, and byte-exact internal POST history preservation.
RSL-07 Bounded toast and host-history state
Issue: #504Status:donePriority:P2Depends On:RSL-06Files:
browser/frontend/src/app/browser-presenter.tsbrowser/frontend/src/session-history.tsbrowser/frontend/src/app/timeline.ts- associated tests
Build:
- Deduplicate and cap identical queued toasts.
- Let successful recovery supersede stale failure notifications.
- Define deterministic oldest-entry history eviction with a documented retained WML back depth.
Tests:
- 97 identical failures remain within capacity and create one accessible failure announcement.
- A later successful load becomes visible immediately.
- A 10,000-navigation simulation keeps history and exported state bounded while Back/index/forward truncation remain deterministic within the retained window.
Accept:
- UI and host-session collections remain bounded and preserve an obvious recovery signal.
Resolution:
- Toast state retains at most four notifications (one visible plus three queued), coalesces identical message/tone pairs, and lets a successful recovery status or toast immediately remove stale failures. Repeated identical failures write the accessible live region once.
- Host history retains 32 entries: the current entry plus 31 deterministic WML Back steps. Forward history is truncated before a push, then overflow evicts the oldest entry and re-bases the index to the retained window. Retained POST request identities are independently cloned and remain byte-exact for replay.
- Timeline production and exported diagnostic state retain at most 200 already-redacted entries, even if a caller requests a larger window. A 10,000-navigation simulation covers history, timeline, toast, and export bounds.
- Issue
#450remains a separate follow-up: this eviction policy preserves every entry it receives (including duplicates) but does not repair same-card history identity lost across deck replacement. Persistent/searchable history must continue to wait for that identity fix.
Dispatch Order and Conflict Map
Completed containment and IPC batches:
RSL-01navigation quarantineRSL-02cancellable/admission-controlled navigationRSL-03transactional frame commandsRSL-04bounded single-pass render outputRSL-05bounded ingress and typed host errors
Completed diagnostic/UI-state sequence:
RSL-06diagnostic and export redaction.RSL-07bounded toast/history state on the completed RSL-06 projection boundary.
Issue #450 history identity/cross-deck correctness remains required before persisted or searchable
history.
Likely conflicts:
- issue
#450/ WBP-11 / merged shell presentation: host-history and presenter surfaces