Files
kandev/docs/plans/canvas-runtime-entry-recovery/plan.md
T
2026-09-21 23:20:52 +01:00

8.8 KiB

created, status, requirements, system_design, legacy_specs
created status requirements system_design legacy_specs
2026-09-21 done
REQ-PLUGINS-ISOLATED-WEB-APPS-012
REQ-PLUGINS-ISOLATED-WEB-APPS-013
REQ-CANVASES-AGENT-WEB-APPS-001
REQ-CANVASES-AGENT-WEB-APPS-006
../../specs/plugins/system-design/isolated-web-app-contributions.md
../../specs/plugins/system-design/runtime-response-preservation.md
../../specs/canvases/system-design/agent-authored-web-apps.md
../../specs/canvases/system-design/task-entry-presentation.md

Implementation Plan: Canvas runtime and task-entry recovery

Overview

Prevent automatic proxy injection into canvas responses. Then show unseen published canvases when users return to their tasks. Both changes reuse the existing runtime and host surfaces.

Evidence and diagnosis

The incident involved task f6136adf-46a6-422f-831c-5a35caf04b3d and canvas 09549bca-9ad4-4169-9d4f-2913e8bfc1b3. The author reported active release 21bf0113-73fe-42c8-8b11-9bbf4ca0db27 as valid.

Backend logs recorded canvas.release.activated at 10:19:28 UTC on September 21. Browser logs recorded task restoration without its canvas panel at 13:14:02 UTC. The user confirmed that they returned after publication.

The screenshot showed Canvas unavailable. The reported console error identified a CSP-blocked Cloudflare beacon. The exact embedded startup JavaScript reproduced the failure mechanism in an isolated Node VM. Without a resource error, it requested context once and reported Ready. A simulated beacon script error reported failed/document_error and made no context request.

This is a source-level reproduction, not a capture of the live frame handshake. The diagnostic archive was partial and lacked publication-time browser events. The source nonetheless establishes both relevant paths:

  • hostRuntimeBootstrap rejects resource errors. setRuntimeHeaders currently sends only no-store, leaving no explicit prohibition on proxy transformation.
  • useTaskCanvasLifecycleActivation depends on volatile lifecycle hints. Task entry does not reconcile the published HTTP inventory with the workbench.

The runtime design already prohibits proxy HTML injection. Preserve that contract. Cloudflare documents the transformation directive in its Web Analytics FAQ. The first-release requirement covers live publication. New criteria AC-CANVASES-AGENT-WEB-APPS-001.13 through .16 define later task entry.

Scope

In scope

  • Runtime no-transform response policy and realistic HTTPS proxy coverage.
  • HTTP inventory reconciliation on task entry, reload, and reconnect.
  • Main editor placement, one focus change, and browser-tab dismissal memory.
  • Phone route behavior and prevention of Back-navigation loops.
  • Operator and user documentation in docs/public/canvases.md.

Out of scope

  • Live Cloudflare configuration changes or live canvas republishing.
  • CSP relaxation, ignored script errors, new grants, or new runtime flags.
  • Cross-device presentation history or changes to canvas package storage.
  • Claims that this investigation verified the live deployment after correction.

Technical approach

Task 01 changes setRuntimeHeaders in the shared plugin runtime. Extend the existing authenticated proxy fixture with directive-aware HTML injection. Its negative control removes no-transform and demonstrates the existing failure. Keep package bytes, capability checks, cookie forwarding, and SSE intact.

Task 02 shares the task-page canvas inventory with the activation hook. Reconcile only after the target environment finishes layout restoration. Use current HTTP metadata for every candidate. Record offered canvases after presentation, following the existing PR-panel session-storage pattern. Receipt identity includes user, workspace, task, and canvas, not release. Manual opening and restored panels also record presentation.

