Skip to main content
Version: v0.0.69

v0.0.48 — Governance UX + project-slug URLs + updater verify

Released: 2026-05-05. Eight commits, dominated by a multi-part governance surface built on top of the v0.0.47 dashboards admin override, plus an additive project-slug URL routing scheme (Dataiku-style /projects/<slug>/<page>), plus the install-time follow-ups that close out the cmd_update hardening from v0.0.47.

This is the first release where every layer of v0.0.47's cmd_update hardening fired without manual intervention on both test and prod ECS.

Governance surface — admin overrides, end-to-end

v0.0.47 introduced the dashboard admin role-shortcut. v0.0.48 builds the operator workflow around it so a multi-org admin who pastes a cross-org URL gets a friendly recovery, every override leaves a usable trail, and compliance teams can subscribe to overrides as a dedicated channel.

Cross-resource recovery: NotFoundBanner

A new NotFoundBanner component replaces the silent navigate('/<list>') on 404 / 403 across Dashboards, Datasets, Agent Builder, and Notebook detail pages. Renders org-switcher buttons (org list fetched on 404 only, not on 403) so an admin who pasted the wrong-org URL can flip orgs and reload in one click. New Playwright spec 59-cross-org-banner.spec.ts pins the round-trip end-to-end.

The audit viewer at /audit gains a substantial workflow upgrade:

  • URL-persisted filters — every filter (user, category, action prefix, date range, search) lives in useSearchParams. Bookmarkable, browser back/forward works.
  • 30-day per-user activity sparkline — inline SVG (no chart bundle) above the table when filterUserId is set. New GET /api/audit/timeline endpoint with generate_series + LEFT JOIN so quiet days survive.
  • 90-day stacked breakdownGET /api/audit/timeline?group_by=action returns per-category daily buckets driving an inline <StackedActivityChart>. Categories: admin_override, auth, dashboard, dataset, notebook, agent, entity, other. admin_override is its own bucket, not folded into dashboard, so the chart answers "is this user spiking on overrides specifically, or just busy?". Click-to-expand to keep the default audit page cheap.
  • Clickable timeline legend — legend pills are now buttons. Click highlights the active pill and pins filterCategory. Click the active pill to clear. Backed by ?category= on /api/audit with a curated WHERE fragment per category (auth is an IN-list; dashboard is LIKE 'dashboard%' AND NOT LIKE '%.admin_override_%'). Unknown values are silently ignored — a stale bookmark shouldn't 422 the page.
  • Admin overrides KPI tileGET /api/audit/summary now carries admin_overrides_7d. Drives a 5th rose tile so an org owner can answer "are we trending up on overrides?" at a glance. Clicking the tile pins filterCategory='admin_override'. Zero-state polish: at 0, the tile renders white + neutral grey "Clean week" sub-label rather than alarming rose; at >0, rose styling fires (the eye-catching is desired here).
  • Per-row deep-links — username and resource cells route through resourceHref(). Notebook rows link to /notebooks?id=...; recipe rows parse the composite <project_id>:<model_name> resource_id and route to /recipes/prepare?model=...&project_id=.... Explicit ↗ icon next to deep-linkable cells with target=_blank + rel=noopener noreferrer for the "open three at once, scan, close" triage pattern.
  • CSV export — carries an action_label column with friendly admin-override phrasing ("Admin override · read"); raw action stays alongside for tooling. Timeline breakdown CSV (/api/audit/timeline/export) returns 3 columns (date,category,count); quiet days emit (date,'',0) so the X-axis survives in Excel.

Webhook channel: audit.admin_override

A new event type in _SUPPORTED_EVENTS. Emitted from _audit_admin_override (dashboards + notebooks + recipes) alongside the existing audit.event firehose. Compliance teams can now subscribe to only overrides without filtering audit traffic.

The webhook deliveries panel on /webhooks gains:

  • Event-type filterGET /api/org/webhooks/{id}/deliveries?event_type=audit.admin_override, catalog-validated. Pills built from the catalog; the audit.admin_override pill is rose-tinted + 🛡️ prefixed to mirror the audit page's governance signal.
  • URL-persisted state?endpoint=<id>&event_type=<key>. A reviewer can paste /webhooks?endpoint=42&event_type=audit.admin_override in #governance and the recipient lands on the same view.

