saropa_drift_advisor 3.7.1
saropa_drift_advisor: ^3.7.1 copied to clipboard
Debug-only HTTP server that exposes SQLite/Drift table data as JSON and a minimal web viewer. Use from any Drift (or raw SQLite) app via an injectable query callback.
Changelog #
Introduction #
This changelog is for Saropa Drift Advisor: the Dart package that wires up Drift’s debug server and web viewer, plus the Drift Viewer extensions for VS Code and Open VSX.
Releases are listed newest first. Each version’s opening paragraph sums up what changed for users and ends with a log link to this file at that release’s tag on GitHub.
Install the library from pub.dev; report issues and browse source on GitHub. History before 2.6.0 lives in CHANGELOG_ARCHIVE.md.
Links #
pub.dev — pub.dev / packages / saropa_drift_advisor
VS Code marketplace - marketplace.visualstudio.com / items ? itemName=Saropa.drift-viewer
Open VSX Registry - open-vsx.org / extension / saropa / drift-viewer
3.7.1 #
Paste a query and see it as a diagram: the web viewer's query builder can now turn a SELECT you've typed (or pasted) into the multi-table visual graph.
Added #
- Website: import SQL into the visual builder — in the debug web viewer's query builder, switch to Raw SQL, paste or write a flat
SELECT, and click Import to visual builder to reconstruct it as a multi-table graph (tables, JOINs, selected columns and aggregates, WHERE filters, GROUP BY, ORDER BY, and LIMIT). The builder then re-renders the exact same SQL, so you can keep editing visually and run it against your data. Supports the same query shape the VS Code Visual Query Builder produces (quoted identifiers,ASaliases, INNER/LEFT/RIGHT joins on column equality, self-joins,=/!=/</>/<=/>=/LIKE/IN/IS [NOT] NULL); unsupported constructs (CTEs,UNION, subqueries) are reported instead of producing a wrong graph, and a failed parse leaves your current builder untouched. This closes the last gap between the website query builder and the extension's.
Maintenance
- Single source of truth for query-builder SQL (Feature 21, Phase 1) — the visual query builder's SQL rendering, validation, literal escaping, WHERE-operator lists, and flat-
SELECTimporter were previously hand-synced between the extension (sql-renderer.ts,sql-import*.ts) and the web bundle (query-builder-sql.ts,query-builder-import.ts), so the two could silently diverge and emit different SQL for the same model. Extracted them into self-contained, dependency-freequery-builder-core*.tsmodules (-corerender/validate/literal,-core-opsoperator lists,-core-parsestring primitives,-core-import+-core-import-clausesparser) that compile into both the extension (tsc) and the web bundle (esbuild). The extension'ssql-renderer.ts/sql-import.tsand the web'squery-builder-sql.ts/query-builder-import.tsare now thin adapters re-exporting or delegating to the shared core; the importer injects a per-surface table factory so the extension keeps its initials aliases + canvaspositionand the web keepstNaliases. Deleted the five now-redundantsql-import-{utils,from-joins,select-list,where,group-order}.tshelpers. The shared validator also adds the JOIN-reachability check the web had but the extension lacked (a disconnected table now reports an error instead of producing an un-runnable cross-join SELECT). All 2677 extension tests pass; web typecheck/build clean; an import→render→import→render stability check confirms identical re-rendered SQL.
3.7.0 #
Two new ways to work with your data over time: a Time Travel slider to scrub a table's snapshot history, and Data Branches to capture, diff, and restore named snapshots of the whole database like git stash for your data.
Added #
-
Time Travel data slider — right-click any table in the Database Explorer → Time Travel (or run it from the command palette) to open a slider across all captured snapshots of that table. Drag the slider, step with the ◀ ▶ buttons, or press play to animate; each frame highlights rows added (green), removed (red, struck through), and changed (amber, with the exact changed cells marked) versus the previous snapshot. A table picker and 0.5×–4× speed control sit above the grid, and the panel updates live as new snapshots are captured. Built on the existing snapshot history, using each table's real primary key to match rows.
-
Data Branches (git-style) — capture the whole database as a named branch, then experiment freely and compare. Open Data Branches from the Database Explorer toolbar (or "Create Data Branch" from the palette) to capture the current state. Each branch offers Diff vs Now (a row-level insert/update/delete view against the live database), Generate Merge SQL (differential SQL — forward or the reverse rollback — opened in an editor tab, with deletes ordered children-first so foreign keys are never violated), Restore (overwrite the live database with the branch's rows, with an offer to back up the current state first), and Delete. Branches persist in the workspace and honor configurable caps (
branching.maxBranches,branching.maxRowsPerTable); a branch that hits the row cap is flagged as truncated so a partial capture is never mistaken for a complete one. -
Refactoring: extract common column groups — the schema refactoring advisor now detects column bundles that repeat across two or more tables and suggests defining them once. It recognizes known families — audit/timestamp columns (
created_at,updated_at, …), soft-delete flags, and address blocks (includingaddr_*prefixes) — and tolerates ragged sets where the same bundle appears in slightly different tables, plus any generic group of columns that always appears together. Columns whose type is inconsistent across tables are excluded so an extraction never forces a lossy type decision. Each suggestion opens a migration plan with a shared-table + foreign-key template and a ready-to-use Drift mixin (so per-row metadata like timestamps can reuse definitions instead of being normalized), with the backfill and column drops left as flagged advisory steps. Detection is schema-only and runs no queries against your data. -
Website: code-declared schema tab — a new Code schema tool in the debug web viewer shows the schema as declared in your Drift code (tables, columns, types, primary keys, nullability), separate from the live SQLite file — useful for spotting drift between code and the running database. It reads a new
GET /api/schema/declaredendpoint, which is served from an optional host callback: apps started with thestartDriftViewerextension get it automatically (derived from the Drift database), or you can pass adeclaredSchemacallback toDriftDebugServer.start. When no schema is supplied the tab shows a short explanation and the endpoint reportsavailable: false— never an error. New public typesDeclaredColumn,DeclaredTable,DeclaredSchema, andDeclaredSchemaCallbacksupport the callback. -
Website: multiple snapshots — the debug web viewer's Snapshot tool now keeps several snapshots instead of a single slot. Each capture is appended (with an optional label you're prompted for) and listed with its timestamp and table count; rename or delete any one, or clear them all. Two selectors let you diff any pair — pick a From snapshot and a To snapshot, or leave To on "now (live DB)" for the classic snapshot-vs-current comparison. Up to 20 snapshots are retained, oldest evicted first. New endpoints back it:
GET /api/snapshots(list),GET /api/snapshot/compare?from=&to=(pairwise;toomitted means live),DELETE /api/snapshot/{id}(one) alongside the existing clear-all, andPUT /api/snapshot/{id}(rename). Older single-snapshot clients keep working —POST/GET /api/snapshotand the no-argument compare behave as before, now operating on the most recent snapshot. -
Website: bulk index creation — the debug web viewer's Index suggestions tool now lets you act on suggestions, not just copy them. Each suggestion gets a checkbox (plus a select-all); pick two or more, click Preview SQL to see the exact
CREATE INDEXstatements validated server-side (with any rejected ones called out), then Apply selected to create them all in one click. Applying is best-effort and reports per-index success or failure, so one bad statement never silently drops the others, and a toast prompts you to re-run Analyze to refresh the list. Apply is shown only when the server was started with writes enabled; otherwise the bar explains it is read-only. Backed by two new endpoints —POST /api/indexes/preview(validate only, safe on read-only servers) andPOST /api/indexes/apply— gated by a dedicated single-CREATE INDEXvalidator so no other SQL can ride along.
Changed #
- Health Score reacts to the refactoring advisor — the Schema Quality metric now applies a small, bounded penalty (up to 15 points) for high-severity refactoring suggestions you have run but not yet acted on or dismissed in the advisor panel. Each deduction is explained in a detail line on the Schema Quality card, and dismissing a suggestion restores the points on the next score. The penalty is separate from the existing missing-primary-key check, so no issue is counted twice, and databases with no advisor session keep their previous grade unchanged.
Maintenance
- Modularize files over the 300-line limit — split the 19 extension source files that exceeded the Step 7 quality-check line cap into cohesive sibling modules along their natural seams, with no behavior change (all 2677 tests pass). Each original file keeps its public exports (moved symbols are re-exported where callers depend on them) so no call sites changed. Highlights:
sql-import.ts(688) split into per-clause parsers (sql-import-{utils,from-joins,select-list,where,group-order}.ts); the refactoring analyzer and plan-builder split into helpers + per-detector / per-plan-type modules;api-client.tssplit into aDriftApiClientBase(HTTP-only/session/DVR) theDriftApiClientsubclass extends, andapi-client-http-impl.tsinto per-domain endpoint files re-exported from a barrel; the query-builder, DVR, and refactoring panels split their message routing / model-ops / integration handlers into separate files; webview HTML files (query-builder-html,health-html,sql-notebook-html, plus the convention-violating inlinebulkEditHtml) split their CSS / client JS into dedicated modules; and the activation/command files split out event-wiring and the feature-command registry. Test files are exempted instead of split — the line check now applies a higher cap (MAX_TEST_FILE_LINES = 500) to*.test.tswhile production source stays at 300 (scripts/modules/constants.py,ext_build.py). - Fix missing Code schema tab icon — the new
declared("Code schema") tool added aTOOL_LABELSentry but no matchingTOOL_ICONSentry, so the tab rendered without an icon and thetab-icons-accenttest failed (everyTOOL_LABELSkey must have an icon). Addeddeclared: 'code'. - Plan housekeeping — archived the shipped Mutation Stream plan (
22-realtime-mutation-stream.md→plans/history/2026.06/2026.06.10/), removed the now-redundantGAP_FIT_PLAN.mdredirect stub from the active tree (its full analysis was already archived and the per-feature plans 71–74 point straight at the archive), and added explicit## Implementation Planheadings toesbuild-ts-migration.mdandfix-pub-dev-publisher.mdso every active plan presents its plan under one heading. - Connection reliability Phase 2 — end-to-end lifecycle test — added
connection-lifecycle.test.ts, the full-chain regression net the project never had: wiring → discovery scans → server found → tree loads → command invoked → data appears. It wires the realDriftApiClient+ServerDiscovery+ServerManager+DriftTreeProvider+ConnectionStateMachineagainst a stubbed HTTP server, asserts table rows appear at the end, then deliberately breaks each link once (no discovery, failed schema load, unregistered command) and asserts the end state is not reached — so a silent break in any single link fails a test instead of shipping. (Phase 2 ofplans/connection-reliability-ongoing.md.) - Connection reliability Phase 1 — single connection-state authority — introduced
connection-state.ts(ConnectionStateMachineplus a purecomputeConnectionPhase/deriveConnectionContextsmodel) as the one place that owns the connection truth and the sole writer of thedriftViewer.serverConnectedanddriftViewer.databaseTreeEmptycontext keys.isDriftUiConnected,buildConnectionPresentation, and the connection-UI refresh funnel now derive "transport up" from that single model instead of each recomputing their own boolean, so the two long-standing contradictions — "connected but no data" and "disconnected but server running" — are no longer representable. The Database tree exposes ahasLiveSchemasignal feeding the machine. Newconnection-state.test.tsenumerates all 16 signal combinations and drives the machine through the full disconnected → connecting → connected → offline lifecycle, asserting the flags can never disagree. No behavior change to the tree's always-return-rows workaround. (First structural phase ofplans/connection-reliability-ongoing.md.) - Archive the website-vs-extension gap analysis; split remaining work into per-feature plans — the parity sweep is complete (all high-impact and quick-win gaps closed on both surfaces), so
plans/GAP_FIT_PLAN.mdmoved toplans/history/2026.06/2026.06.10/with a short stub left in place. The handful of still-open rows were lifted into standalone, individually trackable plans rather than buried in the archived tables:71-website-dart-schema-scanning.md(§5),72-website-multiple-snapshots.md(§8),73-website-bulk-index-creation.md(§11), and74-ide-only-capabilities.md— which reclassifies go-to-definition, code actions, and data breakpoints as intentionally IDE-only rather than unresolved parity gaps. The doc-maintenance backlog (evidence coverage, classification cleanup, parity release gate) retires with the archive.
3.6.1 #
Added #
- Orphan physical-table check — flags tables that physically exist in the SQLite file but are not declared anywhere in your Drift schema (typically left behind by a migration whose Drift definition was later removed or renamed). These are invisible to a schema-first audit and silently bloat the database, so the check starts from the physical side: it enumerates the real tables and subtracts the ones your schema declares. Findings appear in
GET /api/issues(alongside index suggestions and anomalies) and at the newGET /api/analytics/orphan-tablesendpoint, each naming the exact table and suggesting aDROP TABLEyou can run by hand. It is report-only and never drops anything. When you start the viewer withstartDriftViewer, the declared table set is derived automatically from your Drift database; with the callback API, pass the newdeclaredTableNamesparameter to enable it. Without a declared set the check stays silent, so it never produces false positives. Android'sandroid_metadatabookkeeping table is excluded by default (lib/src/server/orphan_table_detector.dart,lib/src/server/analytics_handler.dart,lib/src/server/router.dart,lib/src/server/server_context.dart,lib/src/start_drift_viewer_extension.dart,lib/src/drift_debug_server_io.dart)
Maintenance
- Timeline auto-capture: coalesce write bursts into one re-dump — an open timeline previously re-scanned every physical table (schema metadata + a per-table
SELECT, a thousand-plus queries) on every detected DB write, and the old leading-edge guard fired that scan on the first write of a burst — the worst moment, mid write-storm — while silently dropping the rest, which could leave the panel stale on the final committed write.SnapshotStore.requestCapturenow applies a trailing-edge debounce: writes within a quiet window (newdriftViewer.timeline.captureDebounceMs, default 200 ms) reset the timer, so one re-dump runs after the burst settles, reflecting the coalesced final state, and the coalesced count is logged astimeline: re-dump (coalesced K writes)(extension/src/timeline/snapshot-store.ts,extension/src/extension-providers.ts,extension/src/extension-activation-final.ts,extension/package.json)
3.6.0 #
Improved #
- Startup banner: emulator/device port-forward hint — the server startup banner now shows the exact
adb forward tcp:<port> tcp:<port>command alongside thehttp://127.0.0.1:<port>URL. When the host app runs on an Android emulator or a physical device, the bound port lives in that device's network namespace, so a host browser/viewer cannot reach the printed URL until the port is forwarded — previously "server started" and "viewer offline" looked contradictory with no on-screen guidance (lib/src/drift_debug_server_io.dart,lib/src/server/server_constants.dart)
Fixed #
- Startup banner showed the requested port, not the bound port — when the server was started with
port: 0(let the OS pick an ephemeral port), the banner printedhttp://127.0.0.1:0; it now prints the actual OS-assigned port so the URL and the newadb forwardcommand are copy-pasteable. The default fixed port (8642) was unaffected (lib/src/drift_debug_server_io.dart)
Added #
- Web viewer: dimmed NULL cells with display option — SQL
NULLvalues in data tables now render dimmed (muted + italic) so empty cells are visually distinct from real text; new Settings → Table Defaults → "NULL display" lets you switch the label betweenNULL(default) and-(assets/web/_data-display.scss,state.ts,settings.ts,table-view.ts)
Changed #
- Web viewer: tables sidebar row counts — the row count next to each table name is now rendered one step smaller (
--text-xs) so it reads as secondary metadata, and empty-table counts ((0)) are dimmed at 50% opacity so non-zero rows win the eye when scanning the list (assets/web/table-list.ts,assets/web/_sidebar.scss)
Maintenance
- Lint hygiene — appended
--rationales to// ignore_for_fileand// ignoredirectives inlib/src/drift_debug_server_io.dartto satisfydocument_analyzer_ignore_rationale - Doc headers on flagged-complexity methods — added concise
///headers on_isTextAffinity(lib/src/server/cell_update_handler.dart),_classifySql/_parseTableName/_record(lib/src/query_recorder.dart),_recordEvent/_extractWhereClause(lib/src/server/mutation_tracker.dart), and_migrationColumnMap(lib/src/server/compare_handler.dart) so static-analysis complexity reports surface intent alongside the metric
3.5.0 #
Query Replay DVR is now available in the extension and server API, so you can record SQL activity during debug sessions and inspect recent queries in a timeline panel. Bulk editing also got a dedicated pending-changes grid in the extension, clearer batch-commit failures, and safer inline edits in the browser viewer when writes are enabled. The extension also adds a Visual Query Builder with optional SQL import and a full natural-language-to-SQL flow: after the model answers, you can land the SQL in the notebook, the query builder, a saved snippet, a dashboard SQL widget, or query cost, with an optional starter picker and safer prompts on huge schemas. log
Added #
- Web debug viewer: multi-table query builder — on a table tab, choose Multi-table next to Single table to compose JOINs (FK hints from existing metadata), multi-column
SELECTwith optional aggregates whenGROUP BYis set, stackedORDER BYclauses, type-awareWHERE(includingIN), andLIMIT, with live preview and the samePOST /api/sqlrun path as the classic builder (assets/web/query-builder-sql.ts,query-builder-multi.ts) - Visual Query Builder — compose flat
SELECTqueries against the connected schema (tables, joins, filters, aggregates,GROUP BY/ORDER BY/LIMIT) in a webview with live SQL preview and run; command Visual Query Builder (driftViewer.openQueryBuilder) - Import SQL into Visual Query Builder — paste or pick generated
SELECTtext and map it back into the visual model where the dialect matches the builder output (best-effort;WITH/UNIONnot supported yet); command Import SQL into Visual Query Builder (driftViewer.openQueryBuilderFromSql) - Natural language to SQL (NL-SQL) — Ask Natural Language (
driftViewer.askNaturalLanguage) and NL Query History (driftViewer.nlSqlHistory) use OpenAI-compatible chat settings with the API key in secret storage. Before calling the LLM you can optionally pick a starter prompt from past NL questions, saved table filters, and SQL Notebook run history (driftViewer.nlSql.seedSuggestions); turn that off for a simple single-line prompt instead - NL-SQL: where the SQL goes — after validation, a QuickPick sends the generated
SELECT/WITHto SQL Notebook (new query tab), Visual Query Builder, Save as Snippet (with a suggested name), Add SQL query widget to the dashboard (driftViewer.addQueryWidgetToDashboard), or Analyze query cost; the same picker is used when reopening from NL Query History - NL-SQL: big schemas & follow-on tooling — schema text for the LLM can follow Schema Intelligence when that subsystem started successfully, otherwise live metadata from the server; table and character caps (
driftViewer.nlSql.maxSchemaTables,maxSchemaContextChars) keep token-heavy databases from overfilling the prompt. When Query Intelligence is active, a successful generation is also recorded for pattern hints. If Saropa Log Capture is enabled andperformance.logToCaptureis notoff, each successful NL generation can emit a compactnl-queryJSON line for session logs - Query Replay DVR endpoints on the debug server — added
GET /api/dvr/status,POST /api/dvr/start,POST /api/dvr/stop,POST /api/dvr/pause,POST /api/dvr/config,GET /api/dvr/queries, andGET /api/dvr/query/:sessionId/:idwith versioned envelopes and ring-buffer window metadata for robust client pagination/error handling; status now reports buffer size and before/after capture flags when supported;POST /api/sqlaccepts optionalargs/namedArgsfor DVR-declared bindings (JSON-safe normalization); writeaffectedRowCountuses SQLitechanges()whenwriteQueryis configured; optionalqueryWithBindings/writeQueryWithBindingsonDriftDebugServer.startfor read/write host callbacks that accept declared bindings (HTTP write paths still pass SQL strings until extended); VM Serviceext.saropa.drift.runSqlaccepts the same read bindings as flat JSON strings (args,namedArgs) - Query Replay DVR panel + commands in the extension — added
driftViewer.openDvr,driftViewer.dvrStartRecording, anddriftViewer.dvrStopRecording, plus a DVR webview with filters, semantic search over row snapshots, timeline stepping (buttons + Home/End/arrows), selection detail (/api/dvr/query), JSON export, SQL editor / SQL Notebook / Query Cost actions, a status bar DVR indicator, auto-refresh when schema generation changes, and start/pause/stop/refresh controls; DVR refresh feeds Query Intelligence when active and optionally merges DVR timings into perf baselines (driftViewer.perfRegression.recordBaselinesFromDvr, optionalwarnOnDvrPanelRefresh); toolbar Snapshot diff runsdriftViewer.showSnapshotDiff; Schema rollback… runsdriftViewer.generateRollback - Debug lifecycle auto-record wiring — extension now auto-starts DVR recording on Dart/Flutter debug session start (configurable) and attempts to stop recording on debug-session termination
- Bulk Edit panel grid —
driftViewer.editTableDataopens a dashboard-style webview with a paged grid of pending cell changes, redo support, the same preview/apply/discard flows as before, keyboard navigation on the pending-changes grid (focus the grid with Tab, move selection with arrows, Enter opens the table viewer, Escape clears selection), and toolbar links to Data invariants, Paste from clipboard, Query DVR, and Capture DB snapshot (runsdriftViewer.captureSnapshotas a safety net before destructive work until full plan-37 data branching exists) - Anomaly Detection → bulk edit — the anomalies webview adds Bulk edit table… to pick a single-PK table and jump straight into the bulk edit dashboard
- Batch apply failure detail — when
POST /api/edits/applyfails on one statement in a transaction, the error JSON can includefailedIndexandfailedStatement; the extension surfaces formatted messages plus Preview SQL and Copy Failed SQL actions on commit errors - Web viewer inline editing (v1) — when
/api/healthreports writes enabled and the table has a single-column primary key, you can double-click a cell for explicit Save/Cancel (no blur commit), delete a row with confirmation, and get a leave-page prompt if a cell edit is still open; the row highlights when your draft differs from the loaded value, failed saves offer Retry save and Reload table, and failed deletes can reload the grid from a confirm dialog - Schema refactoring suggestions (Feature 66) — Suggest Schema Refactorings (
driftViewer.suggestSchemaRefactorings) opens a panel that analyzes the connected schema (normalization, wide-table split hints, overlap-based merge hints), shows advisory migration steps, and can copy SQL or Dart snippets; Open Refactoring Advisor (External Hint) (driftViewer.refactoringOpenWithHint) opens the same panel with a hint banner for table/column context; toolbar links for Generate migration, Schema diff, migration preview, and ER diagram; also available from the Database view toolbar when a server is connected - Refactoring Phase 3 integrations — migration preview accepts an optional appended advisory SQL block; ER diagram command accepts optional table focus; NL-to-SQL accepts a pre-filled question; health score webview shows the last refactoring session summary (including dismiss count) and Schema Quality metric text can include advisor session lines when you refresh the health panel after analyzing refactorings
Maintenance
- Cross-stack API typing for DVR — added DVR envelope/status/query/page types in
extension/src/api-types.tsand HTTP/client transport methods inextension/src/api-client-http-impl.tsandextension/src/api-client.tsto keep server/extension contracts aligned - DVR integration tests — extended
test/handler_integration_test.dartto validate DVR route availability, basic recording flow,POST /api/dvr/config, wrong-session lookups,POST /api/sqldeclaredargs/namedArgson DVR entries, and structuredQUERY_NOT_AVAILABLEbehavior; addedtest/query_recorder_test.dart,test/dvr_bindings_test.dart, and extension contract/search tests for DVR JSON parsing and semantic search; golden JSON fixtures underextension/src/test/fixtures/dvr/(envelope, status, recorded row,QUERY_NOT_AVAILABLE, legacyrowCount, missingparams);extension/src/test/dvr-perf-baseline.test.tsfor DVR → baseline helpers - DVR write snapshots — when
writeQueryuses the mutation tracker, DVR write entries can include the same best-effort before/after row snapshots as/api/mutations(still subject tocaptureBeforeAfterand ring-buffer limits) - Bulk edit / edits-apply hardening —
EditsBatchHandlerwraps per-statement failures inBatchApplyStatementError;test/handler_integration_test.dartcovers semicolon-chained statement rejection and failure payload keys; extension tests cover PK gates, HTTP client error parsing, bulk panel HTML, and web inline-edit contract strings - Bulk apply session log + timeline — after a successful pending-edit batch apply, the extension appends one timestamped line to the Drift Advisor output channel and triggers an immediate snapshot capture (debounce bypass) so the Drift Database VS Code timeline row-count history updates right away; DVR write capture for each statement remains unchanged
- Refactoring engine extension tests — added
extension/src/test/refactoring-analyzer.test.tsandrefactoring-plan-builder.test.tsfor analyzer heuristics and plan templates - Refactoring Phase 3 modules —
refactoring-advisor-state.tsandrefactoring-nl-bridge.tsfor workspace session persistence and NL-SQL seed prompts - Query builder import —
extension/src/query-builder/sql-import.tsparsesFROM/JOIN/WHERE/GROUP BY/ORDER BY/LIMITsegments using successive clause boundaries soLIMITis not swallowed intoWHEREor theFROMclause; covered byextension/src/test/sql-import.test.tswith renderer round-trips - Web query builder SQL layer —
assets/web/query-builder-sql.tsmirrors extensionsql-renderervalidation/rendering (join connectivity,GROUP BY/ aggregate rules) so the browser preview matches execution;npm run typecheck:webcovers the new modules
3.4.1 #
Publish-pipeline bug report refreshed (no change to the shipped Dart package or extension behavior in this tag). log
Maintenance
bugs/PROBABLE_marketplace_failure_blocks_open_vsx_publish.md— verified againstscripts/modules/ext_publish.py(_run_publish_steps): added line-level citations for the Marketplace failure path that returns before Step 14 (Open VSX), tightened repro steps, and replaced a Windows-onlyrgexample with repo-root commands
3.4.0 #
No more bogus "potential outlier" warnings on lastModified / last_seen style timestamp columns, and every anomaly and missing-index suggestion now appears exactly once in the Problems panel instead of twice. Outlier messages also now tell you how many rows were sampled. log
Fixed #
- Anomaly false positive on
lastModified/last_seen/last_accessedstyle timestamp columns — the data-quality scanner was firing a "Potential outlier in <table>.last_modified: max value … is 4.1σ from mean …" on any Drift table whoseDateTimeColumn get lastModifiedhad been written to a few times within the same day. The prior skip pattern covered^created/^updated/^deleted/^modifiedprefixes but nothing starting withlast_, so Drift's canonicallastModified(serialized aslast_modifiedin SQLite) fell straight through to the 3σ check. On a ~17-hour window σ is tiny by construction and the newest write always sits many σ above the mean — the "outlier" is just "the row we just wrote." The timestamp-skip pattern inAnomalyDetector._detectNumericOutliersnow matcheslast_modified,last_seen,last_accessed,last_used,last_sync/last_synced,last_refresh/last_refreshed,last_login/last_logout,last_activity/last_active,last_read/last_written,last_opened/last_viewed/last_played,last_fetch/last_fetched,last_heartbeat/last_ping,last_visit/last_visited,last_check/last_checked,last_poll/last_polled,last_scan/last_scanned— in both snake_case and camelCase, without widening to generic^last_.*(which would have swallowedlast_name/last_ip). Reported in plans/history/2026.04/2026.04.22/BUG_anomaly_false_positive_tight_timestamp_range.md - Potential outlier diagnostic now reports sample size — the message now ends with
n=<sampleCount>(e.g. "… (range [1.0, 999.0], n=37)") alongside the existing min/mean/max/σ numbers. The minimum sample-size guard (n ≥ 30) filters the worst low-nfalse positives, but sigma estimates are still wide between ~30 and ~100 samples and the reader has no way to tell how big the n actually is from the old message. Surfacing it lets "4.1σ at n=35" be treated as weaker evidence than the same value at n=5000 without having to go query the table. Covers suggested fix #5 in the same bug report - Duplicate diagnostics — same anomaly and same index suggestion shown twice per file — every anomaly (null counts, empty strings, potential outliers, orphaned FKs) AND every missing-index suggestion was being published through two separate VS Code
DiagnosticCollections inside the extension: the legacydrift-lintercollection (viasrc/linter/schema-diagnostics.ts→mergeServerIssues) and the newerdrift-advisorcollection (viasrc/diagnostics/providers/schema-provider.tscallingcheckAnomalies+checkMissingIndexes). Users saw two Problems-panel entries per issue with different owners, different line numbers for anomalies (class header vs column getter), and — for index suggestions — different codes (index-suggestionvsmissing-fk-index/missing-id-index). The entire legacy pipeline has been retired:src/linter/schema-diagnostics.ts,src/linter/issue-mapper.ts, thedrift-linterdiagnostic collection, theSchemaDiagnosticsclass, and theDriftCodeActionProviderare all deleted. The newDiagnosticManagerpipeline is now the single source of these diagnostics: anomaly warnings land on the column-getter line (with a class-header fallback when the column can't be resolved), index suggestions land on the column line, and theCopy CREATE INDEX SQLquick-fix that previously lived on the legacy provider is already wired onSchemaProvider.provideCodeActionskeyed on the new codes. ThedriftViewer.runLintercommand, the VM-disconnect diagnostic clear, and all activation-time refreshes now dispatch toDiagnosticManagerdirectly. Reported in plans/history/2026.04/2026.04.22/BUG_anomaly_false_positive_tight_timestamp_range.md (Bug 2 — duplicate emission)
Maintenance
error_logger.dart:// ignore: avoid_printdirectives now carry rationales — the analyzer'sdocument_ignoresrule was flagging three bare// ignore: avoid_printlines inlib/src/error_logger.dart(lines 68, 116, 119) as info-level diagnostics. Each directive now appends-- intentional console output so logs/errors/stack traces are visible without DevTools, so future readers see whyprintis deliberate here (structureddeveloper.logalone is invisible in the standard Flutter console)- Legacy
linter/module deleted —extension/src/linter/schema-diagnostics.ts,extension/src/linter/issue-mapper.ts, and their test files have been removed.SchemaDiagnosticsandDriftCodeActionProviderare gone;ProviderSetupResult.linteris gone;IDebugCommandDeps.linteris nowdiagnosticManager: DiagnosticManager;registerNavCommandstakesDiagnosticManagerinstead. Callers that previously invokedlinter.refresh()/linter.clear()now dispatch toDiagnosticManager, which was already being called next to every legacy-linter call site. Disposable count inextension.test.tsupdated from 199 → 197 (thedrift-linterDiagnosticCollection and itsDriftCodeActionProviderregistration are the two that went away; the unifieddrift-advisorcollection still lives and is owned byDiagnosticManager).CommandRegistrationDeps.diagnosticManageris aPartial<DiagnosticSetupResult>so thesetupDiagnostics-throws resilience test still passes: when diagnostics failed, command handlers see a no-op fallback (refresh → resolved promise,clear → noop) rather than crashing
3.3.5 #
Sidebar tables list is easier to read at a glance, clicking a history entry actually takes you to the Run SQL tab, the theme picker is no longer see-through, and the three always-on tools now live as toolbar icons above the tab bar instead of fighting for space with your open tabs. log
Fixed #
- Sidebar tables: name vs count readability — in the sidebar's Tables list, the grey row count had been rendering with more visual weight than the table name itself, making the name hard to pick out at a glance. The two colors are now swapped so the table name wins the eye and the count recedes
- Sidebar tables: unpin icon hidden until hover — the faint pin/unpin button sat visible on every unpinned row at rest, adding a column of low-level noise down the sidebar. It is now hidden on unpinned rows and only appears when you hover the row (or focus it via keyboard). Pinned rows keep the icon visible so the pinned state is still obvious, and touch devices still see it since hover isn't available there
- History sidebar: clicking an entry now opens the Run SQL tab — previously, clicking a query in the History sidebar populated the hidden
#sql-inputeditor but left you on whatever tab you were on (Tables, Schema, etc.), so the click looked like it did nothing. The handler now switches to the Run SQL tab first, then drops focus into the editor, so the loaded query is visible immediately and ready to edit / re-run - History sidebar: second collapse control removed — the history heading had a down-chevron that toggled the inner list independently of the sidebar itself, creating two ways to “collapse history” that didn’t agree with each other. The chevron is gone; the right-hand toolbar icon (
⇥) is now the only collapse affordance, mirroring how the tables sidebar already works - Theme menu: flyout no longer reads as “a menu under another menu” — on Showcase and Midnight the theme dropdown was at 15% opacity, so the toolbar icons behind it bled right through and the whole thing looked like two stacked menus. The flyout is now opaque (92% alpha on the tinted themes) and its
z-indexhas been raised above the tab-panel chrome so it can’t be clipped by panels that establish their own stacking context - Theme menu: double-fire on selection removed —
.tb-theme-optionclicks had two listeners attached (one frominitThemeListeners, one frominitToolbar). Both applied the theme, but only the toolbar one closed the flyout, so the submenu looked “locked” after the first click. Theme-option wiring now lives only ininitToolbar;initThemeListenersonly watches the OSprefers-color-schemechange - Toolbar icons: middle-aligned in the toolbar row — 2 rem icon buttons were top-aligned against the 2.75 rem tab row because the flex container used
align-items: stretchand mixed-height children default to flex-start when stretch can’t apply. The new#toolbar-barsetsalign-items: centerand.tb-icon-btnpinsalign-self: centeras a belt-and-braces guard
Changed #
- Toolbar split: Tables / Search / Run SQL are now toolbar icons, not fixed tabs — the three “always-present” tabs used to share the tab row with the rest of the toolbar icons, which meant that opening several table tabs pushed the tools around and the permanent tabs took a lot of horizontal space for labels. Those three are now icon-only launchers in a dedicated top row (
#toolbar-bar), alongside every other tool. The tab row (#tab-bar) below it holds only the tabs you have actually opened. On first load the Tables tab is auto-opened so you still land on the familiar browse view; closing it leaves the Tables panel visible but with no pinned tab, and clicking the Tables icon again re-creates a closeable tab - Run SQL: Run button moved beneath the editor — the primary Run button used to live in the template toolbar above the textarea, visually detached from the query body it executes. It now sits on its own row directly below the editor so it's the natural next action after typing
- Run SQL: icons added to every toolbar button — Apply template, Save, Del, Export, Import, Ask in English…, and Run now carry Material Symbols icons (post_add, bookmark_add, delete, download, upload, smart_toy, play_arrow) matching the conventions used elsewhere in the viewer's toolbars
- Run SQL: empty dropdowns are dimmed — when a dropdown is still on its placeholder entry (“— Saved queries —”, “— Recent —”, “—” for Table / Fields), it now renders at 55% opacity so the eye skips over unused controls and lands on filled ones. The dim lifts automatically the moment you pick a real value
- Run SQL: inline “Recent” dropdown replaced with a history icon button — the old
History:/Recent:label +<select>looked like a form input waiting for a value, and the em-dash placeholder read as empty. It also duplicated what the right-hand History sidebar already shows (with more detail: full SQL, duration, rows, timestamp, source badge), which after the previous fix even opens the Run SQL tab on click. The inline dropdown is gone; in its place is a single icon button (Materialhistoryglyph) that toggles the History sidebar open/closed — same behavior as the toolbar-level history toggle, so both controls stay in sync
3.3.4 #
No more spurious "14 query regression(s) detected" warnings at the end of every debug session — the extension's own diagnostic probes are no longer mistaken for your app's slow queries. log
Fixed #
- Perf-regression false positives from the extension's own diagnostic probes — every debug session ended with a warning of the shape "Drift: 14 query regression(s) detected: SELECT SUM(CASE WHEN "id" IS NULL THEN …): 55ms vs baseline 6ms (9.17x)" even when the app's own queries were unchanged. The SQL was not written by the user at all — it was the extension's own null-count scan from
DataQualityProvider,scoreNullDensityin health metrics, and the column profiler, running over tables whose row counts differed from the prior session. The regression detector was comparing these probes against baselines it had captured from itself on a prior run, producing one false warning per probed table per session. Thesql()client now accepts{ internal: true }and plumbs it through POST/api/sql(and the VM-servicerunSqlRPC) so the server tags those timings asisInternal: true;detectRegressionsskips internal entries in both the compare pass and the baseline-recording pass so internal probes neither fire false warnings nor poison future baselines. RaisingdriftViewer.perfRegression.thresholdno longer required as a workaround
Maintenance
- Publish script: Marketplace propagation failure now points to the publisher page — when the final Step 16 store-propagation check times out for the VS Code Marketplace, the warning now includes the publisher management URL (
marketplace.visualstudio.com/manage/publishers/Saropa), the public listing URL, and the absolute path to the packaged.vsixso the user can upload it manually in one click instead of hunting for the file. Open VSX and pub.dev timeouts also emit store-specific guidance. Implemented inscripts/modules/store_propagation.py(per-storependingset) andscripts/modules/ext_publish.py(passesvsix_paththrough); newMARKETPLACE_PUBLISHER_URLconstant added inscripts/modules/constants.py - Lint cleanup:
prefer_return_await+depend_on_referenced_packages— removed redundantFuture<T>.value(...)wrappers in twoasyncbranches ofvm_service_bridge.dart(the async function already wraps the return value, so the explicit wrapper both added noise and tripped the lint); converted four self-referentialpackage:saropa_drift_advisor/...imports insidelib/to relative paths indrift_debug_server_io.dart,server/import_handler.dart,server/router.dart, andserver/session_handler.dart(a package cannot list itself in its own pubspec dependencies, so the self-import trippeddepend_on_referenced_packages) - Lint cleanup:
avoid_null_assertionon regex group access inserver_context.dart— replacedmatch.group(1)!/match.group(2)!in_parseCallerFramewith?? ''fallbacks, and gated the file check onfile.isEmpty. The regex literal guarantees both groups are non-null on a successful match today, so behavior is unchanged; the fallback removes a silent crash site if the pattern is ever edited. Related upstream bug filed againstsaropa_lints(avoid_null_assertion_false_positive_regex_match_group.md) — the rule should recognizeRegExpMatch.group(N)!as a safe pattern.
3.3.3 #
Removed the noisy "Drift server not reachable" diagnostic that stuck around whenever your Flutter app wasn't actively running in debug mode — connection state lives in the tree view and panel now, not in your Problems list. log
Removed #
- "Drift server not reachable" diagnostic — the proactive connection-health check fired whenever your Flutter app wasn't running in debug mode (i.e. most of the time), producing a permanent, low-value Information diagnostic that couldn't be distinguished from real issues. The tree view and panel already reflect live connection state, so the editor diagnostic was noise. Connection state is now surfaced only through the tree view / panel.
Maintenance
- Publish script: vsce login limited to 3 attempts — when the Marketplace credential store is unavailable, the script now prompts for the PAT up to 3 times and passes it non-interactively, instead of letting
vsce loginre-prompt indefinitely - Removed connection-error diagnostic path — deleted
connection-checker.ts, theconnection-errorcode, the'connection-error'event type,RuntimeEventStore.hasRecentConnectionError,RuntimeProvider.recordConnectionError, and the connection-error Quick Fix actions (Retry Connection / Don't Show / Open Settings). Tests updated.
3.3.2 #
The extension sidebar and "Get Started" welcome screen no longer show up in Flutter/Dart projects that don't actually use Drift. log
Changed #
- VS Code minimum version bumped to 1.115.0 — aligns
engines.vscodewith the@types/vscodetypings to fix.vsixpackaging errors
Fixed #
- Extension sidebar no longer appears in non-Drift projects — the Database Explorer, Drift Tools, and activity bar icon are now hidden in workspaces that don't declare
driftorsaropa_drift_advisorin pubspec.yaml. Previously, the "Get Started" welcome screen appeared in every Flutter/Dart project regardless of whether it used Drift.
3.3.1 #
Added a real security policy so vulnerabilities can be reported privately through GitHub Security Advisories. log
Maintenance
- **SECURITY.md** — replaced GitHub default template with a real security policy: private reporting via GitHub Security Advisories, response timeline commitments, scope definition, and coordinated disclosure terms3.3.0 #
Brand-new Settings panel for persistent preferences, a right-side History sidebar showing every query the server has run, and every tool launcher is now a visible icon in the tab bar instead of buried in a hamburger menu — plus Showcase and Midnight finally got the glassmorphism overhaul they were always supposed to have. log
Added #
- Settings panel — new Settings tool tab (accessible from the hamburger menu gear icon) lets users configure persistent preferences: SQL history max entries, max saved analyses, default page size, default display format, show-only-matching-rows toggle, slow query threshold, auto-refresh polling, epoch timestamp auto-detection, and navigate-away confirmation; all preferences persist to localStorage and take effect immediately without a page reload; includes "Clear all stored data" (removes project-specific data while keeping theme/sidebar preferences) and "Reset all to defaults" actions
- Binary size disclosure in README — added a paragraph in "How it works" clarifying that this package adds zero bytes to release builds when gated on
kDebugMode, has zero runtime dependencies, and never compiles web UI assets into the binary - History sidebar — new collapsible right-side sidebar shows all SQL query execution history from the server's ring buffer; each entry displays a source badge (Browser / App / Internal), truncated SQL preview, duration, row count, and relative timestamp; filter buttons let you toggle between All, Browser, App, and Internal queries; clicking an entry loads its SQL into the SQL runner input; dedicated
GET /api/historyandDELETE /api/historyendpoints power the sidebar with the full timing buffer (up to 500 entries) and a computedsourcefield derived from caller stack-frame analysis - Inline toolbar replaces hamburger menu — all tool launchers (Snapshot, DB diff, Index, Schema, Diagram, Size, Perf, Health, Import, Export, Settings) are now visible as icon buttons in the tab bar row instead of hidden behind a dropdown; sidebar toggles sit at the edges (left for Tables, right for History); Mask, Theme (flyout picker), and Share are right-aligned; active tool tabs are highlighted on their toolbar icon
- Collapsible results table — the data table and status bar are now wrapped in a
▲ Resultsexpander (matching the existing Table definition and Query builder toggles) so users can collapse the grid and focus on the query builder or definition; heading shows the current row count for context when collapsed - Visual / Raw SQL toggle in query builder — a pill-style toggle above the query builder switches between the existing form controls (Visual) and a free-text SQL textarea (Raw SQL); switching to Raw pre-fills the textarea with the current visual builder query so the user can refine it; both modes share the same Run / Reset buttons and inline results
- Inline cell edit context and validation — double-click cell editing now shows a context bar (PK identity, column name, type, nullable) and the original value above the input; client-side format validation checks number, integer, and boolean formats on each keystroke with a red-border + inline error message instead of
alert()dialogs; validation errors keep the editor open so the user can fix and retry - Double-click tab to close others — double-clicking any tab in the tab bar prompts to close all other closeable tabs, making it quick to declutter when many tables or tools are open
- Tab icons and per-type accent colors — every tab type now shows a unique Material Symbols icon (e.g. table_chart for Tables, search for Search, terminal for Run SQL, etc.); on the Midnight and Showcase themes, each tab type also gets a unique accent color for the top border and text when active, replacing the single link color so tabs are visually distinct at a glance
Improved #
- Showcase and Midnight glassmorphism overhaul — the tab bar, data table, SQL editor, and sticky table headers now use translucent frosted-glass surfaces with
backdrop-filter, so the animated body gradient (pastel aurora for Showcase, deep aurora for Midnight) is visible through every major UI surface instead of being hidden behind opaque backgrounds; Midnight's CSS variables (--surface,--header-bg,--sidebar-bg,--bg-pre) changed from opaque hex to translucent rgba so all elements automatically participate in the aurora bleed-through; tab bar gets a slide-in entrance animation matching the header; pinned columns and sticky headers use heavier frost for readability; scattered data-table glassmorphism overrides consolidated into the per-theme SCSS partials
Changed #
- Hamburger menu — Themes submenu — replaced the single-click theme cycle button with a full submenu listing all four themes (Light, Showcase, Dark, Midnight) with a checkmark on the active selection
- Hamburger menu — sliding toggle switches — Sidebar visibility and PII Mask now use sliding boolean switches instead of text-swapping buttons and checkboxes
- Hamburger menu — layout polish — section headings use a smaller font with tighter bottom padding; a divider separates Mask from Share for clearer visual grouping
Maintenance
- Upgraded
saropa_lintsfrom^11.1.0to^12.0.1;dart_style,analyzer, and related packages remain pinned below their latest versions becauseanalyzer ^12.0.0conflicts with the Flutter SDK'smetaconstraint - Pre-commit Dart format gate — added
dart format --set-exit-if-changed .to the Husky pre-commit hook so formatting issues are caught locally before they reach CI; mirrors the GitHub Actions format check step
3.2.2 #
New setting lets you suppress specific diagnostic rules on specific tables, and several false-positive anomaly / slow-query warnings on bounded rating columns and internal probes are gone. log
Added #
- Per-table diagnostic suppression — new
driftViewer.diagnostics.tableExclusionssetting lets users suppress specific diagnostic rules on specific tables while keeping those rules active elsewhere; for example, suppressno-foreign-keyson tables that deliberately use UUID soft references without disabling the rule project-wide
Fixed #
- Slow-query false positives from extension-internal probes — the extension's own change-detection
COUNT(*)queries (used to fingerprint table row counts) were recorded in the performance timeline and reported as user-application slow-query warnings; these internal probes are now tagged withisInternaland excluded from slow-query diagnostics, aggregate stats, and query patterns so only genuine application queries trigger warnings - False-positive anomaly on bounded ratings — outlier detection no longer flags values at the boundary of known bounded scales (0–5, 0–10, 1–10, 0–100). A TV rating of 1.0 on a 1–10 scale is rare but valid, not a data anomaly
- Rating/score/percent column skip — columns matching
rating,score,percent, orpctare now excluded from sigma-based outlier detection, since bounded-scale data is inherently non-Gaussian
3.2.0 #
All ten toolbar buttons and the floating action button are now a single hamburger menu, the SQL editor auto-runs EXPLAIN as you type and shows an index report, and every theme got a beautification pass with consistent tokens, frosted tables, and fewer invisible borders. log
Added #
- Bug report guide — added
bugs/BUG_REPORT_GUIDE.mdwith a comprehensive template and checklist for filing useful bug reports - Project name in masthead pill — "Saropa Drift Advisor" now appears between the logo and version badge, making the product identifiable at a glance
- Template lock toggle — lock icon in the Run SQL toolbar; when locked (default), changing table or field selections auto-applies the current template
- Auto-explain with index report — the SQL editor now automatically analyzes query plans as you type (1.2 s debounce), showing estimated cost, which indexes are used vs available, and flagging full-scan tables with no indexes
Changed #
- Hamburger menu replaces toolbar and FAB — the 10-button toolbar row and the floating action button are consolidated into a single hamburger menu (☰) at the left edge of the tab bar; tools are grouped by purpose (Snapshots & Comparison, Performance Analysis, Schema Tools, Import/Export) with labeled sections; app-wide settings (sidebar toggle, theme cycle, PII mask, share) sit below a heavy divider; reclaims an entire row of vertical space and eliminates the FAB overlay
Fixed #
- Theme contract tests fail in CLI but pass in IDE —
extractBlocktest helper matched compound selectors likebody.theme-dark ::-webkit-scrollbar-thumbbefore the real variable-defining block; now skips blocks that don't contain CSS custom properties - Publish pipeline aborts on test failure with no recovery — extension and Dart test steps now prompt skip/abort on failure (matching the existing lint step pattern) so a known failure doesn't force a full pipeline restart
- Publish pipeline prompt defaults — target selection defaults to option 1 on Enter; "Continue with uncommitted changes?" defaults to Y
- Publish pipeline git operations hard-abort without asking — every git failure (add, commit, push, tag) now prompts skip/abort instead of silently ending the script; "nothing to commit" is auto-recovered as success
- Outlier false positive on external ID columns — numeric outlier detection now skips identifier columns (
*_id,*Id,*_key,*Key,*_code,*Code) and primary key columns, since external IDs are opaque identifiers not drawn from a normal distribution; also adds a minimum sample size guard (n < 30) to prevent unreliable sigma estimates from flagging small datasets - Empty-string false positive on columns with empty-string default — the anomaly detector no longer flags empty strings when the column's schema declares
withDefault(const Constant('')), since those values are the designed "no value" sentinel, not data quality problems - PII mask toggle now works and gives visible feedback — toggling the MASK checkbox immediately re-renders tables and search results without a page refresh; a bright "MASKED" badge appears in the masthead pill so the user always knows when masking is active
- Expanded PII column detection — the mask heuristic now recognizes many more column names as sensitive:
name,first_name,last_name,username,salary,credit_card,ip,dob,passport,license,city,zip,latitude/longitude, and dozens more; previously only 9 patterns were checked; short words liketelandnameuse word-boundary matching to avoid false positives onhotelorfilename
Improved #
- Unified table grid styling across all panels — Search, Run SQL, and Query Builder now share the same table formatting as the Tables panel (borders, alternating rows, hover highlight, copy-on-hover, column context menu, drag-to-reorder, double-click cell popup)
- Theme beautification pass — all four themes overhauled for contrast, visibility, and visual identity:
- Light: opaque borders (
#c2cde0) replace invisible rgba hairlines;--muteddarkened to#556685for WCAG AA; card shadows strengthened for visible depth - Dark: borders lightened to
#4a4d52for visibility against dark backgrounds - Showcase: gradient stops changed from near-white to saturated pastels (lavender, pink, peach, sky) so frosted-glass surfaces actually show the moving gradient behind them; surface opacity lowered and blur strengthened; white frost-edge borders; frosted tab panels and data tables
- Midnight: aurora gradient widened from monochrome navy to indigo/teal/purple shifts; primary orb raised from 8% to 18% opacity; second warm-purple orb added; surface opacity lowered so aurora bleeds through; expanded card periwinkle glow halo now visible; input focus glow ring added; frosted tab panels and data tables
- All themes: entrance animations strengthened (12px translate); per-file hardcoded rgba border overrides replaced with
var(--border)tokens
- Light: opaque borders (
- Global UI polish — systematic beautification across all partials:
- Spacing tokens (
--space-1through--space-12): 4px geometric scale added to:root; migrated into tab panels, query builder, and pagination - Global form controls: centralized input/select/textarea styling in
_base.scsswith consistent border-radius, padding, and theme-aware focus rings (--focus-ring-colorper theme); removed duplicated focus ring rules from_search.scssand_sql-editor.scss - Custom scrollbars: thin, theme-tinted scrollbars for Firefox (scrollbar-width/color) and Chromium (::-webkit-scrollbar) across all themes
- Text selection: theme-aware
::selectioncolor matching each theme's accent - Tab bar: active tab gets 2px colored top accent bar and bold weight; close button visible at rest (opacity 0.4) instead of hidden
- Buttons: secondary buttons get subtle shadow for depth;
.btn-dangeruses--radius-mdtoken (was hardcoded 4px) with hover glow; toolbar buttons lift on hover (translateY(-1px)) - Sidebar: pin button visible at rest (opacity 0.3) instead of invisible
- Masthead: status button gets subtle pill background so it reads as interactive
- Data table: header row gets 2px bottom border for clear separation; scroll container gets stronger shadow and per-theme frosted glass treatment
- Pagination: "Advanced" toggle gets visible border/background (was invisible text)
- Query builder: hardcoded
border-radius: 3px/4pxreplaced with--radius-smtoken; spacing uses--space-*tokens
- Spacing tokens (
Changed #
- Removed project logo from tab bar — the small icon next to the Tables tab has been removed; the logo remains in the masthead pill
- Dimmed version number in masthead — the version badge is now muted grey, keeping it readable but visually secondary to the project name
- Run SQL panel always visible — the collapsible header has been removed; the SQL runner is now always expanded inside its tab
- Smart field substitution in templates — all templates (except COUNT) now substitute selected fields for
*, not just the "SELECT columns" template - Explain button removed — replaced by automatic query plan analysis; the separate Explain button is no longer needed
Maintenance
- Modularized
tools.ts(850 lines) into 3 files —tools-compare.ts(snapshot, compare, migration preview),tools-analytics.ts(index suggestions, size analytics, anomaly detection), andtools-import.ts(CSV/JSON/TSV import); each file has its own imports and no shared private state - Modularized
_theme-effects.scss(482 lines) into 3 files —_theme-showcase.scss(showcase glassmorphism effects),_theme-midnight.scss(midnight aurora/glow effects), and a slim_theme-effects.scss(shared entrance animations + reduced-motion override)
3.1.1 #
Killed 40+ false-positive "add a datetime index" suggestions that fired on every created_at and updated_at column regardless of whether it was actually being queried. log
Fixed #
- Eliminated 40+ false-positive datetime index suggestions — the blanket heuristic that flagged every
created_at,updated_at, and_atcolumn as needing an index has been removed (96% false-positive rate in real projects); legitimate datetime index suggestions are still caught by the evidence-basedunindexed-where-clausediagnostic
3.1.0 #
Save and compare snapshots for Index Suggestions, Size Analytics, Anomaly Detection, and Health Score — plus fewer noisy diagnostics in multi-root and non-Drift workspaces. log
Fixed #
- Connection warning no longer targets wrong folder in multi-root workspaces — in workspaces with several root folders, the "Drift server not reachable" diagnostic attached to whichever folder happened to be first, even non-Drift projects; now scans folders and only targets one that actually uses Drift
- Consistent
[drift_advisor]prefix on all diagnostics — index-suggestion and invariant-violation diagnostics from the legacy linter paths were missing the[drift_advisor]message prefix; all diagnostic messages now include it for consistent filtering in the Problems panel - Boolean columns no longer flagged as datetime index candidates — the index-suggestion heuristic matched any column name ending in
time, causingBoolColumnfields likeis_free_timeto produce a spurious "Date/time column" diagnostic; the pattern now requirestimestampinstead of baretime - No more "no longer responding" toasts in non-Drift projects — server discovery port scanning now only starts when the workspace pubspec.yaml declares a Drift dependency; previously every VS Code workspace triggered scanning and stale server-lost notifications
Added #
- Save & compare analysis history — Index Suggestions, Size Analytics, Anomaly Detection, and Health Score panels now have Save Snapshot and Compare buttons; snapshots are persisted in workspace state (up to 50 per type) and can be compared side-by-side with a diff summary showing what changed between runs
Changed #
- Connection diagnostic downgraded from Warning to Information — "server not reachable" is the normal state when the debug server isn't running; the diagnostic now shows as an info icon instead of a yellow triangle, reducing noise in the Problems panel
3.0.3 #
Schema tab no longer gets stuck on "Loading…", "Ask in English" stops crashing on open, and the DB Diff tab shows a proper setup guide instead of raw developer-facing errors. log
Fixed #
- Schema tab stuck on "Loading…" — when schema DDL was already cached from another view (table data in "both" scope, search tab), the Schema tab never rendered the cached content; now uses cache-first rendering so the tab displays immediately
- "Ask in English" crashes with
loadSchemaMeta is not defined— the NL modal, table-view column-type loader, and cell-edit module all calledloadSchemaMetaat runtime but the function was scoped insideapp.jsand never reachable from the bundled TS modules; extracted into a sharedschema-meta.tsmodule with proper imports
Improved #
- DB Diff tab shows setup guide instead of error jargon — when the comparison database is not configured, the panel now explains what the feature does and shows a collapsible "How to enable" section with a code example; buttons are hidden until the feature is active, instead of showing developer-facing error messages after clicking
- Quieter debug console for stale tables — when a table is listed in
sqlite_masterbut has been dropped since the last metadata fetch, the server now logs a one-line warning instead of a full stack trace; snapshot capture skips failed tables instead of aborting
Maintenance
- README screenshots — added 10 feature screenshots (Tables, Table Data, Schema, Index, Size, Perf, Health, Import, Ask in English, Light Mode) in an HTML grid with captions; renamed files from random hashes to descriptive names; added Screenshots link to TOC
3.0.2 #
Stale tables no longer carry over when you switch Flutter projects, and empty databases stop flagging every Dart table class as a "missing table" error. log
Fixed #
- Stale tables persist after project switch — switching Flutter projects reloaded the webview HTML but localStorage kept pinned tables, nav history, table state, SQL history, bookmarks, and analysis results from the previous project; now detects when the server origin changes and purges all project-specific storage while preserving user preferences (theme, sidebar state)
- False-positive "missing table" errors on empty database — when the database had no tables (app never run, or server connected to an empty DB), every Dart table class was flagged with an Error-level
missing-table-in-dbdiagnostic; now detects the empty-DB condition and suppresses individual missing-table errors while still flagging genuinely missing tables in partially populated databases
Maintenance
- File modularization — split 3 files exceeding 300-line limit: dashboard chart-clipboard logic, ER diagram SVG helpers, and panel test fixtures each extracted into dedicated modules
- Final IIFE extraction — moved last 4 inline init blocks (
initPiiMaskToggle,initSearchToggle,setupCellValuePopupButtons,setupChartResize) into their feature modules; removed 70 unused imports;app.jsreduced to 926-line init-only glue - Test coverage — added tests verifying extracted helpers compose correctly into webview script output
- Test coverage — 22 contract tests for server-origin storage clearing: state constant, persistence function wiring, key targeting, UI-preference preservation, call ordering in app.js, and bundle integration
3.0.0 #
Fixed stale data after switching servers, restored broken heartbeat and polling controls, and added Log Capture session export so Drift Advisor diagnostics flow into your capture sessions automatically. log
Fixed #
- Wrong project tables after server switch — webview panel showed stale tables from the previous project when the debug server changed; now detects host/port changes and fully reloads content from the new server
- Retry targeted wrong server — the Retry button in the webview used the original server endpoint instead of the current one after a server switch; now always uses the panel's current host/port
- Heartbeat reconnection stopped working — heartbeat reconnection silently dropped back to no-op stubs instead of resuming polling; now wired correctly at startup
- Polling toggle missing — the masthead pill click handler and keep-alive toggle stopped responding; restored
Added #
- Log Capture session export — when both extensions are installed and
driftViewer.integrations.includeInLogCaptureSessionisfull(the default), session end now writes structured metadata (query stats, anomalies, schema summary, health, diagnostic issues) into the Log Capture session and a{session}.drift-advisor.jsonsidecar file; set toheaderfor lightweight headers only, ornoneto opt out entirely - Log Capture extension API —
getSessionSnapshot()is now available oncontext.exportsso Log Capture's built-in provider can request a snapshot directly without the file fallback - Session file fallback —
.saropa/drift-advisor-session.jsonis written at session end for tools and scenarios where the extension API is unavailable
Maintenance
- esbuild bundling — all web JS/TS assets bundled into a single
bundle.jsvia esbuild; Dart server plumbing collapsed from 4 cached fields / 4 script tags to 1 - Full JS modularization —
app.jsdecomposed from 6882-line monolith to 915-line init glue; 23 TypeScript modules extracted; shared state centralized instate.tswith typed exports - SCSS modularization —
style.scssdecomposed from 2184 lines to 28-line import hub with 17 feature partials; migrated from deprecated@importto@use - Connection diagnostic logging — all connection state transitions, poll cycles, heartbeat, and keep-alive events now emit
[SDA]prefixed console.log entries for browser dev tools tracing
2.19.0 #
Type badges on columns, random data sampling, health scores, query cost analysis, and a pile of UI polish. log
Added #
- Column type icons (Website) — data table column headers now show a compact type badge (e.g. TEXT, INT, REAL, BLOB) sourced from schema metadata; full type in tooltip
- Table definition type icons (Website) — table definition panel now shows a fixed-width icon column with type glyphs (
#integer,Ttext,.#real, etc.) plus 🔑 PK and 🔗 FK badges for quick visual scanning - Data sampling (Website) — Sample button in the pagination bar loads a random sample of rows via
ORDER BY RANDOM() LIMIT N - Health score (Website) — anomaly scan results now show a 0–100 health score with letter grade (A–F) and a severity breakdown summary
- Query cost analysis (Website) — EXPLAIN output now shows an estimated cost rating (Low/Medium/High) with operation counts (full scans, index lookups, subqueries, sorts, temp storage) and a collapsible raw plan detail view
Fixed #
- App logo not appearing (Website) — replaced corrupted inlined base64 PNG (~185 lines) with a CDN-hosted URL using the same jsDelivr +
@mainfallback pattern as CSS/JS assets
Changed #
-
Query history expanded (Website) — SQL history limit increased from 20 to 200 entries, matching the VS Code extension
-
Collapsible table definition (Website) — table definition panel above the data grid is now collapsible (collapsed by default), matching the query builder pattern; self-contained in
table-def-toggle.js -
Masthead pill (Website) — combined the version badge and connection status into a single header pill showing logo · version · Online/Offline; styles extracted to
_masthead.scsspartial, HTML extracted to_buildMastheadPill()method -
Connection status terminology (Website) — renamed "Live" to "Online" throughout the web viewer for clarity
-
Sidebar toggle arrow (Website) — arrow is now larger, right-aligned, and points left instead of down for clearer collapse affordance
-
FAB opens upward (Website) — floating action button menu now fans upward from the trigger, with items right-aligned against the trigger edge
-
Share moved to FAB (Website) — Share button relocated from the header bar into the FAB menu as the first action item
-
FAB modularized (Website) — FAB styles extracted to
_fab.scsspartial, FAB UI logic extracted to self-containedfab.jsmodule -
Premium theme effects (Website) — Showcase and Midnight themes now have real glassmorphism (backdrop-filter blur on header, sidebar, cards), animated gradient backgrounds, rainbow shimmer borders on expanded cards, floating glow orb (Midnight), entrance animations, and gradient buttons; removed broken CDN dependency on nonexistent drift-enhanced.css; all four themes are always available without external network requests
-
Monospace font upgrade (Website) — switched to JetBrains Mono via Google Fonts CDN; centralized font stack into a single
--font-monoCSS custom property for easy future changes -
Responsive toolbar (Website) — tools toolbar no longer wraps to a second row; text labels progressively hide at three breakpoints (1100px, 900px, 700px) leaving icon-only buttons with tooltips at narrow widths
Added #
- Column visibility toggle (Extension) — SQL Notebook results now have a "Columns" button to show/hide individual columns, with a dropdown chooser and "Show All" reset
- Row filter toggle (Extension) — SQL Notebook filter bar now has a "Matching/All" toggle to switch between showing only matching rows and showing all rows
- Responsive ER diagram (Extension) — ER diagram automatically re-fits to the panel when the window is resized, debounced to avoid flicker
- Export index analysis (Extension) — Index Suggestions panel has a new "Export Analysis" button that exports as JSON, CSV, or Markdown to clipboard or file
- Copy chart to clipboard (Extension) — Dashboard chart widgets now have a clipboard button in the header that copies the chart as a PNG image
- JSON export (Website) — Export panel now offers "Table JSON" alongside the existing CSV download
- Import history log (Website) — Import panel tracks all import operations during the session in a collapsible history list showing time, table, format, row count, and errors
Fixed #
- Acronym column name mismatch detection — When Drift's camelCase-to-snake_case splits acronyms like
UUIDintou_u_i_d, but the database usesuuid, the advisor now reports a singlecolumn-name-acronym-mismatchdiagnostic instead of a confusingmissing-column-in-db/extra-column-in-dbpair. The message explains the root cause and suggests both fix options (rename getter or.named()override) - Anomaly detector: reduced false positives — Numeric outlier detection now skips timestamp columns (
created_at,*_date, etc.), sort/ordering columns (sort_order,position,rank, etc.), and year/founded columns. Added a log-scale fallback so distributions spanning orders of magnitude (e.g., currency exchange rates, engagement scores) are no longer flagged. Outlier messages now identify which end (min/max) is the problem and by how many σ - Slow-query and N+1 false positives on table definitions — Runtime performance diagnostics (
slow-query-pattern,n-plus-one) moved from theperformancecategory toruntimeso users can disable them independently of schema checks. Server-internal queries (no caller location) are now downgraded from Warning to Information severity. When caller location is available, diagnostics pin to the call site at full Warning severity. Slow-query messages include row count; N+1 messages hint at batching via JOIN/IN for high repeat counts
2.17.5 #
Super FAB menu, app logo in the tab bar, and premium theme effects that actually look dramatic now. log
Added #
- Super FAB menu — Sidebar toggle, theme cycle, and PII mask moved from the header into a floating action button in the bottom-right corner. Click the gear icon to expand; click outside or press Escape to dismiss
- App logo in tab bar — Replaced the "Saropa Drift Adviser" text header with the app logo, positioned inline with the tab buttons
Fixed #
- Showcase/Midnight themes now show dramatic visual effects — The premium themes had nearly-opaque backgrounds (75-85% alpha) that made glassmorphism invisible. Completely rewritten with floating ambient orbs, glass shimmer sweeps, card entrance animations with blur-to-clear, rainbow borders visible at rest, dramatic hover lifts, animated gradient buttons, and backgrounds at 25-35% alpha so the frosted glass effect is unmistakable
- Sticky header preserved in premium themes — The enhanced CSS was overriding
position: stickywithposition: relativeon the header, causing it to scroll away instead of staying fixed
2.17.4 #
Fixed the changelog — 2.17.2 had accidentally overwritten the 2.17.1 entry. Both versions are now listed correctly below. log
Maintenance
- Publish pipeline: store propagation polling — After publishing, the pipeline now polls pub.dev, VS Code Marketplace, and/or Open VSX APIs until the new version is visible (30 s interval, 10 min max). Timeout is non-fatal
For older versions (2.17.3 and prior), see CHANGELOG_ARCHIVE.md.
