#Shared-code migration: Netezza validation boundary
The preparation stage established the boundaries and the migration now has a
platform-neutral @justybase/sql-core entrypoint. The Netezza lexer, grammar,
parser runtime, semantic validator, authoring helpers and quality rules are
owned by sql-core. The VS Code adapters compose metadata, transport, and
stateful cache lifecycles around that backend. The Web Editor/API described in
the historical migration record was retired on 2026-09-26; shared package
boundaries remain active because VS Code and companion extensions consume
them and benefit from platform-neutral implementations.
References below to the former API, browser client, or their test suites record
the migration context at that time; they are not current products or gates.
Target ownership is defined in Architecture; test selection
and lifecycle requirements remain governed by Testing strategy.
#Reproducing the baseline
The repository-wide checker and its edge/cycle baseline existed before this
preparation. Keep changes to scripts/architecture-check.mjs and
quality/architecture-rules.json reviewable independently of later code moves.
Do not regenerate exceptions to make a migration pass.
Run npm run check:architecture, npm run test:quality-tools, and
npm run architecture:report --silent. The JSON report contains all production
files, exact resolved edges with import forms/locations, layer-to-layer counts,
strongly connected components with edge fingerprints, and the configured debt
entries with owners and removal conditions. Redirect it to a temporary artifact
when comparing revisions; do not commit volatile graph/timing reports.
| Current consumer | Current dependencies and debt |
|---|---|
src |
contracts/shared packages and desktop modules |
media |
shared packages, desktop protocol/types and media modules |
packages/contracts |
its own public types/helpers; existing type cycle is fingerprinted |
packages/sql-core |
Platform-neutral Netezza lexer/parser, semantic validation, authoring and quality rules |
Other packages |
contracts and shared helpers; designer-core is pure, database-runtime owns shared execution plus compatibility exports, and sqlite/duckdb/netezza-runtime/access-file own Node I/O |
extensions |
own modules, contracts/shared helpers and public core activation API |
#Runtime extraction in R2 (closed 2026-09-08)
The three database-specific Node runtimes now have explicit ownership. At R2 closure the retired Web/API adapters also used these runtimes; those API references below describe the former product, not a current consumer.
@justybase/sqlite-runtimeowns the Nodenode:sqlitesession and is used by both the API adapter and the desktop SQLite connection facade.@justybase/duckdb-runtimeowns the structural DuckDB module resolver, instance ownership, catalog serialization, bounded result streaming and cancellation. The API supplies its sandbox resolver; the DuckDB companion supplies the optional native module and retains File SQL view setup.@justybase/netezza-runtimeowns the only production import of@justybase/netezza-driver, stateful API lifecycle and metadata helpers. The desktop dialect and MCP use its factory, while@justybase/database-runtimere-exports compatibility helpers without importing the driver.
All three packages accept resolved product configuration rather than API store objects, credentials are decrypted only in the API adapter, and shutdown drains active operations in the API managers. Netezza uses a fresh connection per execution (including a per-query database override); the manager retains a target fingerprint rather than credentials. The Web/API and VS Code adapters instantiate the same runtime packages without moving secrets into shared code.
Closure evidence for R2 (lifecycle/cancellation in desktop DuckDB and File
SQL, direct SqliteSession ownership/close tests plus real Extension Host
SQLite runs, and a clean-checkout build/package verification) is recorded in
REFACTORING_PLAN.md under "R2 closure evidence".
#Execution orchestration in R5 (closed 2026-09-09)
@justybase/database-runtime/execution is the canonical lifecycle owner for
desktop single/batch/stream execution. At the time of the migration it also
owned API query jobs; that adapter was retired with the Web Editor. The shared
package consumes additive contracts from @justybase/contracts and exposes an
injected backend port; it does not know about VS Code, editors, web sockets,
credentials, history or UI messages. Product adapters map lifecycle events to
their existing protocols.
The shared owner guarantees monotonic event sequence, at most one reconnect, one terminal summary, callback retirement, cancellation checks around reconnect, and idempotent reverse-order cleanup. Replay safety is stricter than read-only authorization and requires no rows to have crossed the delivery boundary. Failed streams retain partial row/limit metadata without replaying already delivered data. Desktop activation owns the current mutable registries and timers; former API server registries were retired with that product, while compatibility singletons are forwarding facades only.
#Netezza validation boundary
@justybase/sql-core/validation defines the canonical diagnostic, position,
scope, statement-boundary and validation-result shapes. Desktop validation
profiles are aliases of the contracts package model. The desktop adapter in
src/sqlParser/sqlCoreAdapter.ts crosses this boundary explicitly. The former
API adapter in apps/api/src/sqlCoreLsp.ts used the same boundary and is
historical. The desktop adapter preserves the existing validation result
shape, incremental-cache ownership, SQL025/SQL026
metadata flow, LSP severity conversion and suggested-fix mapping.
The current Netezza semantic backend is the package-owned
NetezzaSqlSemanticValidator. Full, parse-result, and incremental validation
all call it directly. SqlCoreBackedValidator implements the shared
SqlValidationService without inheriting from or constructing the legacy
SqlValidator; the latter remains the fallback for non-Netezza dialects and
the parity oracle for the migration corpus. Desktop compatibility facades
retain their result shape and incremental cache owner.
Required checks for this slice are:
npm run test:sql-corefor the package boundary;sqlCoreValidationParity.test.tsfor diagnostic, scope and directvalidateIncrementalboundary parity;- parser, linter and Extension Host authoring suites (the API suite was retired with the Web product);
npm run check:architecturewith no new exceptions or cycles.
The complete layer/import exception inventory is
quality/architecture-rules.json, not a second manually maintained list. Both
its exceptions and cycleExceptions arrays are empty, so no active exact
direction/import exception or fingerprinted cycle remains. The current graph
contains 1,367 production files and 4,492 resolved internal edges and passes
with zero cycles. Companion production code no longer has an edge into src,
and migrated webviews no longer import companion DDL. The former cycle areas
were closed through leaf contracts, narrow ports, neutral connection-factory
ownership, and host-provided maintenance callbacks. New forbidden edges or
cycles fail the blocking check.
The report includes type-only imports; the former cycles were not all runtime cycles. It excludes tests, declarations, generated output and non-TypeScript assets, and cannot prove absence of dependencies hidden behind nonliteral loaders.
#Companion public entry points and compatibility
Core activation returns JustyBaseLiteApi v1 from src/api/publicApi.ts.
The VS Code-specific activateCoreExtension() adapter and
CORE_EXTENSION_ID now live in packages/vscode-companion-adapter; it
activates the core and validates version/registration methods. Companions
consume this adapter and portable types from @justybase/contracts; they do
not import a desktop src implementation. The enforced companion boundary is
npm run check:companion-boundaries, included in npm run check:architecture.
| Public API members | Responsibility |
|---|---|
version, registerDatabaseDialect, listRegisteredDatabaseDialects |
v1 handshake and dialect registration |
createConnectedDatabaseConnectionFromDetails (optional) |
connected/tunnel-aware runtime creation |
openFileSqlSession, openFileSqlWorkspaceSession |
File SQL editor/profile integration |
listSavedConnections, getActiveConnectionDetails, getConnectionSummary (optional) |
connection discovery and editor binding |
executeActiveConnectionSql, executeActiveConnectionSqlQuery (optional) |
active editor execution |
executeConnectionSql, executeConnectionSqlQuery (optional) |
named-profile execution |
The public @justybase/contracts barrel exports database connections,
capabilities, dialect traits, authoring, import, and advanced-feature provider
types. A desktop implementation imported directly by an addon is technical
debt even if exported by its source module. Dialect packages own provider
implementations; desktop owns capability lookup and orchestration, while
companions register their dialect object and retain database I/O, secrets, and
resource lifetime.
Keep v1 signatures, optionality, activation behavior and
registerDatabaseDialect semantics unchanged. Contracts evolve additively:
existing payloads must remain accepted and existing fields retain meaning.
Adding a required field or union variant that breaks exhaustive consumers needs
a separate compatibility design, not an automatic declaration of “additive”.
Keep facades until every consumer of that slice has migrated. Never serialize
driver objects, VS Code handles or credentials into a new shared result type.
The v1 getActiveConnectionDetails method retains its historical
credential-bearing ConnectionDetails result for compatibility with already
published companions. New shared DTOs must continue to omit credentials; a
credential-free replacement requires a coordinated major-version rollout for
the core extension and all companions.
#Tabular import ownership
@justybase/tabular-import-runtime currently owns the platform-neutral
analysis, descriptor, sampling, and row-reading behavior used by the Snowflake
planner. The desktop importer remains the compatibility/product implementation
for Netezza and the other companion import paths. The former API
request/upload and database-execution import path was retired with the Web
product. A future consolidation must first compare CSV/XLSX/XLSB quoting,
header, type-inference, limits, and error behavior, then migrate consumers and
remove the old paths with the corresponding product gates.
Result webview messages and API QueryEvent are distinct historical
protocols. At the time of the migration, HTTP/CSRF/download/WebSocket transport
was shared by the Web Editor and VS Code through @justybase/api-client; that
client package and the Web Editor were retired on 2026-09-26. Public API DTOs
remain in contracts for compatibility. No current desktop code depends on the
retired HTTP transport.
Preserve legacy timestamp identity fallback, row offsets, chunk sequence and
authoritative hydrate semantics. Cache/disk schema changes require explicit
versioning, migration/reset and restart evidence under
Metadata cache contract.
#Contract duplication audit
These entries describe canonical ownership or compatibility obligations; they
are not interchangeable aliases. The result-model and metadata-rule slices now
have concrete @justybase/result-core and @justybase/metadata-core
implementations; the other future packages remain migration targets.
| Concept | Existing definitions | Future canonical definition / compatibility obligation |
|---|---|---|
| Query result and columns | src/types/index.ts: QueryResult, ResultSet, ColumnDefinition; former apps/web/src/queryState.ts: ResultState; contracts QueryColumn, QueryPageResponse; public API ConnectionQueryResult |
Portable result DTO remains in contracts; @justybase/result-core owns desktop result identity/state and pure operations. Former Web data/API rows and column type/scale mappings are historical compatibility concerns. |
| Streaming chunks | src/core/streaming/StreamingManager.ts: StreamingChunk; src/contracts/webviews/resultPanelContracts.ts: append/hydrate messages; contracts QueryRowsEvent and ExecutionRowsEvent |
ExecutionRowsEvent is canonical only inside the shared execution lifecycle. Callback chunks and product wire events remain explicit adapter boundaries; first/last, partial/cancelled, total counts and ordering mappings are tested. |
| Query events | packages/contracts/src/webApi.ts: legacy QueryEvent; packages/contracts/src/queryExecution.ts: ExecutionEvent; desktop execution lifecycle and webview command unions |
ExecutionEvent is canonical for shared execution orchestration and guarantees one terminal summary. The former HTTP/WebSocket QueryEvent DTO remains exported for compatibility; no current product adapter consumes that transport. |
| Source/result identity | src/state/resultSetIdentity.ts, ResultSet.resultSetId; media ResultSetScope/GridScrollState; API queryId, statementIndex, sessionId |
@justybase/result-core owns source, execution, result-set and storage-session identity rules. IDs are not tab indices, timestamps, storage-session IDs or interchangeable URI strings; adapters retain URI normalization and legacy fallback. |
| SQL diagnostics | @justybase/sql-core/validation: ValidationError, ValidationResult, Scope, StatementBoundary; contracts SqlDiagnostic; desktop quality/LSP mappings |
Shared structural validation types are canonical in sql-core; adapters retain only runtime, qualification and transport-specific mappings. Preserve offset and line conventions, rule-code mapping, ranges and suggested fixes. |
| Metadata columns | parser ColumnInfo; contracts MetadataColumn; desktop MetadataColumnItem; ColumnDefinition |
Portable metadata column DTO in contracts and metadata rules in @justybase/metadata-core. Preserve dataType, keys, qualification, aliases; map FORMAT_TYPE and LSP type explicitly. SQL025/026 must work through both schema providers. |
| Capabilities and authoring | packages/contracts/src/database/index.ts; packages/contracts/src/database/advancedFeatures.ts; packages/dialect-utils/src/authoring/*; src/core/sqlAuthoringRegistry.ts; src/contracts/database/index.ts |
contracts owns portable capabilities, provider contracts, and validation profiles; @justybase/dialect-utils owns pure optional-dialect authoring; desktop owns registry lookup/orchestration; dialect packages own runtime providers; extension authoring files remain compatibility facades. |
| Query/metadata/result services | shared ExecutionOrchestrator; desktop activation-owned StreamingManager, MetadataCache, ResultStateManager; former API server jobs, @justybase/api-client, and Web queryState.ts |
The orchestrator owns desktop execution state/retry/cleanup through injected ports. Former API client transport and server-owned jobs were retired with the Web product; desktop adapters retain secrets, database acquisition, I/O, state lifetime and transport policy. |
#Proposed product service ports
This typed design sketch is not a new exported API. Request/response types
below refer to the existing names in @justybase/contracts; ResultRef and
ExportArtifact illustrate adapter-local identities/handles pending the result
slice. Implement only the port needed by a real migration. Clients receive
individual services, not a singleton product service locator.
type Dispose = () => void;
type ResultRef = { queryId: string; statementIndex: number };
type ExportArtifact = { downloadUrl: string; expiresAt?: number };
interface SqlAuthoringService {
completion(request: SqlCompletionRequest): Promise<SqlCompletionResponse>;
diagnostics(request: SqlDiagnosticsRequest): Promise<SqlDiagnosticsResponse>;
format(request: SqlFormatRequest): Promise<SqlFormatResponse>;
}
interface MetadataService {
columns(connectionId: string, database: string, schema: string,
table: string): Promise<MetadataColumn[]>;
invalidate(connectionId: string): Promise<void>;
}
interface QueryExecutionService {
preview(request: QueryStartRequest): Promise<QueryPreviewResponse>;
start(request: QueryStartRequest): Promise<QueryStartResponse>;
cancel(queryId: string, scope: 'statement' | 'batch'): Promise<void>;
subscribe(queryId: string, onEvent: (event: QueryEvent) => void,
onError: (error: Error) => void, afterSequence?: number): Dispose;
}
interface ResultStorageService {
page(result: ResultRef, request: QueryPageRequest): Promise<QueryPageResponse>;
release(result: ResultRef): Promise<void>;
}
interface ExportService {
export(result: ResultRef, request: QueryExportRequest): Promise<ExportArtifact>;
}
interface ConnectionService {
list(): Promise<ConnectionProfileSummary[]>;
save(profile: ConnectionProfileInput): Promise<ConnectionProfileSummary>;
remove(connectionId: string): Promise<void>;
}The pure result reducer is a separate state + event -> state engine, not a
storage service or transport client. Query cancellation is an explicit backend
operation; disposing a subscription only removes listeners. Adapters translate
errors, enforce authorization, own pending operations and release sessions on
product shutdown. Metadata caches are scoped by connection/database/schema and
user where applicable; no cross-user singleton may hold credentials or results.
The former Web adapter used HTTP plus its event transport. VS Code uses an in-process compatibility adapter with editor and secret-storage integration. A future download handle must be scoped to the authenticated owner; it is not a raw server filesystem path.
#Migration order and comparison gates
- Replace the legacy backend behind the validation boundary with the Netezza parser/linter implementation in sql-core. The completed vertical slice is parser-backed validation and authoring for a document plus injected schema metadata: input SQL/profile/schema -> parse -> diagnostics/quality/authoring -> desktop compatibility facade. Keep the smallest coherent dependency closure, public exports and diagnostics mappings intact.
- Use SQLite and DuckDB as the first dialect packs, splitting pure authoring from runtime/driver registration without changing companion registration.
- Extracted shared result identity/state and pure operations to
@justybase/result-core; the former Web consumer was removed at retirement. - The former Web/API event and storage adapters preserved their own wire boundaries; the HTTP client transport was retired with that product.
@justybase/api-clientand the Web React provider were removed on 2026-09-26; VS Code retains its host integration.- Extracted metadata keys, identifier policies, TTL, completeness,
merge/invalidation, indexes, and prefetch decisions to
@justybase/metadata-core; desktop disk/catalog adapters own current product-specific state. The former API per-server metadata service was retired with the Web product. - Migrate companions one at a time with their own activation/runtime evidence.
Every backend/shared-code slice in R0–R8 switches desktop through its
compatibility adapter and runs the relevant desktop gates. R9 and its
Web → VS Code UI order are historical. This does not move execution,
runtime, or secret ownership out of the desktop-first path. For the first SQL slice, keep a
baseline fixture corpus with expected diagnostic codes, severities, messages,
ranges and fixes; compare old and extracted implementations against that same
corpus before deleting the old implementation. Include Netezza DB..TABLE,
qualified/relaxed names, procedures and string bodies, malformed SQL, typed and
untyped metadata, and both metadata schema-provider paths. Never normalize away
codes, offsets, column types or stable identity to make parity pass.
Use validator.test.ts, identifierRoleCollector.test.ts,
completionEngine.test.ts, metadataCacheAdapter.test.ts and
lspSchemaProvider.test.ts as existing authoring anchors. Run parser construction
guards and benchmark:lsp for SQL changes; preserve hard dialect budgets and
the performance policy in the testing strategy.
For results, freeze pure state transitions first using
resultStateManager.test.ts, resultPanelStateContract.test.ts,
resultPanelProtocol.test.ts, and (for historical parity evidence) web
queryState.test.ts and API querySessions.test.ts. Compare ordered events, stable identities, total/partial
rows, retries/cancellation and cleanup before DOM work. Then exercise the full
persisted/async UI matrix in the testing strategy, followed by bundled browser,
Extension Host and React boundaries. No new reducer tests can prove migration
parity before a reducer is actually extracted. The R9 result slice now adds
@justybase/ui-core state/ports and @justybase/ui-react presentation for the
VS Code adapter; the Web adapter and its remaining follow-up slices retired with
the product.
#Repeatable verification and completion
Use Node >=22.12 and root npm ci with the lockfile; install companion
dependencies through npm run install:<dialect> where provided. All commands
below run from the root; do not commit generated bundles, profiles or reports.
| Scope | Gates |
|---|---|
| Preparation tooling/docs | check:architecture, test:quality-tools, docs:check, version:check |
| Desktop/shared baseline | npm run verify:pr (architecture, type checks, lint, unit/coverage and desktop build; retired API/web gates are excluded) |
| Companions | npm run verify:access, verify:db2, verify:duckdb, verify:oracle, verify:postgresql, verify:snowflake, verify:mssql, verify:mysql, verify:clickhouse, verify:vertica (lint/types/build, not live tests) |
| Companion registration | npm run test:extension-host:companions |
| SQL extraction | npm run test:parser, test:completion-parity, test:extension-host:authoring, benchmark:lsp; dialect construction tests |
| Result extraction | npm run test:extension-host, npm run test:playwright -- test-harness/tests/table-rendering.spec.ts |
| Metadata extraction | npm run test:metadata-cache:integration, schema-provider and authoring tests |
| Dialect runtime extraction | matching test:<dialect>:integration, companion verify and packaging gates |
Use xvfb-run -a for Extension Host gates on headless Linux. Live suites require
their documented environment and fixtures; missing configuration is not a pass.
The PR workflow already runs architecture checking in its Quality Checks job;
repository branch protection must require that job (a repository setting, not
something this source change can assert). Tooling changes remain separate from
production migrations in review.
Preparation acceptance requires target ownership, exact debt/graph inventory, compatibility policy, first vertical slice and comparison criteria documented; the checker and negative tests passing in PR; and the existing desktop and companion gates passing without behavior changes. Record commands and environment limitations in the implementation handoff. API and Web gates named in the original migration record are historical. Documentation or a passing import graph alone is not evidence of runtime parity. Do not begin a production move while its prerequisite gates remain unresolved.