A new paas/docs/webhook-events.md (in-repo) documents the wire envelope, HMAC verification pattern, and per-event payload shape for every supported event type. audit.admin_override is called out with its action-code matrix.

Notebook + recipe admin shortcuts (mirror dashboards)

GET /api/notebooks/{id} and GET /api/flow/recipe/{model_name}?project_id= now accept the same admin role-shortcut as dashboards:

  • Org admins resolve cross-project reads with audit + the dedicated audit.admin_override webhook channel.
  • Cross-org admins → 404 (mask).
  • Non-admins / same-project reads keep original behavior.
  • Superadmin bypasses audit (incident-response support).
  • Response carries is_admin_override so the FE renders the rose 🛡️ "Admin access · audited" badge in the page toolbar (NotebookPage, PrepareRecipePage, RecipeEditorPage).

Project-slug URLs (Phase 1, additive)

Dataiku-style /projects/<slug>/<page> routes mount alongside the existing top-level paths. Both /flow and /projects/<slug>/flow render — legacy URLs are untouched, new URLs are shareable deep-links scoped to a specific project.

  • GET /api/projects/by-key/{slug} — frontend hits this on /projects/... URLs to convert slug → numeric project_id for the X-Project-Id header. Org-scoped, runs check_project_access.
  • Slug regex + reserved-word list (new, admin, api, by-key, public, static, assets) so a slug can never collide with a sub-route mounted under /projects/. Malformed slugs 400 instead of looking like a duplicate-on-retry.
  • useProjectKeySync hook reads the URL slug, GETs by-key, and writes selected_project_id. Reload only fires when the resolved id differs from stored — no loop on deep-linking the active project.
  • ~35 nested page routes wrapped: flow, dashboards, datasets, recipes/*, jobs, scenarios, schedules, agent-builder, etc. Org-level pages (members, audit, storage, …) intentionally stay top-level.
  • Selecting a project on /projects now navigates to /projects/<slug>/flow instead of /dashboard.

Phase 2 (a future release) will collapse the recipe-type-per-route paths and add /scenarios/:name/steps, /jobs/:runId, etc.

Install: schema_sync auto-loads .env + honeyframe verify

Two install-time follow-ups that close gaps surfaced during the v0.0.47 deploy.

schema_sync was a silent no-op for 2+ releases

systemd-spawned honeyframe doesn't export DB_USER / DB_PASSWORD / DB_NAME, so on every honeyframe update the schema_sync auto-heal step hit ERROR DB_USER / DB_PASSWORD / DB_NAME env vars must be set and never applied any drift. Drift was detected but never applied.

schema_sync.py now loads /opt/honeyframe/paas/backend/.env at the top of main(). Auto-detected relative to __file__; can be overridden with --env-file <path>. cmd_update passes --env-file explicitly. Uses os.environ.setdefault() so an operator who pre-sets DB_HOST=foo on the command line still wins over the file.

Validated on the v0.0.47 → v0.0.48 deploy: 7 columns of accumulated drift actually applied (4 prod + 3 test) across the chain. The auto-heal feature is now real.

honeyframe verify command

A stricter post-deploy check than honeyframe status:

honeyframe verify
  • Exits non-zero on any failure — suitable for CI / cron / smoke scripts.
  • Cross-checks live /api/version against on-disk VERSION — catches stale-process deploys where the binary swapped but the process didn't restart.
  • Runs schema_sync --dry-run to confirm the parser still works against the shipped init_schema.sql.
  • Confirms nginx + every detected hub-* service is healthy. Services that don't expose HTTP (e.g. hub-control-plane, hub-scheduler) are gated gracefully — they get an OK without a port check.

Wire it into your deploy script as the final gate. Combined with v0.0.47's service autodetect + full-tree backup + self-update re-exec, the upgrade pipeline now has end-to-end verification in one command.

What's not in this release

  • Phase 2 of project-slug URLs — recipe-type-per-route consolidation, /scenarios/:name/steps, /jobs/:runId, etc. land in a follow-up.
  • Audit category drill-down for the other bucket — read-only by design (its SQL would be a NOT-of-everything-else compound with little operator value).
  • Webhook channel on more resource typesaudit.admin_override covers dashboards / notebooks / recipes today. Datasets follow when the cross-project read path lands.
  • HelpTip on more pages — only the v0.0.47 SSO / Webhooks / SMTP coverage; Backups / Custom Domains / AI Keys remain on the backlog.