Skip to content

(MOT-4208) feat(database): console function-calls view + UNKNOWN_DB handle enumeration - #580

Merged
andersonleal merged 4 commits into
mainfrom
feat/database-console-ui
Jul 23, 2026
Merged

(MOT-4208) feat(database): console function-calls view + UNKNOWN_DB handle enumeration#580
andersonleal merged 4 commits into
mainfrom
feat/database-console-ui

Conversation

@andersonleal

@andersonleal andersonleal commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

What

Two changes to the database worker, motivated by watching a live agent scan run (secaas-7k3m) in the console:

1. UNKNOWN_DB errors enumerate the available handles (fix)

Sub-agents in that run each burned 25 failed database::execute calls brute-forcing 23 db-handle names (scans, secaas, default, app.db, …) before landing on primary — the error only echoed the bad name back. Now:

{"code":"UNKNOWN_DB","db":"scans","available":["primary"]}

One failure teaches the right name. Additive on the wire (code and existing fields unchanged); listDatabases already exposes the same names to any caller that can reach the worker.

2. Injectable console UI: database function-calls view (feat)

Per docs/sops/injectable-console-ui.md (state worker template): the worker now ships a function-trigger renderer covering all 13 database::* functions, so calls render as real cards in chat and traces instead of raw JSON —

  • query/transactionQuery/runStatement: highlighted SQL, params, result-row table (capped at 50, +N more)
  • execute/transactionExecute: SQL + affected rows + returned rows
  • executeBatch/transaction: numbered step list, failed step marked, committed/rolled-back chip
  • prepareStatement/beginTransaction/commit/rollback: handle + status lines
  • listDatabases: name/driver/url/pool table
  • FunctionIdLabel dims the database:: prefix on every card header

Error outputs fall through to the console's built-in error card (which renders the new available list from change 1). Renderer only — no page, no config form; those slots can be added later without rework.

How

  • Scaffold copied from the state worker: build.rs (pnpm→esbuild→ui/dist), src/ui.rs (include_str! + iii-console-ui crate registration, III_DATABASE_UI_WATCH dev watcher), database/ui/ pnpm project joined to the root UI workspace.
  • main.rs now Arc-wraps the client (ConsoleUi::register needs &Arc<IIIClient>; deref coercion keeps every existing call site unchanged).
  • Defensive parsing throughout the renderer: unknown success shapes degrade to a JSON dump inside the card, never a throw.

Verification

  • cargo test in a fresh worktree (no prebuilt ui/dist — exercises the full build.rs→pnpm→esbuild→embed path): 228 passed, 0 failed (incl. 3 new ui.rs asset tests + extended UNKNOWN_DB tests pinning the wire envelope).
  • pnpm build in database/ui: tsc strict clean, page.js 13.4kb / styles.css 3.3kb.
  • Live smoke against a dev engine: GET /ui manifest lists both assets with empty warnings (scoped-CSS lint clean); opened a live scan session in the console — custom cards render (QUERY pill, db primary chip, highlighted SQL, results table), error-status cards correctly fall through to the built-in error view, FunctionIdLabel styles every database::* header.

No version bump / changelog per repo convention (workers-ci handles versions post-merge).

Summary by CodeRabbit

  • New Features
    • Added a database console UI for browsing SQL operations, query results, execution details, transactions, and database listings.
    • Added previews for pending database actions and clearer progress displays for running operations.
  • Bug Fixes
    • Unknown-database errors now list available database names in both messages and structured responses.
    • Improved handling of varied database results without disrupting standard error displays.
  • Build Improvements
    • Database UI assets are automatically built and integrated into the console when needed.

An agent that guesses a wrong db handle got only the bad name echoed
back — in a live scan run, sub-agents burned 25 failed database::execute
calls each brute-forcing 23 handle names before landing on "primary".

UnknownDb now carries the registered handle names, filled from the pools
map at the miss site, so one failure teaches the right name:

  {"code":"UNKNOWN_DB","db":"scans","available":["primary"]}

The code field and existing fields are unchanged; `available` is
additive. listDatabases already exposes the same names to any caller
that can reach the worker, so no new information surface.
…derer

Ship the SOP scaffold (docs/sops/injectable-console-ui.md, state worker
template) and a function-trigger renderer covering all 13 database::*
functions, so calls render as real cards in chat and traces instead of
raw JSON:

- query/transactionQuery/runStatement: highlighted SQL, params, result
  rows as a table (capped at 50 with a +N note)
- execute/transactionExecute: SQL + affected rows + returned rows
- executeBatch/transaction: numbered step list, failed step marked,
  committed/rolled-back chip
- prepareStatement/beginTransaction/commit/rollback: handle + status
- listDatabases: name/driver/url/pool table
- FunctionIdLabel dims the database:: prefix on every card header

