> ## Documentation Index
> Fetch the complete documentation index at: https://oxy.tech/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Data App Publish/Draft, Airway ELT Pipelines, and Airhouse Observability

> Control which Data Apps appear in the sidebar with publish state, ship streaming ELT pipelines via Airway, and route Oxy's own observability to Airhouse.

<Icon icon="calendar" iconType="regular" size={16} /> **May 20, 2026** · v0.5.56, v0.5.57

### New Features

#### Data App Publish/Draft Paradigm

Data App authors now control which apps surface in the sidebar with a `published` flag, so works-in-progress no longer leak into navigation for the rest of the workspace.

* **Sidebar shows published apps only** — The sidebar fetches only published apps by default. All apps remain accessible from the IDE Objects view, so drafts stay editable without cluttering team navigation.
* **Per-app publish state in YAML** — A new `published: bool` field on `.app.yml` controls visibility. Defaults to `false`, so apps stay drafts until explicitly published.
* **Role-based publishing** — `POST /:projectId/apps/:pathb64/publish` and `POST /:projectId/apps/:pathb64/unpublish` toggle the state. Owners, Admins, and Members can publish; Viewers cannot. The `list_apps` response includes a `can_publish` flag derived from the caller's workspace role so the UI can adapt actions per user.
* **Draft indicator in the IDE** — Apps that aren't published show a draft state in the IDE Objects list, making it easy to see at a glance which apps haven't been promoted yet.

#### Airway ELT Pipelines

Oxy ships a first-class **Airway** ELT integration: a queue-driven streaming pipeline subsystem with a Developer-Portal UI to create, run, and monitor ingestion jobs.

* **`.airway.yml` pipeline spec** — Define a pipeline by pointing `source` (`rest_api`, `filesystem`, `sql_database`, `postgres_cdc`, `toast`) at a `destination` that references a database from `config.yml`. Credentials stay in the secret manager — `.airway.yml` never holds them. minijinja `variables` make pipelines configurable.
* **Streaming by default** — Concurrent extract→sink with per-resource producers, bounded channels, and per-batch commits. Partial failures are recorded as durable `completed_with_errors` audits instead of failing the whole run. A rich event taxonomy (`PipelinePlan`, `ExtractStarted/Progress`, `Normalize*`, `TableLoadStarted/LoadProgress/TableLoaded/TableLoadFailed`, `ResourceFailed`) drives the lineage view.
* **Pipelines section in the Developer Portal** — A dedicated **Pipelines** entry in the IDE left rail (`/ide/pipelines`) lists pipelines, embeds a monitor view (phase bar + per-resource grid + run history), and jumps straight to YAML edit. A 3-step **New Pipeline** card wizard walks through source → destination-from-config.yml → details, with Toast credentials persisted to the secret manager.
* **`oxy airway run` CLI** — Run pipelines from the terminal in addition to the UI. The same streaming event stream is surfaced for both entry points.
* **Airhouse and Airhouse-managed destinations** — Pipeline destination resolution understands `airhouse` and `airhouse_managed` targets and brokers credentials through the system-account token broker at runtime.

#### Airhouse Observability Backend

Oxy now supports Airhouse as a fourth observability backend alongside DuckDB, Postgres, and ClickHouse, so teams can dogfood Airhouse for trace, intent-classification, and metric-usage storage.

* **`OXY_OBSERVABILITY_BACKEND=airhouse`** — Routes spans, intent classifications, intent clusters, and metric usage to an Airhouse instance over the pgwire protocol. Tables are namespaced with an `oxy_obs_` prefix to avoid collisions with user tables.
* **Full observability surface** — All 25 `ObservabilityStore` methods are implemented in DuckDB-dialect SQL, so trace listing, detail, cluster mapping, metric usage, and execution analytics all light up against Airhouse.
* **TLS by default with secure reconnect** — TLS via `tokio-postgres-rustls` is the default; `OXY_AIRHOUSE_OBS_INSECURE=true` opts into plaintext for localhost only. A background reconnect loop with exponential backoff (200 ms → 30 s) keeps the connection healthy through restarts.
* **Batched span writes** — Spans are inserted as multi-row `INSERT … VALUES` batches of up to 500 rows per chunk, keeping write overhead low under high trace volume.

***

### Platform Improvements

#### Builder Reliability