Desktop adds every eligible unseen canvas and focuses only the deterministic last candidate. Existing panels never move. Phones open one candidate and mark the batch offered after confirmed navigation. Other candidates remain in the picker. The nearest phone exemplars are task-layout.tsx and CanvasHostFrame. Their full-height route suits primary content and retains existing scroll ownership, safe areas, accessible controls, and touch targets.

Related completed packages remain historical evidence: same-origin authentication and first-release UX. Their existing happy-path scenarios must remain covered alongside these regressions. No new ADR is needed: this preserves the runtime boundary and extends the existing tab-local offered-marker pattern. Specifications retain the local rationale.

ASCII UI preview

UI-01: Returning to a task after publication, desktop.

Before: main editor [Agent] [Plan] [+]
        Canvas requires manual selection.

After:  main editor [Agent] [Plan] [Task coordinator *] [+]
        +-------------------------------------------+
        | Existing canvas toolbar                   |
        | Canvas application fills remaining space  |
        +-------------------------------------------+

UI-02: Returning to the same task, phone.

+--------------------------------+
| Existing navigation | Canvas   |
| Existing host actions          |
|                                |
| Focused canvas application     |
| One content scroll region      |
+--------------------------------+
Back -> task, without redirecting again

The main editor group, one focused canvas, and existing phone route are required. Spacing and titles are illustrative. No new toolbar or visible copy is required. Permission-review canvases show the existing review state before execution. Real runtime failures keep the existing unavailable state and Retry action.

Tests

  • AC-PLUGINS-ISOLATED-WEB-APPS-013.8: extend runtime_test.go with TestRuntimeNoTransformHeaders for entry HTML, nested assets, and bootstrap.
  • AC-PLUGINS-ISOLATED-WEB-APPS-012.1: preserve startup error tests and the injected-script negative control.
  • AC-CANVASES-AGENT-WEB-APPS-001.2, .13 through .16: extend dockview-canvas-activation.test.tsx, use-task-canvases.test.ts, and a focused receipt-storage test. Include mixed eligible and ineligible inventory.

E2E tests

  • Desktop and phone authenticated-proxy specs prove retained runtime startup with transformation prevention, plus the negative control on desktop.
  • Desktop and phone plugin-canvas specs prove publication before navigation, reload, receipt persistence, manual reopening, and no focus/navigation loops.
  • Desktop also proves main editor placement after delayed layout restoration.
  • Feature-disabled, wrong-task, unavailable, and permission-review paths retain focused unit/component coverage and existing rendered scenarios.

Work orders

Execute sequentially. Each work order contains exact commands and owns its tests. No delegation is authorized.

Verification results

Planning: the isolated bootstrap probe reproduced the failure mechanism. Implementation and rendered verification are complete. Backend runtime tests, focused web tests, full web lint, i18n checks, web typecheck, and the managed desktop and phone E2E suites passed. make -C apps/backend build and pnpm --filter @kandev/web build:vite passed. The authenticated proxy suites passed with 5 desktop and 2 phone tests; the task-entry suites passed with 6 desktop and 4 phone tests. The focused component and hook suite passed 61 tests, including deferred request invalidation, authenticated identity, mixed inventory, delayed layout ownership, batch focus, restored-panel receipts, and duplicated-tab receipt isolation. Full web lint passed with zero warnings. pnpm run i18n:check passed; it reported the repository's existing orphan catalog warnings without failing. Public-doc validation passed 62 tests and validated 47 pages. python3 scripts/list-docs.py validate passed with 294 decisions and 1068 specifications, python3 scripts/lint-spec-files.py --all passed, and python3 scripts/lint-spec-files.test.py passed all 36 tests. git diff --check passed.

Risks

  • A proxy can override origin headers. The real deployment still needs an operator smoke check, and can require a runtime-path analytics exclusion.
  • Old canvases have no presentation receipts. The first corrected task visit can offer them once. Existing panels count as already presented.
  • Blocked session storage falls back to memory. Reload persistence then cannot be guaranteed, but manual access must continue to work.
  • Async restoration and task switches can misplace panels unless generation and environment checks occur immediately before insertion.