Error outputs return null and fall through to the console's built-in
error card. Assets are esbuild outputs embedded via include_str! and
registered through the shared iii-console-ui crate (content function
database::ui-content, III_DATABASE_UI_WATCH dev watcher). main.rs now
Arc-wraps the client — ConsoleUi::register needs &Arc<IIIClient>;
deref coercion keeps every existing call site unchanged.
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment Jul 23, 2026 8:06pm
workers-tech-spec Ready Ready Preview, Comment Jul 23, 2026 8:06pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 48 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@andersonleal, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3828cf31-aab8-4bb1-baa4-820b132c2a39

📥 Commits

Reviewing files that changed from the base of the PR and between daa9260 and 0f497c6.

📒 Files selected for processing (1)
  • .github/workflows/database-e2e.yml
📝 Walkthrough

Walkthrough

The database worker now builds and embeds a console UI that renders database function triggers, registers the UI during worker startup, and reports available database handles in unknown-database errors.

Changes

Database Console UI

Layer / File(s) Summary
Unknown database context
database/src/error.rs, database/src/handlers/..., database/src/driver/sqlite.rs
DbError::UnknownDb includes sorted available handles in error text and serialized output, with related tests updated.
UI asset build pipeline
database/build.rs, database/ui/..., pnpm-workspace.yaml, database/Cargo.toml
The workspace and database crate build page.js and styles.css, validate freshness, support watch mode, and locate pnpm.
Database trigger parsing
database/ui/src/function-trigger-message/parsers.ts
Defensive parsers normalize requests and database operation responses, including query, execute, transaction, and database-list data.
Function trigger renderer
database/ui/src/function-trigger-message/index.tsx, database/ui/page.tsx, database/ui/styles.css
The console renders database SQL, running and approval states, operation results, transaction steps, identifiers, tables, and fallback details with scoped styling.
Embedded UI registration
database/src/lib.rs, database/src/ui.rs, database/src/main.rs
Compiled UI assets are embedded and registered as the database console UI after worker initialization.
Estimated code review effort: 4 (Complex) ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ConsoleHost
  participant DatabaseTriggerRenderer
  participant DatabaseParsers
  participant DatabaseWorker
  ConsoleHost->>DatabaseTriggerRenderer: register database function-trigger renderer
  DatabaseTriggerRenderer->>DatabaseParsers: parse request and output envelope
  DatabaseParsers-->>DatabaseTriggerRenderer: normalized operation data
  DatabaseTriggerRenderer->>DatabaseWorker: render database operation state
  DatabaseWorker-->>ConsoleHost: display embedded database UI
Loading

Suggested reviewers: sergiofilhowz

Poem