* **Accurate file-change events for auto-applied edits** — `FileChanged` events are now emitted for both suspended (user-accepted) and auto-accepted Builder file changes by comparing pre- and post-operation file contents. The frontend no longer misses approvals when the Builder writes through delegated tools.
* **Revert auto-applied Builder edits** — A new `POST /runs/:id/revert-file-changes` endpoint reverts one or more files changed by the Builder during a run, giving users a clean way to undo unwanted auto-applied edits without manual diffing.
* **Clearer error messages on pipeline failures** — Builder and analytics pipeline failures (especially configuration and semantic errors) now surface structured, user-friendly error messages instead of raw error strings, so the cause shows up directly in the UI.
* **No more hung Builder runs on broken semantics** — The SSE stream now always emits a terminal event (`done`, `error`, or `cancelled`) at the end of a run, even when the pipeline fails before the orchestrator loop starts (e.g., a broken `.view.yml`). The frontend no longer hangs waiting for a terminal event that never arrived.

#### Workflow Run Orchestration

* **New `/workflows` HTTP API** — A new HTTP surface for starting, listing, cancelling, and inspecting workflow runs, and browsing workflow files programmatically. The SSE event stream recognises workflow terminal events for proper client-side cleanup.
* **Workflow run caching and retry-from-step** — Workflow tasks now support `cache_enabled` for hash-based step skipping and `retry_from_run_id` for resuming a run from a specific step forward, making long workflows cheaper to iterate on after a partial failure.
* **Workflow file-listing errors are now logged** — The `OxyProcedureRunner` previously swallowed errors from `list_workflow_files()` and returned an empty list silently. Failures now log a `warn!` with details, making missing-procedures diagnoses far easier in production.

#### Web App Resilience

* **ErrorBoundary around third-party renderers** — SQL editors, diff and merge-conflict viewers, Monaco-based editors, workflow diagrams, the context graph, and Markdown answer content are now individually wrapped with `ErrorBoundary` and a consistent `ErrorAlert` fallback. A broken renderer on one panel no longer blanks the entire page.
* **Git actions hidden when Git isn't available** — The IDE header's Git actions button now hides itself in workspaces that don't support branch switching, instead of showing inert controls.
* **Deferred Monaco theme application** — Monaco no longer immediately forces the `github-dark` theme after defining it, letting the design system's Light/Dark/System toggle drive editor theming.

#### Local-Mode Onboarding

* **Onboarding wizard state scoped per project directory** — Wizard progress in `oxy --local` is now keyed by a deployment-stable `storage_key` (`local:{hash(canonical_path)}`) instead of a shared `LOCAL_WORKSPACE_ID`. Running `oxy --local` in two different project directories on the same dev port no longer leaks wizard state between them.
* **Credential-driven onboarding redirect** — Local-mode users with a populated project but an unset `ANTHROPIC_API_KEY` (or any missing non-DuckDB warehouse credential) are now routed to the lightweight credential wizard, instead of falling through into the full from-scratch BlankOnboardingPage. No behavioural change for `app.oxy.tech` users — cloud onboarding state remains keyed by workspace UUID.

#### Performance

* **Faster thread history with many runs** — `get_thread_history_with_events` no longer issues an N+1 fan-out of per-run event queries. Events for all runs are now fetched in a single batched query and run state is computed from the in-memory event data, eliminating a per-run database round-trip when loading busy threads.

#### Observability Storage

* **Bounded DuckDB WAL growth** — The DuckDB observability backend now runs periodic 5-minute WAL checkpoints, autocheckpoints at 32 MB (down from 512 MB), and runs an explicit checkpoint on graceful shutdown. The WAL file no longer grows unbounded when the process is killed without a clean shutdown (e.g., a Kubernetes liveness-probe SIGKILL).
* **Env-var credentials restored for the Airhouse observability backend** — Reverted a regression where the Airhouse observability backend tried to mint credentials through a workspace-scoped broker that has no observability tenant provisioned. `OXY_AIRHOUSE_OBS_USER`, `OXY_AIRHOUSE_OBS_PASSWORD`, and `OXY_AIRHOUSE_OBS_DATABASE` are the correct configuration surface again; the reconnect-on-credential-refresh plumbing stays in place for a future proper observability-tenant design.
* **Airhouse observability schema now initializes cleanly** — The Airhouse observability backend no longer aborts during schema setup on its first `CREATE INDEX` statement (DuckLake doesn't implement indexes). All four observability tables — spans, intent clusters, intent classifications, and metric usage — are now created reliably on startup, so trace and metric capture work end-to-end against Airhouse instead of silently going inert after the first table.
