diff --git a/platform/known-issues.md b/platform/known-issues.md index 99ae821..7c4a6db 100644 --- a/platform/known-issues.md +++ b/platform/known-issues.md @@ -22,22 +22,22 @@ and missing pieces. Entries are **recorded, not fixed**; they feed the product r | KI-008 | Charts | UX | S3 | Saving an existing chart takes two steps: **Update** opens a dialog and a second **Update** confirms. | | KI-009 | Charts API | Docs | S3 | Creating a chart through the API requires `params.version = 2` and a `settings` object; the axis mapping lives in `settings`, not in `spec.dimensions`. Charts created with only `spec` load with the X-axis empty. Document the payload. | | KI-010 | Dashboards | Docs | S3 | The dashboard grid is 24 columns wide; this is not stated anywhere in the UI or API reference. | -| KI-011 | Databases | UX | S3 | A newly created connection shows status *Unknown* until **Test** is pressed, even though creation already validated reachability. | +| KI-011 | Databases | UX | S3 | A newly created connection shows status *Unknown* until **Test** is pressed, even though creation already validated reachability. *Docker demo stack (Oct 2026):* after **Test** succeeds the row shows a green **OK**, but the **Status** column stays *Unknown* and the counter *0 ok* until the page is reloaded, although the API already answers `status: ok`; the counter also reads "1 connections". *Steps:* Workspace settings → Engines → **Test** on `trino-demo`. (Reported by the start area.) | | KI-012 | Workspace settings | UX | S3 | The Notifications page does not follow the layout of the other settings tabs: the heading is offset, and Encryption is an unstyled native select. | -| KI-013 | Workflows | UX | S1 | With the default config the workflow worker is **off**. *Run* succeeds and the execution sits in *Running* indefinitely (one waited 53 s until the worker was enabled). Only the Triggers page warns; Run, Flow and Executions give no hint. | +| KI-013 | Workflows | UX | S1 | With the default config the workflow worker is **off**. *Run* succeeds and the execution sits in *Running* indefinitely (one waited 53 s until the worker was enabled). Only the Triggers page warns; Run, Flow and Executions give no hint. *Docker demo stack (Oct 2026):* still true for the default configuration; the demo stack turns the worker and scheduler on (`EGRET_WORKFLOW__WORKER_ENABLED=true`, `EGRET_WORKFLOW__SCHEDULER_ENABLED=true`), so the symptom is not seen there. | | KI-014 | Workflows | UX | S3 | A new flow shows *Version —* in its header, and *Run* says it runs "the saved draft"; it is unclear what a version is until **Create version** is pressed. | | KI-015 | Governance | Missing | S2 | **Data Lineage** is in the sidebar but is a placeholder page with no functionality. | -| KI-016 | Control Plane | Defect | S3 | `/control-plane/config` renders a completely blank page inside the shell. | +| KI-016 | Control Plane | Defect | S3 | `/control-plane/config` renders a completely blank page inside the shell. *Docker demo stack (Oct 2026):* no longer blank; it now redirects without end to `/control-plane/config/workspaces/workspaces/workspaces/…`. | | KI-017 | Audit log | UX | S2 | Every page view writes `*:read allow` rows, so the audit log is dominated by routine reads and hides grant changes. Offer a default filter or separate reads from changes. | | KI-018 | Access overview | UX | S3 | *Recent changes* identifies the actor by an id prefix (`by 6d60b4c4`) instead of a name. | | KI-019 | Roles | Consistency | S3 | Control Plane → Roles lists four workspace roles (including `data_api_invoker`); Workspace settings → Roles & permissions lists three. Verify whether the fourth is hidden on purpose. | -| KI-020 | People & groups | UX | S3 | Every user shows *No username yet*, even users who signed in through SSO. | +| KI-020 | People & groups | UX | S3 | Every user shows *No username yet*, even users who signed in through SSO. *Status:* closed on the Docker demo stack (Oct 2026): People & groups → Users shows usernames for everyone who signed in or was granted (`member-sso`, `alice-nguyen`, …); only `admin-sso`, never granted, shows *No username yet*. | | KI-021 | Control Plane | Defect? | S3 | verify: a group (`platform-admins`) mapped from the identity provider gives its member no platform role (Users shows no role for `admin-sso`). Check whether group-to-role mapping is expected to be configured separately. | -| KI-022 | Engines | Limitation | S2 | Engine provisioning (**Add engine**) needs Kubernetes. On a Docker-only setup the only way to attach an engine is **Register external engine**, and the UI does not say so. | +| KI-022 | Engines | Limitation | S2 | Engine provisioning (**Add engine**) needs Kubernetes. On a Docker-only setup the only way to attach an engine is **Register external engine**, and the UI does not say so. *Status:* closed on the Docker demo stack (Oct 2026): **Add engine** works with the Docker provisioner (`EGRET_ENGINES__PROVISIONER=docker`, Trino only): `docs-trino` ran in 72 s, restart 38 s, delete 7 s. StarRocks and RisingWave engines, ingress, autoscaling, pod logs and exec still need Kubernetes. See KI-195, KI-196 and KI-213. | ## Findings from the detailed pages -Collected while writing the detailed pages for each area (October 2026), checked against the running demo instance and the product source. Same legend as above. **S1 items:** KI-040, KI-059, KI-060, KI-112, KI-136. +Collected while writing the detailed pages for each area (October 2026), checked against the running demo instance and the product source. KI-154 to KI-213 come from re-verifying every area on the Docker demo stack (`just demo-up`, October 2026), which also closed or updated older rows (marked *Status* or *Docker demo stack*). Same legend as above. **Open S1 items:** KI-059, KI-060, KI-112, KI-136, KI-159, KI-175, KI-187 (KI-040 is closed). ### Data API, Alerts and Apps @@ -47,22 +47,41 @@ Collected while writing the detailed pages for each area (October 2026), checked | KI-024 | Data API | Bug | S3 | Versions tab: the **N breaking change** badge overlaps the note text because the Version column is too narrow. *Steps:* `/explore/default/data-api/endpoints/{id}/versions` for an endpoint with a breaking publish (screenshot `data-api/endpoint-versions`). | | KI-025 | Data API | UX | S3 | Expired client shows `expires 7 years ago` next to the **Expired** badge; a past expiry reads as a future one. A revoked client row has no actions menu while an expired one does. *Steps:* `/explore/default/data-api/clients` (screenshot `data-api/clients-list`). | | KI-026 | Data API | UX | S3 | Number parameter constraints (**minimum**, **maximum**) are two unlabeled boxes under the type; once filled, the placeholder that names them disappears, so `0` and `1000000` appear with no meaning. String and date boxes have the same problem. *Steps:* Query tab, **Database and parameters**, parameter `min_total` (screenshot `data-api/endpoint-params`). | -| KI-027 | Data API | UX | S3 | **Who** in the Versions history shows a shortened user id (`6d60b4c4`) instead of the publisher's email for a platform admin. The Apps version list does the same. *Steps:* Versions tab; Apps **Versions** dialog. | +| KI-027 | Data API / Apps | UX | S3 | **Who** in the Versions history shows a shortened user id (`6d60b4c4`) instead of the publisher's email for a platform admin. The Apps version list does the same. *Steps:* Versions tab; Apps **Versions** dialog. *Docker demo stack (Oct 2026):* Data API **Versions → Who** now shows `admin@egret.local`; the Apps **Versions** dialog still shows `by 8a66d837`, so the row now applies to Apps only. | | KI-028 | Data API | Gap | S3 | `meta.columns` in a response ignores **Naming**: with camelCase the data keys are `orderStatus` but `meta.columns[].name` is still `order_status`. *Steps:* Walk-through endpoint with `naming: camel`. | | KI-029 | Data API | Gap | S3 | `GET /api/ws/{ws}/data-api/activity/summary` returns `total.endpoint_name` set to one arbitrary endpoint's name ("Yearly revenue summary") although `total` covers all endpoints. The UI does not show it. *Steps:* `GET .../activity/summary?range=24h`. | | KI-030 | Data API | Gap | S3 | A `data_access_denied` (403) could not be reproduced: no Ranger policy exists for the demo connection, so the page documents it from the OpenAPI text only. The governed-connection refusals (publish refused, `503 governance_stale`) were not provoked either, because changing the shared connection was out of bounds. *Steps:* `platform/data-api/governed-connections`. | | KI-031 | Data API | UX | S3 | **Database and parameters** is collapsed by default on the Query tab, so the parameters table and database picker are hidden until opened; the count in the summary is the only hint. *Steps:* Query tab of any endpoint. | | KI-032 | Alerts | Bug | S2 | **Run now** writes a run-log row but does not update the item's last state: the list **Last run** and the header badge stay **Never run**, while **Recent runs** on the same page shows the runs. Scheduled runs do update it. *Steps:* Create an alert, press **Run now**: `GET /api/ws/default/alerts` still has `last_state: null`; `/alerts/{id}` shows badge "Never run" above two recent runs. | -| KI-033 | Alerts | UX | S2 | A run is **Success** (and starts the grace period) even when delivery failed; the failure is only in the run-log **Detail**. Nothing in the list marks an alert whose messages never arrive. *Steps:* Alert **Pending orders above 100**: run log `Success` with `webhook host resolves to a blocked address (127.0.0.1): loopback`; **Urgent open orders exist**: `Success` with `smtp is not configured for this workspace`. | +| KI-033 | Alerts | UX | S2 | A run is **Success** (and starts the grace period) even when delivery failed; the failure is only in the run-log **Detail**. Nothing in the list marks an alert whose messages never arrive. *Steps:* Alert **Pending orders above 100**: run log `Success` with `webhook host resolves to a blocked address (127.0.0.1): loopback`; **Urgent open orders exist**: `Success` with `smtp is not configured for this workspace`. *Docker demo stack (Oct 2026):* still true; the failed delivery also starts the grace period: "Late orders to Slack" (no Slack app) and "Webhook to an internal host" (blocked) show **On grace** after the next scheduled run. | | KI-034 | Alerts | Bug | S3 | With several destinations only the first failure is recorded. An alert with an email and a webhook destination recorded only the webhook error; the missing-SMTP error for the email destination was not shown. *Steps:* Alert **Pending orders above 100** (email + webhook), run log. | -| KI-035 | Alerts | Gap | S3 | Webhook destinations that resolve to loopback or private addresses are refused and there is no UI hint or setting; `automation.webhook_allow_hosts` is operator config, so a local receiver cannot be used to test webhooks. *Steps:* Run now on an alert with `http://127.0.0.1:19099/egret`. | -| KI-036 | Alerts | Env | S2 | PNG and PDF reports fail because the rendering service is not deployed: `render failed: error sending request for url (http://egret-renderer:8080/render)`. Only CSV and text formats could be run. *Steps:* Report **Sales overview weekly digest** (PDF), **Run now**. | +| KI-035 | Alerts | Gap | S3 | Webhook destinations that resolve to loopback or private addresses are refused and there is no UI hint or setting; `automation.webhook_allow_hosts` is operator config, so a local receiver cannot be used to test webhooks. *Steps:* Run now on an alert with `http://127.0.0.1:19099/egret`. *Docker demo stack (Oct 2026):* Docker service names resolve to private addresses (`webhook host resolves to a blocked address (172.24.0.5): private`), so the demo stack cannot receive webhooks locally; a public endpoint was reached (`webhook returned 405`). | +| KI-036 | Alerts | Env | S2 | PNG and PDF reports fail because the rendering service is not deployed: `render failed: error sending request for url (http://egret-renderer:8080/render)`. Only CSV and text formats could be run. *Steps:* Report **Sales overview weekly digest** (PDF), **Run now**. *Status:* closed on the Docker demo stack (Oct 2026): with `EGRET_AUTOMATION__RENDERER_URL=http://renderer:8080`, PNG reports, single and two-dashboard PDFs and an alert's PNG attachment were delivered to Mailpit (a PNG dashboard report arrived in 23 s). The remaining failure mode is KI-167. | | KI-037 | Alerts | Gap | S3 | The editor offers six comparison operators; the API also accepts `between` and `not between`. *Steps:* `validator_config` handling in `egret-automation` vs the Condition tab. | -| KI-038 | Alerts | UX | S3 | The Schedule column shows a raw cron (`0 * * * *`) for an hourly schedule, while other schedules are shown in words. *Steps:* Alerts list, **Cancelled orders spike**. | +| KI-038 | Alerts | UX | S3 | The Schedule column shows a raw cron (`0 * * * *`) for an hourly schedule, while other schedules are shown in words. *Steps:* Alerts list, **Cancelled orders spike**. *Docker demo stack (Oct 2026):* still true; custom expressions such as `30 8 * * 1-5` are shown raw too. | | KI-039 | Alerts | UX | S3 | The **Don't send when there are no rows** option sits under Notification, but reports and Data API alerts ignore it; the note says so only after you read it. *Steps:* Notification tab. | -| KI-040 | Apps | Env | S1 | Apps cannot be edited or opened on this instance: `apps.origin` is not configured and there is no pod launcher or Kubernetes. The editor and the viewer show *Apps are not set up on this deployment*. The editor UI, per-viewer execution and the query gateway were documented from source, not observed. *Steps:* `/explore/default/apps/{id}/edit` and `/explore/default/apps/{id}`. | +| KI-040 | Apps | Env | S1 | Apps cannot be edited or opened on this instance: `apps.origin` is not configured and there is no pod launcher or Kubernetes. The editor and the viewer show *Apps are not set up on this deployment*. The editor UI, per-viewer execution and the query gateway were documented from source, not observed. *Steps:* `/explore/default/apps/{id}/edit` and `/explore/default/apps/{id}`. *Status:* closed on the Docker demo stack (Oct 2026): the subprocess launcher runs apps: editor, run, publish, viewer, versions and sharing all work. The remaining blocker is the viewer hang, KI-175. | | KI-041 | Apps | Gap | S3 | The Create app dialog asks only for a name. The API accepts `description` and `database`, and the template pre-fills a connection cell from `database`, but the UI sends neither, so every new app starts without a connection and the description can only be set later through **Rename…**. *Steps:* `POST /api/ws/{ws}/apps` body; `Apps.tsx` `NewAppDialog`. | | KI-042 | Apps | UX | S3 | `PUT .../draft` without `If-Match` returns `If-Match with the draft revision is required`; an API client that only knows the draft body gets no hint of the revision. Publishing before saving silently publishes the starter notebook. *Steps:* `POST /apps` then `POST /apps/{id}/publish` with `{}` publishes v1 of the template. | +| KI-156 | Apps | Gap | S2 | The marimo editor has no autocomplete or hover help: the apps proxy refuses `/api/lsp/health` (403, console "Language server initialization failed"), and also `POST /api/packages/sandbox`, `POST /api/datasources/discover` and `GET /api/usage`, so the package and data-source panels do not work and every editor load logs 5 or 6 console errors. Refusing the LSP is by design (demo guide), but the editor does not tell the author. The first load also shows *Not connected to a runtime* for about 30 s before *Reconnected*, and opening the editor alone bumps the draft revision (1 → 2). *Steps:* Apps → **+ App** → Create, watch the console and network log. (Reported by the start and apps areas.) | +| KI-157 | Reports | UX | S3 | A report's mail subject is always `[egret] report`, so a report whose name ends in "report" mails "… report report". *Steps:* report "start: first dashboard report" → Run now; Mailpit subject `[egret] start: first dashboard report report`. | +| KI-167 | Reports | Bug | S2 | A multi-object PDF report fails with `render failed: error sending request for url (http://renderer:8080/render)` although the renderer is up. The render client has a fixed 30 s timeout (`render/client.rs` `CLIENT_TIMEOUT`) while the renderer captures the objects one after another with up to 20 s each, so two medium dashboards exceed it; the error does not say "timeout". *Workaround:* split the report, keep each under about 25 s. *Steps:* **Sales performance weekly digest** (PDF: Sales performance + Executive summary) → Run now: error after 30.5 s, three times. Sales performance alone renders in about 20 s; Executive summary + Weekly sales review (about 26 s) succeeds. | +| KI-169 | Reports | Bug | S2 | CSV and Text reports write numbers unformatted, as `f64` debug text: `"F","1.0356810234900002e+9"` and `F \| 1.0356810234900002e+9`, so spreadsheet users see scientific notation and float noise. *Workaround:* round or cast in the chart's dataset SQL. *Steps:* **Revenue by status CSV** and **Revenue by status (text)** → Run now → Mailpit. | +| KI-170 | Alerts / Notifications | Gap | S3 | The **Opening note** and **Closing note** appear only in the HTML part of the email; the text/plain part has only "The alert … fired. Observed value: …" or "The report … is attached." *Steps:* alert **Pending orders above 100** (both notes set) → Mailpit → Text tab. | +| KI-171 | Alerts / Run log | UX | S3 | In a report's run log dialog the **Value** column is empty and too narrow: its heading runs into **Detail** ("ValueDetail") and **Started** wraps. *Steps:* Reports tab → Run log of **Sales performance weekly digest** (screenshot `alerts/run-log-report-error`). | +| KI-172 | Alerts API | Docs | S3 | For a report, a non-empty `targets` silently replaces `chart_id`/`dashboard_id`: `POST /alerts` with `dashboard_id` = Sales performance and `targets` = [chart Top clerks] delivered a PDF of the chart alone and recorded **Success**. The editor always sends every object (primary first) in `targets`, so only API clients hit this, and the API reference does not say so. *Steps:* `runner.rs` `render_image_report` uses `targets_for` when non-empty. | +| KI-173 | Alerts / Scheduler | UX | S3 | Items due in the same tick run one after another, so a slow PNG/PDF render delays every other alert in the workspace: twelve items due at 12:10:00 started between 12:10:18 and 12:11:21, all showing **Working** meanwhile; an alert with a dashboard attachment takes about 25 s per run. *Steps:* set twelve items to `*/2 * * * *`, watch `GET /alerts` `last_state`. | +| KI-175 | Apps | Bug | S1 | On the Docker demo stack published apps stop opening a few minutes after the first view: every later **Open** stays on *Starting the app…* until Egret is restarted. The egret image has no `kill` binary, so `SubprocessPodLauncher::kill_group` (`crates/egret-apps/src/subprocess_pod.rs`) cannot signal the process group; when the idle reaper calls `stop_run`, it waits forever on `child.wait()` while holding the `running_run` mutex (the guard of `self.running_run.lock().await.remove(&key)` lives through the block), and every `ensure_run` blocks behind it. Edit pods use a separate lock and keep working, but `stop_edit` (idle 30 min) likely has the same problem. *Workaround:* restart the egret container. *Fix idea:* install procps or use `killpg`, and do not hold the mutex across `kill_group`. *Steps:* open a published app as a viewer; more than 5 minutes later open another (`Customer lookup`): `POST …/ticket` 200, `GET http://apps.localtest.me:18080/r//` never answers, the first run's processes are still alive and the log has no "stopped an idle app run pod". Seen twice. | +| KI-176 | Apps | Bug | S3 | The **Versions** dialog is stale after a publish (still *Nothing has been published yet.*) until the page is reloaded: `usePublishApp` (`frontend/src/api/apps.ts:119`) invalidates the app and the list but not `getAppsVersionsQueryKey`, while `useRestoreVersion` does. *Steps:* new app → Versions → Ctrl+S → **Publish draft rev 2** → toast *Published version 1* → Versions still empty; reload → `v1`. | +| KI-177 | Apps | UX | S2 | **Publish draft rev N** pressed right after Ctrl+S answers `409 {"error":"the draft changed since it was read","current_revision":2}` (toast *The draft changed while you were publishing…*), because the header re-reads the draft revision only every 5 s (`useApp(..., {refetchMs})`). *Workaround:* wait until the button shows the new revision, then publish. *Steps:* new app → cell `1 + 1` → Ctrl+S → **Publish draft rev 1** within 0.3 s → 409; about 7 s later **Publish draft rev 2** works. | +| KI-178 | Apps | Gap | S3 | The Data Apps image ships `plotly` (7.1.0) and `altair` but not `numpy` or `pandas`, so `import plotly.express` fails (*Plotly Express requires numpy to be installed*) and so does anything that calls `.to_pandas()`. Only Altair (`mo.ui.altair_chart`) and `plotly.graph_objects` with lists work. *Steps:* `python3 -c "import plotly.express"` in the egret container; `apps-image/constraints.txt` has no numpy. | +| KI-179 | Apps / Security | Gap | S2 | Over plain http the session cookie is `egret_session` (host-only on `egret.localtest.me`) with no `__Host-` prefix, so author code served from the sibling `apps.localtest.me` can set `Domain=localtest.me` cookies that the browser sends to Egret (cookie tossing, session fixation). Demo-only in practice (production is https), but the demo stack is what new users run. *Steps:* cookie names in a signed-in storage state are `egret_session`, `egret_csrf`; demo guide "Safety" section. | +| KI-180 | Data API | Bug | S2 | Access tab: the note **Revoking will not remove access** (*This account also reaches invoke through the workspace…*) is shown on every granted service account, including ones with no workspace role, for which it is false. The inherited-access check seems to read the account's OpenAPI document, which lists the endpoint because of the grant. *Steps:* **Orders by status** → Access: `finance-dashboard` and `orders-reporting-bot` carry the note; revoke `finance-dashboard` → its next call answers `403 not_granted` and the path leaves its OpenAPI `paths`. | +| KI-181 | Apps | Gap | S3 | A user shared into an app as **Viewer** who is not a workspace member gets `POST …/ticket` 200 and `GET …/apps/{id}` 200, but `GET /api/ws/{ws}/apps` answers 403, and no workspace switcher entry exists, so the app can only be opened by direct URL. *Steps:* share **Revenue explorer** with `member-sso@egret.local` (not in `default`): list 403, detail 200, run ticket 200, edit ticket 403. | +| KI-182 | Apps | Consistency | S3 | The Apps list's row menu buttons are all named **Actions**; the Data API lists name them per row (*Actions for Top customers*), so screen-reader users cannot tell the Apps rows apart. *Steps:* `/explore/default/apps`, accessible names of the `⋯` buttons. | +| KI-183 | Data API | Consistency | S3 | **New service account** puts **Create service account** under the page description on the left; **New endpoint** and **New client** put their create button at the top right. *Steps:* `/explore/default/data-api/clients/new` vs `/endpoints/new`. | +| KI-184 | Apps | UX | S3 | The Apps **Versions** dialog says *restored from an earlier version* without naming it, although the API returns `restored_from`. Opening a draft-only app shows the raw server detail in lower case under the title (*the app has no published version to run; publish it first*). *Steps:* Revenue explorer → Versions (v3, v4); open **Shipping modes** by URL. | +| KI-186 | Reports | Gap | S3 | CSV and text reports work on charts only; a dashboard report must be PDF or PNG, enforced by the `schedule_report_format_matches_target` CHECK (migration 0112; `crates/egret-automation/src/runner.rs` `build_chart_report`). The report editor should say so before save. *Steps:* from the demo guide and source; the editor was not exercised for this. | ### Charts @@ -80,10 +99,13 @@ Collected while writing the detailed pages for each area (October 2026), checked | KI-052 | Charts / Editor | Gap | S3 | There is no filter builder. Filters exist only as chips created by drilling into a value, so a chart cannot be restricted to a fixed condition without a custom dataset. *Steps:* **Charts** page and editor; `FilterChips` is fed only by the drill menu. | | KI-053 | Charts / Editor | Inconsistency | S3 | Spelling: **Colour** (Progress), **Conditional colours** (Big number), **Switch positive / negative colours** (Trend) against **color** on every other panel. *Steps:* Display tab of those three types. | | KI-054 | Charts / Editor | UX | S3 | Waterfall and box plot axes panels say **Show label** where the other types say **X label** / **Y label**, and have **Scale** instead of **Y scale**. *Steps:* Axes tab of "Profit bridge" vs "Revenue by order priority". | -| KI-055 | Charts / List | UX | S3 | The Trash view's summary reads "1 chart · 1 folder" although folders are not shown in the Trash. *Steps:* Move a chart to Trash while a folder exists → Trash view. | +| KI-055 | Charts / Datasets list | UX | S3 | The Trash view's summary reads "1 chart · 1 folder" although folders are not shown in the Trash. *Steps:* Move a chart to Trash while a folder exists → Trash view. *Docker demo stack (Oct 2026):* the **Datasets** Trash view does the same (*1 dataset · 2 folders*). | | KI-056 | Charts / Funnel | UX | S3 | The **Steps** list only appears after the first run, and stage order follows the database order unless a **Sort** or the Steps list is used; nothing in the empty state says so. *Steps:* "Checkout conversion" with the **Sort** removed. | | KI-057 | Charts / Waterfall | UX | S3 | The **Total color** swatch shows slate (`#4C5773`) while the total bar is drawn in the dark text color by default, so the swatch does not match the bar until a color is chosen. *Steps:* "Profit bridge" → **Display** → **Total color** vs the **Total** bar. | | KI-058 | Charts / Formatting | UX | S3 | Identifier columns (`orderkey`, `custkey`) are formatted as numbers with thousands separators by default (29,989) in tables and Object detail. *Steps:* "Order record" preview. | +| KI-163 | Charts / Scatter | UX | S3 | Scatter axis titles (`customers`, `avg_balance`) are drawn in a very light grey, almost invisible on the white plot, unlike the axis titles of bar, line and combo charts. *Steps:* chart "Customer balance vs size by nation". | +| KI-164 | Charts / Funnel | UX | S3 | With **Funnel type** = **Bar**, the X axis drops every other stage label at the default 1440 px editor width (only *Visited site*, *Added to cart*, *Paid*), so two bars have no name. *Steps:* "Checkout conversion" → Display → Funnel type **Bar — a column per step**. | +| KI-165 | Charts / Box plot | UX | S3 | With **Show values on data points** on, the last box's label is clipped at the right edge (`31.6` instead of `31.6K`). *Steps:* "Line price spread by ship mode" → Display → All points + Show values on data points. | ### Dashboards @@ -103,11 +125,13 @@ Collected while writing the detailed pages for each area (October 2026), checked | KI-070 | dashboards / interactivity | Gap | S3 | "See these records" ignores the dashboard filters and shows the first 1000 rows of the whole dataset for the clicked value. *Steps:* Sales performance → click a pie slice → See these records (rows from 1992 shown while the date filter is 1995-1996). | | KI-071 | dashboards / interactivity | Gap | S3 | Custom URL clicks insert `{{value}}`, `{{column}}` and `{{slug}}` without URL encoding. *Steps:* `resolveClick` / `interpolateUrl`. | | KI-072 | dashboards / export | Bug | S3 | The download popover promises "The maximum download size is 1 million rows", but the file is built in the browser from the rows the card loaded, which a chart caps at 10,000 (`MAX_CHART_ROWS`). *Steps:* Card → download. | -| KI-073 | dashboards / export | Gap | S3 | The rendered print page (`/embed/print`) used for PNG/PDF reports draws chart cards only, with the chart's name and settings: card title and visualization overrides, text, heading and link cards, and tabs are ignored. *Steps:* `PrintObject.tsx`, `render/payload.rs` `build_dashboard`. | +| KI-073 | dashboards / export | Gap | S3 | The rendered print page (`/embed/print`) used for PNG/PDF reports draws chart cards only, with the chart's name and settings: card title and visualization overrides, text, heading and link cards, and tabs are ignored. *Steps:* `PrintObject.tsx`, `render/payload.rs` `build_dashboard`. *Docker demo stack (Oct 2026):* confirmed on a real PDF of Sales performance: "Top clerks" instead of the card title "Top 10 clerks", no heading or text card, the Orders tab stacked below. | | KI-074 | dashboards / list | UX | S3 | The Trash view still shows the **+ Dashboard** button and the folder count in the summary line. *Steps:* Dashboards → Trash. | | KI-075 | dashboards / list | UX | S3 | Deleting a folder, moving a dashboard to Trash and reverting a revision happen without confirmation. Deleting a folder moves its dashboards to Uncategorized. *Steps:* Folder ⋯ → Delete; row ⋯ → Move to Trash; History → Revert. | | KI-076 | dashboards / list | Gap | S3 | The folder API accepts a blank name (`POST /folders/dashboards {"name":" "}` returns 200) and names are unique only case-sensitively (`Finance` vs `finance`), while the UI trims and refuses blank names and the bulk move treats names case-insensitively. *Steps:* API call above. | | KI-077 | dashboards / page | Gap | S3 | "Subscribe…" exists only in the list row menu; the dashboard page's ⋯ menu has no subscribe item. There is no dashboard-level cache setting, public link or embed option. *Steps:* Dashboard page ⋯ menu. | +| KI-168 | dashboards / print page | Bug | S3 | On the rendered print page (PNG/PDF reports) a table card is taller than its 384 px box and runs past the bottom border into the next card. *Steps:* PDF report of **Sales performance**, page 2: "Largest orders" (50 rows) overflows. | +| KI-174 | dashboards / API | Docs | S3 | `PUT /dashboards/{id}` with an unchanged body adds a new "edited this" revision every time, so re-running a seed or any idempotent client fills the 20-entry history with no-op versions. *Steps:* run `scripts/seed-dashboards.mjs` twice; History shows two identical "Administrator edited this" entries. | ### SQL Lab and Datasets @@ -123,7 +147,7 @@ Collected while writing the detailed pages for each area (October 2026), checked | KI-085 | SQL Lab | UX | S3 | A zero-row result shows the filter message `No rows match “”.` *Steps:* Run a query with an empty-string parameter: 0 rows. | | KI-086 | SQL Lab | UX | S3 | Errors found before the query starts (bad parameter, forbidden) appear as a toast with raw JSON: `Error: {"error":"invalid input: parameter 'n' is not a number: abc"}`. *Steps:* Parameter type **num**, value `abc`, **Run**. | | KI-087 | SQL Lab | UX | S3 | Engine error positions are one line too high for wrapped queries (a typo on line 1 is reported on line 2); some messages carry a doubled prefix `engine: engine:` (dataset create, refresh, metric and column validation). *Steps:* `SELECT ... FROM tpch.tiny.ordres` shows `line 2:35`. `POST /datasets` with bad SQL returns `engine: engine: line 2:14`. | -| KI-088 | SQL Lab | Bug | S3 | Previewing a table from the Explorer submits the query twice (two identical History rows). Probably React StrictMode on the dev server; not checked in a production build. *Steps:* History after one **Preview**. | +| KI-088 | SQL Lab | Bug | S3 | Previewing a table from the Explorer submits the query twice (two identical History rows). Probably React StrictMode on the dev server; not checked in a production build. *Steps:* History after one **Preview**. *Status:* closed on the Docker demo stack (Oct 2026): not reproduced on the production frontend build the demo stack serves; one **Preview** of `tpch.tiny.region` added exactly one History row. Applies to the Vite dev server only, if at all. | | KI-089 | SQL Lab | UX | S3 | Download JSON and Copy export only the rows loaded in the grid (first 1,000, after filter), while Download CSV exports the full result. Nothing says so except the small "interactive over first 1,000 rows" note. *Steps:* Run a query returning 5,000 rows; Download JSON. | | KI-090 | SQL Lab | Gap | S3 | Autocomplete does not resolve table aliases (`o.` suggests tables) and only knows Explorer nodes that were expanded. *Steps:* Expand `orders`, type `SELECT orders.` (works) vs `FROM orders o ... o.` (does not). | | KI-091 | SQL Lab | UX | S3 | Deleting a snippet has no confirmation (saved queries do). *Steps:* Snippets tab, hover, bin. | @@ -147,6 +171,14 @@ Collected while writing the detailed pages for each area (October 2026), checked | KI-109 | Datasets | Docs | S3 | OpenAPI says the update/refresh/delete endpoints return 403 "or not the dataset owner", but the handlers only check `dataset:manage` on the object. *Steps:* `crates/egret-bi/src/routes.rs`, `ds_remove`. | | KI-110 | Datasets | UX | S3 | **Duplicate** is only offered for virtual datasets; there is no way to copy a physical dataset's column settings and metrics. *Steps:* Row menu. | | KI-111 | Datasets | UX | S3 | Trashing a dataset hides it but its charts keep running; nothing tells the owner of those charts. *Steps:* Trash a dataset with a chart; the chart still returns rows. | +| KI-154 | SQL Lab | Bug | S2 | `ORDER BY` is ignored on Trino: Egret wraps a single SELECT as `SELECT * FROM () AS _egret_lim LIMIT n`, and Trino drops the ordering of a subquery, so rows come back in a different, unsorted order on each run. Hits the first-dashboard tutorial query. *Workaround:* add your own `LIMIT` after `ORDER BY` (then the order holds). *Fix idea:* append the limit instead of wrapping, or carry the `ORDER BY` outside. *Steps:* `SELECT orderstatus, count(*) AS orders, round(sum(totalprice), 2) AS revenue FROM tpch.tiny.orders GROUP BY 1 ORDER BY 3 DESC` five times: P,F,O / F,P,O / P,O,F; with `LIMIT 1000` appended, F,O,P every time. `system.runtime.queries` shows the wrapped text. (Reported by the start and sql-charts areas.) | +| KI-158 | Datasets | UX | S3 | The dataset header says "1 metrics" (no singular). *Steps:* dataset "Order priority summary" after adding one metric. | +| KI-159 | SQL Lab / Workspace settings | Bug | S1 | Only workspace admins can list a workspace's connections. Members with `ws_editor` (direct or through a group), `ws_viewer` or a custom role with `query:run` get 403 on `GET /api/ws/{ws}/databases` (`registry/routes.rs:109`), so their SQL Lab database picker is empty ("Select a database"), also for a provisioned engine assigned to the workspace, and nothing tells them why. Queries sent through the API with a `database_id` do run. As a result a delegated (per-user) query by a non-admin through the UI is still unproven. *Workaround:* use the API with `database_id`, or make the user a workspace admin. *Steps:* `bao.tran` (ws_editor) or `member-sso` in Docs sandbox → SQL Lab → Select a database: no options, console 403; ws_admin `alice.nguyen` sees two. (Reported by the start and admin areas.) | +| KI-160 | SQL Lab | UX | S3 | Explorer search lists same-named tables from different schemas in no fixed order (`tpch.sf1000`, `tpch.sf300`, `tpch.sf100000`, `tpch.sf1`, …, `tpch.tiny`), so finding the `tiny` copy means reading every row. Sort by catalog.schema after the name. *Steps:* Explorer → Search tables… → `customer`. | +| KI-161 | SQL Lab | UX | S3 | Singular is not handled: the status badge and counter read *Done in 1.1 s · 1 rows* and *1 rows*. *Steps:* `SELECT count(*) FROM tpch.tiny.orders`, or Explain query. | +| KI-162 | SQL Lab | UX | S3 | The quick **Chart** view of a result uses fractional ticks for counts (`1,833.3`, `3,666.5`, …) and rotates one-letter X labels by 45°. *Steps:* run the order-status query of KI-154, press **Chart**. | +| KI-166 | Datasets | UX | S3 | The **Usage** tab shows the bar-chart icon for every chart, whatever its type. *Steps:* dataset `orders` → Usage. | +| KI-211 | SQL Lab | UX | S3 | SQL Lab runs every query with `query_max_run_time = 60s`; a longer statement (for example the first CTAS on a fresh engine) fails with the bare error *timeout* and no hint about the limit. *Steps:* `SHOW SESSION LIKE 'query_max_run_time'` → 60s. | ### Workflows @@ -165,22 +197,48 @@ Collected while writing the detailed pages for each area (October 2026), checked | KI-122 | workflows | UX | S3 | Schedule `inputs` with `{{ }}` and bad cron only fail at the scheduler (Last error), not on save. *Steps:* Triggers drawer. | | KI-123 | workflows | UX | S3 | Flow header shows "Active" for a never-published draft. *Steps:* Flow page. | | KI-124 | workflows | Gap | S3 | `errorLogs()`, `render()`, `max()`, `min()`, urlencode/base64 filters missing. *Steps:* expression-probe flow. | +| KI-187 | workflows | Bug | S1 | One long task stalls every workflow on the replica: the claim loop runs the task runs it claimed one after another (`tick_with` awaits `run_one` per run) and only then ticks again, so a `Sleep` or any slow task holds up every other execution until it ends. Kestra runs worker tasks concurrently. *Steps:* run `docs.ops/slow-export` (Sleep) and in the same second a backfill of `docs.demo.sales/daily-revenue`: the four `Write` tasks claimed in the same batch stayed *Running* for 2 min 13 s and new `Log` tasks were not claimed until the Sleep was killed. | +| KI-188 | workflows | Gap | S3 | The webhook route (`/workflows/v1/{ws}/executions/webhook/...`) is not forwarded by the shipped entry points: the frontend nginx has no `/workflows/` location and the Helm ingress sends `/` to the frontend, so with webhooks enabled a call reaches the SPA (`GET` 200 HTML, `POST` 405 from nginx). The drawer does not tell the operator to add the route. *Steps:* `curl -X POST http://egret.localtest.me:8080/workflows/v1/default/executions/webhook/docs.demo/order-webhook/orders-demo-key` → 405. | +| KI-189 | workflows | UX | S3 | A schedule that does not fire still shows a **Next run**: a switched-off one shows a time in the past ("6 minutes ago"), one with `disabled: true` in its YAML shows "in 5 days". It should show a dash. *Steps:* Triggers page, `every_minute` (docs.demo/nightly-heartbeat, off) and `weekly` (docs.ops/purge-old-logs). | +| KI-190 | workflows | UX | S3 | The triggers table is wider than the content area at 1440 px: on the **Triggers** page **Backfill** and **Details** are off-screen (sideways scroll, no hint), on a flow's **Triggers** tab **Details** is cut to "Deta", and the *Disabled in the flow's YAML* note is clipped. *Steps:* Workflows → Triggers at 1440×900. | +| KI-191 | workflows | UX | S3 | On a running execution, tasks that have not started yet are labelled *Not run* in the topology, the same words used for a skipped branch on a finished run. *Steps:* run `docs.ops/slow-export`, open **Topology** while `export` sleeps: `done` says *Not run*. | +| KI-192 | workflows | Docs | S3 | `FilterItems` and the other item tasks read Ion records, not CSV lines: a CSV written by `Write` fails with *item 0 … is not a record: it is an Ion symbol, not a struct*. The task catalogue text is fixed; no product change is needed unless CSV input is wanted. | +| KI-193 | workflows | UX | S3 | On a running or paused execution the action buttons (**Resume**, **Replay**, **Kill**) are indented about 75 px from the title, with an empty gap, and the *Replay is available when the execution has finished* reason wraps below them; on a finished execution **Replay** is at the top right. *Steps:* the paused `docs.demo/approval-gate` execution. | ### Governance, Control plane and Workspace settings | ID | Area | Type | Sev | Description | |---|---|---|---|---| -| KI-125 | Governance / Engines | Gap | S2 | A policy profile created with **New profile** (Trino) can never be bound to an engine: binding fails with "has no usable tag service". The console cannot set `tagService`, so an external Trino engine can only be bound by creating the `tag` + `trino` profile pair through the API. *Steps:* Engine & policy → New profile → docs-trino-profile; Control Plane → Engines → docs-trino → Settings → Policy profile → Save changes (400) | -| KI-126 | Workspace settings / Notifications | Bug | S2 | Saving SMTP settings returns HTTP 500 "internal error" on this instance (the Notifications form shows "internal error"), so the saved state, "Send test message" and the Slack save could not be verified. *Steps:* `PUT /api/ws/docs-sandbox/notifications/smtp` with host smtp.example.com, port 587, from alerts@example.com | +| KI-125 | Governance / Engines | Gap | S2 | A policy profile created with **New profile** (Trino) can never be bound to an engine: binding fails with "has no usable tag service". The console cannot set `tagService`, so an external Trino engine can only be bound by creating the `tag` + `trino` profile pair through the API. *Steps:* Engine & policy → New profile → docs-trino-profile; Control Plane → Engines → docs-trino → Settings → Policy profile → Save changes (400) *Docker demo stack (Oct 2026):* still true, and the **Policy profile** pickers (Register external engine, engine Settings) list tag-less profiles such as `docs-external-policy` without marking them unbindable. | +| KI-126 | Workspace settings / Notifications | Bug | S2 | Saving SMTP settings returns HTTP 500 "internal error" on this instance (the Notifications form shows "internal error"), so the saved state, "Send test message" and the Slack save could not be verified. *Steps:* `PUT /api/ws/docs-sandbox/notifications/smtp` with host smtp.example.com, port 587, from alerts@example.com *Status:* closed on the Docker demo stack (Oct 2026): with `EGRET_SECRETS__MASTER_KEY` set, SMTP to Mailpit (`mailpit:1025`, no encryption) saves, **Send test message** answers *Test message sent…* and mail arrives; the Slack save answers *Slack settings saved.* | | KI-127 | Workspace settings / Roles | UX | S3 | A custom role that inherits shows only its own permissions ("2 permissions") on the workspace Roles & permissions page, while the Control Plane role page counts 8 (including inherited). `data_api_invoker` is missing from the workspace list but is offered in the Members role picker. *Steps:* /explore/docs-sandbox/settings/roles vs /control-plane/roles/<finance_reporter> | -| KI-128 | Workspace settings / Members | UX | S3 | Typing a partial email ("member-sso") in Add member gives no suggestions and the add silently does nothing visible; only the exact email works. *Steps:* /explore/docs-sandbox/settings/members → Add member | -| KI-129 | Control plane / Storage | Bug (unverified) | S3 | On a connection created with Key prefix `sandbox`, the Browse tab lists the bucket root, not the prefix. *Steps:* Storage → sandbox-lake → Browse | -| KI-130 | Governance / Overview | Doc | S3 | The count tiles say "classifications" and the tag page "0 tagged objects" counts BI objects only; a tag on a table column does not raise the count. *Steps:* /governance/classifications/<tag> after tagging `user_id` | +| KI-128 | Workspace settings / Members | UX | S3 | Typing a partial email ("member-sso") in Add member gives no suggestions and the add silently does nothing visible; only the exact email works. *Steps:* /explore/docs-sandbox/settings/members → Add member *Status:* closed on the Docker demo stack (Oct 2026): typing `emma` in Add member suggests *Emma Schmidt emma.schmidt@egret.local*. | +| KI-129 | Control plane / Storage | Bug (unverified) | S3 | On a connection created with Key prefix `sandbox`, the Browse tab lists the bucket root, not the prefix. *Steps:* Storage → sandbox-lake → Browse *Docker demo stack (Oct 2026):* still true (`sandbox-lake`, prefix `sandbox/`). Related: KI-208. | +| KI-130 | Governance / Overview | Doc | S3 | The count tiles say "classifications" and the tag page "0 tagged objects" counts BI objects only; a tag on a table column does not raise the count. *Steps:* /governance/classifications/<tag> after tagging `user_id` *Status:* closed on the Docker demo stack (Oct 2026): the Classifications list has a **Data** column (*0 tables · 4 columns*), and the tag page's **Where used** lists the tables and columns. | | KI-131 | Governance / Data | UX | S3 | Grant and rule row actions are icon-only (pencil, bin) and the row text is not a link. The single grant/rule page (`/governance/grants/`) has no visible link from the row. *Steps:* Data → Permissions tab | | KI-132 | Governance / Data | UX | S3 | The New grant dialog taller than a 900 px viewport scrolls inside the dialog and the Preview result sits below the fold. *Steps:* Data → Grant access → Preview | | KI-133 | Control plane / Workspaces | Gap | S3 | No way to delete a workspace, only archive; archived workspaces still count in the summary strip. *Steps:* /control-plane/workspaces | -| KI-134 | Control plane / Audit log | Gap | S3 | The Action filter is an exact match (`secret` matches nothing; `secret:read` does). Creating a secret, workspace, catalog or engine registration did not show as a mutation entry when filtered by kind. *Steps:* /control-plane/audit-log, API `kind=mutation` | -| KI-135 | Governance / Engines | Gap | S3 | "Seed default policies" on an empty manual profile showed no change and no message. *Steps:* Profile page → Advanced → Seed default policies | +| KI-134 | Control plane / Audit log | Gap | S3 | The Action filter is an exact match (`secret` matches nothing; `secret:read` does). Creating a secret, workspace, catalog or engine registration did not show as a mutation entry when filtered by kind. *Steps:* /control-plane/audit-log, API `kind=mutation` *Docker demo stack (Oct 2026):* wider than written: Kind = Mutation lists no entry for creating users, groups, roles, workspaces, secrets, storage connections, catalogs or tags, for provisioning, restarting, reconfiguring or deleting an engine, for declaring a catalog or for saving SMTP settings. Action is still an exact match. | +| KI-135 | Governance / Engines | Gap | S3 | "Seed default policies" on an empty manual profile showed no change and no message. *Docker demo stack (Oct 2026):* it does add 13 policies (`{"created":13}`), shown on **Policies** as egret-seeded, but Advanced still says *This profile has no hand-written policy.* and no message is shown. *Steps:* Profile page → Advanced → Seed default policies | +| KI-194 | Engines / Monitor | Bug | S2 | The **Monitor** tab of a running Trino 483 engine says *Engine not reachable — is a coordinator running?* and *Coordinator unreachable — no live queries.*: `/cluster` and `/queries` answer 502 because the summary calls `GET /v1/node` (404 on Trino 483) and a JWT-delegation engine gives the `egret-monitor` account no sign-in. Not Docker-specific. *Workaround:* use `system.runtime.queries` in SQL Lab. *Steps:* docs-trino → Monitor while a query runs. | +| KI-195 | Engines | UX | S3 | On a Docker-provisioned engine the **Logs** and **Exec** buttons stay visible although they cannot work: Logs shows the raw *bad request: not available with the Docker engine provisioner*; Exec opens a shell that closes at once with *[connection closed]* (the WebSocket answers 400). Hide them or say why. | +| KI-196 | Engines | Consistency | S3 | Engine dialogs speak Kubernetes on a Docker engine: Delete says *This destroys the engine's Kubernetes cluster*, Restart says it *rolls the coordinator and worker pods*, Review changes says *re-provisions (rolls) the engine pods*. | +| KI-197 | Engines | Bug | S3 | After **Add engine** with Worker → Replicas `0`, the stored spec says `workerReplicas: 2` and Overview shows *Coord 1 · Worker 2* while only the coordinator container exists; the first **Save changes** on Settings corrects it. With the field blank, one worker container starts and the strip still says 2. | +| KI-198 | Engines / Settings | UX | S3 | **Review changes** lists an unrelated `auth.passwordUsers [] Added` next to the real change and has only **Close**; **Save changes** then applies without confirmation while the header stays **running** although the coordinator container is recreated. *Steps:* docs-trino → Settings → Server → add `query.max-run-time` = 2h → Review changes. | +| KI-199 | Engines | UX | S3 | The engine header and list show the endpoint `docs-trino-coordinator.egret-engines:8080`, which does not resolve on the Docker network; the container answers as `docs-trino-trino(.egret-engines(.svc))` and the workspace connection uses `docs-trino-trino.egret-engines.svc:8443`. | +| KI-200 | Engines / Add engine | UX | S3 | **Expose via ingress** without a **Host** is silently dropped: the engine is created with no ingress and no message. With a host the Docker provisioner refuses (*not supported by the Docker engine provisioner: ingress*), as expected. | +| KI-201 | Governance / Lineage | Bug | S2 | View lineage fails on a provisioned engine: *engine docs-trino: engine: Access Denied: Cannot access catalog demo_warehouse*, because the engine's own policy does not let Egret's lineage reader into the catalog. The overview shows a **Warning**, the table's Lineage tab *No reader is known*, View exposure lists the view as *clearance unknown*; `POST /classifications/lineage-sweep` fails the same way, and the console has no control for the sweep the UI asks you to run. *Steps:* view `demo_warehouse.analytics.revenue_by_country` over `sessions`. | +| KI-202 | Governance / Migrate | Gap | S3 | A one-policy migration cannot be proved when its catalog is also served by a provisioned engine: *proving this migration needs 48735 probe evaluations across 2 profile(s), 2697570 units of work … over the limit of 1300000*. On a catalog only the external engine serves, the same policy proved with 1575 probes. *Steps:* `select` on `tpch_bench.*.*.*` in `docs-legacy-trino` (also served by docs-trino, 28 policies) → Preview migration. | +| KI-203 | Governance / Engine permissions | UX | S3 | In **Grant engine permission** the user search list stays open after a pick and covers the **Grant** button until you click elsewhere. | +| KI-204 | Control plane / Engines | UX | S3 | After **Register engine** without a profile you land on Plugin config with the raw API text *conflict: engine trino-demo-ext is bound to no policy profile: bind a profile first Bind a policy profile on the Settings tab, then come back.* (prefix kept, sentences run together). | +| KI-205 | Audit log | Gap | S2 | Decisions made while impersonating are recorded under the impersonated user with an empty `detail`; only `impersonation.start`/`impersonation.end` name the admin, so the workspace Activity tab shows `member-sso` as the actor of what `ops.admin` did. | +| KI-206 | Control plane / Storage | Security | S2 | **Storage → \ → Browse** lists `query-results/*.jsonl`, the stored SQL Lab results of every user, and `GET /storage/{id}/download?key=…` returns them to anyone with `storage:read`, which the built-in `data_steward` role holds. These are each user's post-mask results. | +| KI-207 | Control plane / Secrets | UX | S3 | System-managed secrets (`engine-internal-*`, `engine-monitor-*`, `engine-tls-*`, `catalog-client-*`) are listed with user secrets, can be rotated or deleted, and are offered in the catalog **Password secret** picker. The **Used by** and **Created** columns are cut off at 1440 px. | +| KI-208 | Control plane / Catalogs | Gap | S3 | A second egret warehouse on the same bucket is refused (*Storage profile overlaps with existing warehouse demo-warehouse*), also through a connection with another key prefix (`sandbox/`); the New catalog form does not say a warehouse needs its own bucket. Related: KI-129. | +| KI-209 | Control plane / Users | UX | S3 | **Disable** on a user page acts at once and signs the user out without confirmation, while **Delete** asks for a typed confirmation. | +| KI-210 | Access requests | Gap | S3 | No mail is sent when someone requests access or when a request is approved or denied, although the workspace has working SMTP (Mailpit received nothing); admins only see the queue when they open it. | +| KI-212 | Workspace settings / Notifications | UX | S3 | Before settings exist the page loads `GET /notifications/smtp` and `/notifications/slack`, which answer 404 and show as console errors. | +| KI-213 | Engines / Demo stack | Bug | S2 | After `just demo-down` and `just demo-up`, engines added with **Add engine** stay `provisioning`: their containers are gone and nothing recreates them, and **Restart** now tells you to delete and re-add the engine. *Workaround:* delete the engine and add it again (its policy profile stays under *Profiles without an engine*). | ### Install, configuration, security and operations @@ -204,7 +262,19 @@ Collected while writing the detailed pages for each area (October 2026), checked | KI-151 | Helm | Docs | S3 | Chart README is stale: says OIDC is off "in this milestone" and builds only backend and frontend images, while the chart has `oidc.enabled` and `just images-build` builds four images. Chart `description` still says "local kind deployment". *Steps:* `deploy/helm/egret/README.md`, `Chart.yaml`. | | KI-152 | Helm | Security | S3 | The bundled Keycloak (with `oidc.enabled`) imports the dev realm: `sslRequired: none`, `*` redirect URI, password grant, known user passwords and the client secret `egret-secret`. *Steps:* `deploy/helm/egret/files/egret-realm.json`. | | KI-153 | OpenAPI | Gap | S2 | Only the Data API bearer scheme is declared; session cookie and CSRF are not, so generated clients cannot authenticate. Most operations have no summary (only an `operationId`), and many descriptions are internal doc comments (long, referencing internal types and task numbers). *Steps:* `openapi.json`; `scripts/gen-api-reference.mjs` has to truncate descriptions. | +| KI-155 | Demo stack | Docs | S3 | The demo edge does not route `/readyz` and `/healthz` to Egret: `curl http://egret.localtest.me:18080/readyz` answers 200 with the web app's HTML, which looks healthy whatever the backend state, so the generic first checks of the troubleshooting index do not work on the demo stack. | +| KI-185 | Authentication | UX | S2 | An SSO user lands on *No workspaces yet* after the first sign-in and can do nothing until a workspace admin adds them; Egret only knows the user after that first sign-in, so the admin cannot add them beforehand. The demo guide documents this. *Workaround:* sign in once, then have an admin add the user. Seen by the demo-stack guide author, not re-observed. | ## Not verified -These could not be exercised on the demo instance (no Kubernetes, no rendering service, no mail server), so the matching pages describe them from source and say so: engine provisioning and the Migrate tab, Data Apps editor and viewer, impersonation from the Members menu, tagging BI objects, SMTP/Slack delivery, PNG and PDF reports, `data_access_denied` and `governance_stale` responses on governed connections, and "Limit this filter's choices" on dashboards. +The Docker demo stack (`just demo-up`) now exercises what the earlier demo instance could not: **Add engine** with the Docker provisioner (Trino), the Data Apps editor and viewer, PNG and PDF reports through the renderer, and SMTP delivery to Mailpit. These are still not exercised there, so the matching pages describe them from source and say so: + +- **Kubernetes-only features:** StarRocks and RisingWave engines, ingress, autoscaling, pod logs and exec on engines, the Kubernetes kernel and app launchers. +- **Ranger enforcement on an external engine:** the demo Trino has no Ranger plugin. Rule overlaps that already exist cannot be shown, because Egret refuses to create them. +- **Governed connections:** `data_access_denied` and `governance_stale` responses, and different rows per viewer in an app (`trino-demo` runs every query as `egret`). +- **Non-admin use:** a delegated (per-user) query by a non-admin through the UI, SQL Lab and dataset behaviour for a viewer, and the permissions needed for Tags (blocked by KI-159). +- **Delivery:** Slack (no Slack app on the stack) and webhook request bodies (private and Docker hosts are blocked, KI-035; payload shape comes from source). +- **Workflows:** script tasks and `WorkingDirectory`, Kestra JDBC plugin tasks (no container runner or plugin host, refused with `task_type_not_served`), `egret.sql`, `egret.dataapi.call`, `egret.dataset.refresh`, `egret.report.send`, `core.http` and `core.slack` (no handler on any deployment), mail from a workflow (`MailSend` is unknown) and webhook calls (off on the stack, see KI-188). +- **SQL Lab errors:** `connect:`, `timeout` and authentication errors (the only connection is healthy and not delegated). +- **Demo stack lifecycle:** `just demo-up` from an empty machine and its build time, `demo-reset` and `demo-seed`, and the demo-stack upgrade path. Engine state after `demo-down`/`demo-up` is KI-213. +- **Elsewhere:** tagging BI objects, and "Limit this filter's choices" on dashboards.