fix: stabilize canvas runtime and permission review (#3600)

This commit is contained in:
Carlos Florêncio
2026-09-11 15:51:32 +01:00
committed by GitHub
parent 76ab362701
commit 86b96fd14e
67 changed files with 4829 additions and 644 deletions
@@ -6,7 +6,7 @@ system: canvases
owners:
- canvases
created: 2026-08-26
last_updated: 2026-09-08
last_updated: 2026-09-10
requirements:
- REQ-CANVASES-AGENT-WEB-APPS-001
- REQ-CANVASES-AGENT-WEB-APPS-002
@@ -78,10 +78,7 @@ standard web protocol that the Plugins system owns.
## Implementation baseline and feature gate
Implementation starts from current `main`. PR #3061 contains the superseded
declarative canvas implementation and must not merge as a prerequisite. The
new implementation creates the canvas model and host surfaces directly from
this design.
PR #3061's declarative implementation is superseded, not a prerequisite.
The runtime flag identity is `features.canvases`. Its environment variable is
`KANDEV_FEATURES_CANVASES`. The first implementation sets `prod`, `dev`, and
@@ -188,7 +185,8 @@ The normal flow starts in a task conversation:
8. The agent calls `publish_canvas_kandev` with the canvas ID and source path.
9. Kandev reads that directory through the trusted task execution file API.
10. The Plugins service validates and stores an immutable release.
11. The canvas activates immediately when its permissions fit existing grants.
11. The canvas activates when its permissions fit existing grants or its
recorded [initial creation authority](local-creation-authority.md).
12. The task client receives a lifecycle event and opens the new canvas.
The source directory is workspace-relative and scoped to the current execution.
@@ -253,23 +251,12 @@ The optional section is absent when the resolved profile lacks canvas tools.
This covers canvas requests inside ordinary task conversations, independently
of the guided task preset.
`CanvasTaskCreateLauncher` retains the localized
`CanvasTaskCreateLauncher` retains the visible, editable
`canvases:createCanvasTaskPrompt` preset in the normal `TaskCreateDialog`.
The preset is visible and editable. Proposed English wording:
> Create an interactive canvas inside Kandev for the application I describe.
> If the application goal is missing, ask what the canvas must show or do.
> Find the Kandev canvas MCP tools before writing application files.
> If they are not callable, use native tool search for `kandev canvas` or inspect the available MCP catalog.
> Call `create_canvas_kandev` to create the draft and obtain its source directory.
> Read `read_canvas_authoring_skill_kandev` once without a path.
> Build inside the returned directory and use authorized live Kandev data for domain views.
> Call `publish_canvas_kandev` and address any validation errors.
> Report the canvas identity and whether its release is active, awaits permission review, or was unsuccessful.
> If publication is unsuccessful, report the failure and do not claim that the canvas is published.
> If workspace access requires promotion, explain the user action that is still required.
> A local build alone does not publish a canvas inside Kandev.
> If the tools remain unavailable, report the limitation instead of claiming that workspace files are a Kandev canvas.
The locale catalog owns the exact wording. It names discovery, creation,
assigned-root authoring, live data, the single core skill read, publication,
and honest outcome reporting. It explains permission review and promotion
when required, and does not equate local files or a build with publication.
The existing selected question capability governs any clarification. The
preset cannot grant a question tool to an autopilot session that lacks one.
@@ -376,6 +363,10 @@ If the declaration needs more permission, the release gets
`pending_permission` status. The service publishes
`canvas.release.permission_required`. The active release remains unchanged.
Recorded owner-authorized first publication uses
[the creation authority transaction](local-creation-authority.md) instead.
The generic publish and manual review paths do not infer that authority.
Rollback selects the retained prior valid release. It does not restore old
grants that the user revoked. If the current grants do not cover the old
release, rollback needs a permission review.
@@ -409,6 +400,41 @@ A release that adds permissions uses the same review component. Removing a
declaration does not need approval. The effective grant contracts to the new
declaration after activation.
### Readable review surfaces
`CanvasReleaseDialog` and `CanvasPromotionDialog` share a permission view model
and human-readable provenance. Show release creation time, author kind, source
task title, and source session name when currently authorized. Use an
unavailable-source label for deleted or inaccessible records. Raw UUIDs stay in
API identities and action payloads, never headings, accessible labels, or copy.
Add optional source labels to the HTTP release/promotion projections through
authorized task/session lookups; avoid client-side lookup waterfalls.
Select the pending release by default, otherwise the active release. A compact
release selector preserves access to retained history. Distinguish Active from
Previous for valid releases by comparing with `active_release_id`. Render one
grouped declaration with newly requested rows marked. Use localized semantic
labels for reads, writes, state, and supported event/resource names; preserve
exact normalized network origins. Unknown values have a localized unsupported
permission label and cannot be approved silently. Keep rejection reasons and
real validation errors separate from normal permission review.
On desktop use a viewport-bounded wider dialog (target 48rem maximum width)
with a fixed title and action footer. The single middle region can scroll;
remove the 288px cap and repeated declared/missing-permission blocks. Pending
release actions are Approve and Reject, retained release action is Roll back,
and current release has Close. Reuse unchanged stale-review safeguards.
On phones use the full-height focused surface pattern from `task-layout.tsx`,
with header/footer and internal scrolling mechanics from
`mobile-menu-sheet.tsx`. This deep release review warrants a full-height
surface; the short host action chooser remains an inset bottom drawer.
Use `useResponsiveBreakpoint`, dynamic viewport height, safe areas, and
touch-only targets of at least 44px. Desktop controls remain 28px. Share
selection, actions, loading, and errors between presentations. Dismissal returns
focus to the opener; a release change during review refreshes the selection and
disables stale actions. No horizontal document overflow is permitted.
## Quick Chat editing
The workspace canvas host has an Edit canvas action. It calls a canvas edit
@@ -609,6 +635,14 @@ The iframe can remain visible during an event-stream reconnect. The host shows
the offline state outside the application. If the runtime token expires, the
host requests a new URL and reloads the same active release.
Receiving a descriptor keeps `loading_runtime` and mounts the frame behind its
loading cover. `CanvasHostSurface` must mount during this state, not only Ready.
Only the current [plugin startup acknowledgement](../../plugins/system-design/isolated-web-app-contributions.md#runtime-startup-protocol)
sets Ready. A failed or absent acknowledgement within 15 seconds tears down the
frame and exposes Retry and Releases. Do not claim a specific CSP or network
cause from the generic timeout. Retry, renewal, navigation, and authority
changes fence old callbacks. Appearance remains applied before reveal.
If the release is unavailable, the host offers Edit, Releases, Roll back, or
Remove according to current permissions. It never loads a rejected artifact.
@@ -628,23 +662,14 @@ repositories, sessions, or external services by itself.
The plugin runtime repeats resource authorization for each request. Canvas
authorization does not replace task or workspace authorization.
## Baseline from the superseded declarative work
The declarative implementation is not on `main` and is not a released
contract. PR #3061 must close or remain unmerged. Implementation does not merge
that block model before it creates the plugin-backed model.
Development databases that ran PR #3061 can keep unused declarative tables.
The new implementation does not read them. It does not add a destructive
startup migration for those development-only tables.
## Failure handling
- A missing task agent disables the create prompt and shows how to start one.
- A source read error preserves the active release.
- A package validation error returns safe file and rule diagnostics to the
authoring agent.
- A permission increase creates a pending release.
- A permission increase after initial owner-authorized publication creates a
pending release.
- A promotion transaction either changes scope and grants together or changes
neither.
- A Quick Chat launch error leaves releases unchanged.