I’m a rabbit with bundles tucked tight,
SQL tables now sparkle in light.
Handles list clearly, errors speak true,
Triggers hop through a console UI,
And pnpm builds the whole view just right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: the database console function-calls view and UNKNOWN_DB available-handle enumeration.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/database-console-ui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@andersonleal andersonleal changed the title feat(database): console function-calls view + UNKNOWN_DB handle enumeration (MOT-4208) feat(database): console function-calls view + UNKNOWN_DB handle enumeration Jul 23, 2026
database/build.rs now shells out to pnpm to build ui/dist before
embedding it; the e2e job installed Node but not pnpm, so the cargo
build died in locate_pnpm() (build.rs:168). ci.yml's rust job already
sets up pnpm via the hashFiles(ui/package.json) condition, and the
release path auto-detects ui/ (web_bundle) — this was the one job
missing the toolchain.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@database/ui/src/function-trigger-message/index.tsx`:
- Around line 18-24: Update the imports in function-trigger-message to import
React before the existing React.ReactNode type references, preserving the
current CodeHighlight and renderer imports and component behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7139fac8-7b4b-414b-b8fc-e9601a407d74

📥 Commits

Reviewing files that changed from the base of the PR and between ad795f9 and daa9260.

⛔ Files ignored due to path filters (2)
  • database/Cargo.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • database/Cargo.toml
  • database/build.rs
  • database/src/driver/sqlite.rs
  • database/src/error.rs
  • database/src/handlers/mod.rs
  • database/src/handlers/query.rs
  • database/src/handlers/transaction.rs
  • database/src/lib.rs
  • database/src/main.rs
  • database/src/ui.rs
  • database/ui/build.mjs
  • database/ui/package.json
  • database/ui/page.tsx
  • database/ui/src/function-trigger-message/index.tsx
  • database/ui/src/function-trigger-message/parsers.ts
  • database/ui/styles.css
  • database/ui/tsconfig.json
  • pnpm-workspace.yaml

Comment on lines +18 to +24
import {
CodeHighlight,
type FunctionTriggerMessage,
type FunctionTriggerRenderer,
type Host,
JsonHighlight,
} from '@iii-dev/console-ui'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm no react import exists despite React.ReactNode usage
rg -n "React\." database/ui/src/function-trigger-message/index.tsx
rg -n "^import" database/ui/src/function-trigger-message/index.tsx
cat -n database/ui/tsconfig.json

Repository: iii-hq/workers

Length of output: 671


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package scripts =="
node - <<'JS'
const fs = require('fs');
for (const p of ['package.json','database/ui/package.json']) {
  if (fs.existsSync(p)) {
    const pkg = JSON.parse(fs.readFileSync(p, 'utf8'));
    console.log(p, pkg.scripts || {});
  }
}
JS

echo "== dependency availability =="
if [ -d node_modules/typescript/lib ]; then
  tslib=$(find node_modules/typescript/lib -maxdepth 1 -name 'typescript*.d.ts' | head -1)
  echo "typescript d.ts: ${tslib:-missing}"
else
  echo "node_modules/typescript/lib missing"
fi

echo "== exact file excerpt =="
sed -n '1,40p;65,78p;338,350p' database/ui/src/function-trigger-message/index.tsx | cat -n

echo "== behavioral probe against repository TypeScript config (if tsc is available) =="
node - <<'JS'
const {existsSync, readFileSync, writeFileSync} = require('fs');
const {execFileSync} = require('child_process');
if (!existsSync('node_modules/.bin/tsc')) {
  console.log('tsc not available in node_modules/.bin');
  process.exit(0);
}
const tsconfig = JSON.parse(readFileSync('database/ui/tsconfig.json','utf8'));
tsconfig.include = ['src/function-trigger-message/index.tsx'];
writeFileSync('/tmp/probe-tsconfig.json', JSON.stringify(tsconfig, null, 2));
const probe = `import { CodeHighlight } from '`@iii-dev/console-ui`';
type T1 = React.ReactNode;
declare const x: T1;
`;
writeFileSync('/tmp/probe.tsx', probe);
writeFileSync('/tmp/probe-package.json', JSON.stringify({type:'module'}));
try {
  execFileSync('node_modules/.bin/tsc', ['/tmp/probe.tsx', '--project', '/tmp/probe-tsconfig.json', '--noEmit'], {stdio:'inherit'});
  console.log('RESULT: tsc no error');
} catch (e) {
  console.log('RESULT: tsc failed with exit', e.status);
}
JS

Repository: iii-hq/workers

Length of output: 3145


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate `@types/react` availability =="
fd -a "^index\.d\.ts$" node_modules 2>/dev/null | rg '/@types/react/.*/index\.d\.ts$|react.*index\.d\.ts' | head -5 || true

echo "== package manifests mentioning react and deps =="
python3 - <<'PY'
import json, pathlib
for p in pathlib.Path('.').rglob('package.json'):
    if 'node_modules' in p.parts:
        continue
    try:
        pkg=json.loads(p.read_text())
    except Exception:
        continue
    deps={}
    for k in ['dependencies','devDependencies','peerDependencies','optionalDependencies']:
        if k in pkg:
            deps.update(pkg[k])
    if 'react' in deps or 'react-dom' in deps:
        print(p, {dep: deps.get(dep) for deg, dep in enumerate(deps) if dep in ('react','react-dom')})
PY

echo "== local package lock react entries (if present) =="
for f in package-lock.json npm-shrinkwrap.json pnpm-lock.yaml yarn.lock bun.lockb bun.lock; do
  [ -f "$f" ] && echo "--- $f" && rg -n '"?react"?:|react@|react-dom' "$f" | head -20 || true
done

Repository: iii-hq/workers

Length of output: 2612


🏁 Script executed:

#!/bin/bash
set -euo pipefail
node - <<'JS'
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('database/ui/package.json', 'utf8'));
const entries = [
  ...Object.entries(pkg.dependencies || {}),
  ...Object.entries(pkg.devDependencies || {}),
  ...Object.entries(pkg.peerDependencies || {}),
];
const reactRelevant = entries.filter(([name]) => name === 'react' || name === 'react-dom' || name === '`@types/react`' || name === '`@types/react-dom`' || name.includes('console-ui'));
console.log(JSON.stringify({name: pkg.name, scripts: pkg.scripts, reactRelevant}, null, 2));
JS

Repository: iii-hq/workers

Length of output: 437


🌐 Web query:

TypeScript MDX @mdx-js/react v3 React.ReactNode without import JSX namespace react-jsx

💡 Result:

To use TypeScript with @mdx-js/react v3 and React.ReactNode without explicitly importing the global JSX namespace or react-jsx, you must ensure that your TypeScript environment is correctly configured to recognize the React types [1][2]. 1. Install React Types: The foundational requirement is to have @types/react installed in your project [1][3]. npm install --save-dev @types/react 2. Understanding the JSX Namespace: The MDX documentation explicitly states that for types to function correctly, the TypeScript JSX namespace must be typed [2][4]. This is achieved by including @types/react in your project's dependencies [1][5]. TypeScript automatically merges JSX types into the global namespace when these types are present [6][7]. You do not need to manually import a "JSX namespace" or "react-jsx" in your individual files; rather, you rely on the presence of the @types/react package to provide these definitions globally for your project [1][3]. 3. Type Usage: When defining components that use React.ReactNode, you can import it directly from 'react' to avoid relying on implicit globals [7]. import type { ReactNode } from 'react'; // Using it in a component interface MyProps { children?: ReactNode; } 4. MDX Integration: When using @mdx-js/react, ensure your MDX compiler (e.g., in Webpack, Vite, or Rollup) is configured with providerImportSource: '@mdx-js/react' [2][4]. This allows MDX to use the React context provider for components [8][9]. If you are encountering errors regarding "ReactNode" not being found or JSX types missing, it is typically because @types/react is either missing or your tsconfig.json is not including the necessary type definitions. Ensure your tsconfig.json includes "compilerOptions": { "types": ["react", "react-dom"] } if automatic detection fails, though this is rarely necessary in modern setups [1][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== console-ui package metadata =="
node - <<'JS'
const fs = require('fs');
for (const rel of ['packages/console-ui/package.json','console/package/package.json','console/web/package.json','database/ui/package.json']) {
  try {
    const data = JSON.parse(fs.readFileSync(rel, 'utf8'));
    console.log('---', rel);
    console.log(JSON.stringify({name:data.name, version:data.version, scripts:data.scripts, dependencies:data.dependencies, devDependencies:data.devDependencies, peerDependencies:data.peerDependencies, exports:data.exports, types:data.types, main:data.main}, null, 2));
  } catch (e) {
    console.log('---', rel, e.message);
  }
}
JS

echo "== tsconfig resolution in relevant packages =="
for f in database/ui/tsconfig.json packages/console-ui/tsconfig.json console/web/tsconfig.json console/package/tsconfig.json; do
  [ -f "$f" ] && { echo "--- $f"; cat -n "$f"; }
done

echo "== deterministic TypeScript JSX namespace probe from scratch =="
cd "$(mktemp -d)"
export HOME="$(mktemp -d)"
cat > tsconfig.json <<'JSON'
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "strict": true,
    "skipLibCheck": true,
    "noEmit": true,
    "types": []
  },
  "include": ["probe.tsx"]
}
JSON
cat > package.json <<'JSON'
{"type":"module"}
JSON
mkdir -p node_modules/@types/react
cat > node_modules/@types/react/index.d.ts <<'DTS'
export as namespace React;
export type ReactNode = null | boolean | string | number | ReactElement;
interface JSX {
  createElement(type: any, props?: any, ...children: any[]): ReactElement;
}
export interface ReactElement {}
DTS
cat > probe.tsx <<'TSX'
import { Component } from '`@iii-dev/console-ui`';
type Props = { head?: React.ReactNode; children?: React.ReactNode };
const render = (): React.ReactNode | null => null;
TSX
npm install --no-save --no-audit --no-fund typescript 1>/dev/null
./node_modules/.bin/tsc --project tsconfig.json 2>&1 || true

Repository: iii-hq/workers

Length of output: 4468


Import React before referencing React.ReactNode.

This file references React.ReactNode three times, but has no react/React import. With this module containing top-level import/export and the UI build running tsc --noEmit, these React namespace references fail TypeScript type-checking.

🐛 Proposed fix
 import {
   CodeHighlight,
   type FunctionTriggerMessage,
   type FunctionTriggerRenderer,
   type Host,
   JsonHighlight,
 } from '`@iii-dev/console-ui`'
+import type React from 'react'
 import {
   DB_PREFIX,
   type DbRequest,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import {
CodeHighlight,
type FunctionTriggerMessage,
type FunctionTriggerRenderer,
type Host,
JsonHighlight,
} from '@iii-dev/console-ui'
import {
CodeHighlight,
type FunctionTriggerMessage,
type FunctionTriggerRenderer,
type Host,
JsonHighlight,
} from '`@iii-dev/console-ui`'
import type React from 'react'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/ui/src/function-trigger-message/index.tsx` around lines 18 - 24,
Update the imports in function-trigger-message to import React before the
existing React.ReactNode type references, preserving the current CodeHighlight
and renderer imports and component behavior.

…ndency

pnpm@11 (repo packageManager) needs the node:sqlite builtin (Node >=22.5)
for its store; the job pinned Node 20 so pnpm install died with
ERR_UNKNOWN_BUILTIN_MODULE inside build.rs. ci.yml's pnpm jobs already
standardize on 22; the e2e harness has no engines pin (only a
@types/node ^20 dev dependency, which is types-only).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant