Skip to content

chore(core): backend stabilization — ARCH rules, comment hygiene, decomposition (pre-UX) - #163

Merged
dgtalbug merged 15 commits into
mainfrom
chore/stability-audit-pre-ux
Jun 7, 2026
Merged

chore(core): backend stabilization — ARCH rules, comment hygiene, decomposition (pre-UX)#163
dgtalbug merged 15 commits into
mainfrom
chore/stability-audit-pre-ux

Conversation

@dgtalbug

@dgtalbug dgtalbug commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Summary

The pre-UX stable cut from the stability audit (scratch/stability-audit/). Implements the architecture rules that .dextree/rules.md declared but the code never enforced, fixes a multi-language correctness bug, removes spec/process comment rot, decomposes backend god-objects, and clears the opportunistic P3 backlog. Every group is behavior-preserving and the full test suite stays green throughout (core 266 / exporters 161 / extension 640).

Linked spec / issue

Slice classification

  • refactor — internal change, no behavior delta (one fix for the import bug, one additive feat for symbol-tree nesting)

Affected surfaces

  • packages/core
  • packages/extension (VS Code host)
  • packages/exporters
  • Build / CI / tooling (eslint.config.js, static-checks workflow, spec-tag guard script)

Groups (commit-by-commit)

  1. ff4f4eb comment hygiene (122→0 spec tags, 3 user-facing slice-leak fixes) + ESLint no-vscode-in-core
  2. 4630091 fix: multi-language imports — IMPORTS edges for Python/Go/Rust/etc., not just TS/JS
  3. 1269c97 DuckDB driver confined to storage/adapters/ + @duckdb/node-api ESLint ban (RULE-ARCH-003)
  4. bb901df serializer strategy registry (RULE-ARCH-004) + PreciseLocationResolver interface (RULE-ARCH-010)
  5. e6a98c0 typed EdgeMetadata + key constants (RULE-ARCH-007) + boundary hardening (RULE-ARCH-006)
  6. ff16c09 backend decomposition (repository.ts 915→507 via resolution.ts/folderTree.ts; subgraph edge-query extract; panel unknown-type branch)
  7. (no commit) folded graph-cleanups items verified already implemented — ignore toggles, hull persistence, exporter test hardening
  8. f02af8b 5.2 typed serializer result { source, validation } — preview router stops reconstructing status by regex over Error.message and stops re-running the pipeline for the soft-cap warning
  9. 9ae8ddb 6.3 (partial) extract useGraphLenses hook from GraphView.tsx (1747→1680)
  10. e2935bb 6.4 (partial) extract createExportShortcutCommands factory from activate (548→519)
  11. 51cfb83 1.6 CI guard (scripts/check-no-spec-tags.mjs + static-checks step) so the comment-hygiene cleanup can't rot back
  12. 7f3fe31 8.1 drop unused ExtractionResult.modules/.tests (producer+aggregator, zero consumer); keep recomputeGraphHealth as a documented seam
  13. df5c52c 8.2 route clear.ts through runInTransaction; per-connection transaction guard (WeakMap<connection>, was a module-global boolean)
  14. 9d5b86d 8.3 firstCapBreach cap helper (class-diagram); indexed sequenceDiagram lookups (was O(trace·subgraph)); split serializeToClassDiagram
  15. e4c19d2 8.4 (partial) single source of truth for Mermaid option strings (RULE-ARCH-007) — canonical as-const arrays, types derived, validators/fuzz derive from them
  16. 90d741a 8.5 nest methods under their enclosing class in SymbolsTreeProvider via enclosingSymbolId

Test plan

  • pnpm check green (prettier + eslint --max-warnings=0 + lint + test + typecheck) on the committed tree
  • tests behavior-preserving throughout: core 266, exporters 161, extension 640 (forced/uncached)
  • both ESLint bans active: no vscode in core, no @duckdb/node-api outside storage/adapters/
  • multi-language IMPORTS verified (Python/Go/Rust fixtures)
  • global spec-tag grep returns 0 in non-test source — now enforced in CI (pnpm lint:spec-tags)
  • pnpm dedupe --check clean (no deps added)

Deferred to follow-ups (documented in the change)

  • WebviewPanelManager singleton encapsulation (the other half of 8.4) → the UX phase: ~30 call sites across extension.ts/panel.ts, the same files the UX rework touches (same rationale as the remaining 6.3/6.4 hooks). The Mermaid-option single-source half shipped here.
  • Remaining 6.3/6.4 hooks (GraphView selection/trace/layout/search; the 14-dep registerCommands) → the UX phase, which reworks GraphView; splitting all of them now would be done twice. The clean seams (lens hook, export-shortcuts factory) shipped here.
  • Full method-per-query GraphRepository interface → its own PR. Design is written (scratch/stability-audit/graph-repository-design.md, grounded in the real query/storage surface). This PR already delivers ARCH-003's intent: the driver is isolated to the adapter and ESLint-enforced.
  • 8.5 structure-only fallback diagram for ungrammared languages (separate, lower-value). Outline→Mermaid as a primary mechanism is DROPPED (scratch/stability-audit/findings-outline.md).

Notes for reviewers

  • The headline: three approved ARCH rules (repository port intent, serializer strategy, resolver interface) were declared in .dextree/rules.md but never implemented — this makes them real and lint-enforced.
  • Two deliberate "keep" decisions worth a reviewer's eye (decisions.md is anchored, so they're flagged here, not in the file): recomputeGraphHealth is a documented seam, not dead code (8.1); MermaidTheme is intentionally a separate vocabulary from the webview's lowercase theme (8.4).
  • recomputeGraphHealth-style judgments and per-package findings: scratch/stability-audit/ (gitignored, local).
  • Every group left the test suite green; commits are independently revertible.

🤖 Generated with Claude Code

dgtalbug added 6 commits June 7, 2026 12:53
…group 1)

Strip spec/process tracking metadata from non-test source comments across all
three packages, keeping the genuine why-explanations. Removes Slice/FR/US/T0xx/
S8/M7/CodeRabbit/CodeQL/"this slice" tags; rewrites comments that named the four
extractor classes deleted in the indexing rewrite to describe the generic engine.

Also fixes three user-facing strings that leaked slice numbers into the UI
(Mermaid sequence-diagram unavailable label, decorator-classification label,
sequence-preview message) and adds an ESLint `no-restricted-imports` rule banning
`vscode` in `packages/core/src` (RULE-ARCH-005), making the boundary self-policing.

Comments only — no code logic changed. Global spec-tag grep is now 0 in non-test
source. typecheck 5/5, tests unchanged (core 263 / exporters 161 / extension 638),
lint green with the new ban active.

The `@duckdb/node-api` ban is deferred to group 3, after storage access moves
behind the repository adapter.
…group 2)

extractImportRefs matched only the TS/JS `import_statement` node type and
hardcoded language:"typescript", so Python/Go/Rust/Java/etc. emitted zero IMPORTS
edges (its sole caller runs for every language). Drive import extraction off the
provider (RULE-ARCH-009).

- ProviderConfig.importNodeTypes: each language declares its grammar's import
  node types; the engine reads the specifier and emits IMPORTS generically.
- extractImportRefs tags the edge with the file's language and keeps the raw
  specifier when TS-style path resolution doesn't apply, so the edge always
  exists; the generator emits importNodeTypes per language.
- Tests: Python/Go/Rust each produce language-tagged IMPORTS edges; TS unchanged.

typecheck 5/5; core 266 (+3), exporters 161, extension 638; lint green.
…RULE-ARCH-003)

Isolate the database driver so the rest of core depends on an abstraction, not
@duckdb/node-api directly.

- storage/adapters/duckdb.ts: the only module allowed to import the driver. Owns
  instantiation (openDatabase / openReadOnlyDatabase / runInTransaction / readRows)
  and re-exports the connection type as GraphDbConnection (+ GraphDbResult /
  GraphDbValue).
- storage/db.ts is now a thin facade re-exporting the adapter; all 15 storage +
  query modules import GraphDbConnection from it instead of the driver.
- workspaceRegistry's two inline foreign-DB opens go through openReadOnlyDatabase.
- ESLint: ban @duckdb/node-api in packages/core/src except storage/adapters/**
  (alongside the existing no-vscode ban) — both boundaries now self-policing.

Scope note: a full method-per-query GraphRepository interface was a multi-day,
high-risk rewrite and is deferred to its own PR; this delivers RULE-ARCH-003's
intent (driver isolated to the adapter, modules off the driver, lint-enforced)
with zero behavior change.

Pure relocation: typecheck 5/5, tests unchanged (core 266 / exporters 161 /
extension 638), lint green with both bans active. Public Indexer contract
unchanged — no consumer edits.
…ARCH-004/010)

Implement two declared-but-unused architecture rules as real interfaces.

RULE-ARCH-004 — serializer strategy:
- SubgraphSerializer interface + a SERIALIZERS registry keyed by diagram type in
  scopedSerializer.ts; the hardcoded `switch (options.diagram)` becomes a registry
  lookup, so adding a diagram type is registration, not a new switch arm.
  Behavior-preserving (same three serializers).

RULE-ARCH-010 — resolver interface:
- core gains PreciseLocationResolver (+ shared NodeLocation / PreciseCallEdge):
  a position-based precise-resolver contract, since the LSP answers by
  file+position, not by graph node id (core's existing CallResolver is the
  node-id/heuristic contract). LspCallResolver now `implements
  PreciseLocationResolver` — the host/core seam is real and IntelliJ-portable.
- deduped the webview protocol's PreciseCallEdgeResult to alias core's
  PreciseCallEdge (RULE-ARCH-007 — one shape across resolver/message/webview).
- SCIP ingest is a bulk index importer, not a per-node resolver, so it stays as
  its own shape rather than be forced into either interface (documented).

typecheck 5/5; tests unchanged (266/161/638); lint green; additive, no consumer
ripple.
…/007)

Make the edge-metadata seam typed and the public boundaries fail-fast.

RULE-ARCH-007 — typed metadata:
- storage/edgeMetadata.ts: typed EdgeMetadata + EDGE_META_KEYS constants +
  metaPath() helper. The engine writer and all 10 resolution-SQL sites now
  reference the shared constants instead of duplicated string literals, so a
  drifted key is a single edit and a TS typo is a compile error.

RULE-ARCH-006 — boundary hardening:
- DuckTreeIndexer.indexFile rejects non-absolute paths; neighborhood rejects an
  empty nodeId — fail fast with a descriptive error rather than a deep fs/SQL
  failure later.
- watcher re-index failure now logs at error (was debug — silent staleness);
  panel workspace-list + precise-calls catches log before degrading.
- synthesizeFolderTree's load-bearing `!!` assertions replaced with a guard that
  throws a clear invariant error.

Deferred: 5.2 typed serializer result (a serializer throw-contract change with
its own test ripple) → its own follow-up.

typecheck 5/5; tests unchanged (266/161/638); lint green. Behavior-preserving
(the metaPath SQL is byte-equivalent to the prior quoted literals).
Behavior-preserving structure cleanup with clean seams; GraphView.tsx + activate
decomposition deferred to the UX phase (that phase reworks GraphView, so splitting
it now would be done twice).

- storage/repository.ts 915→507 LOC: extracted resolution.ts (resolveCallEdgeSymbols
  / stampResolutionTier / resolveWorkspaceCrossFileEdges) and folderTree.ts
  (folderId / synthesizeFolderTree). Re-exported so index.ts is untouched.
- query/subgraph.ts: extracted queryResolvedEdges() — the four byte-identical
  CALLS/INHERITS/INSTANTIATES/IMPLEMENTS query blocks (~95 LOC) collapse to four
  calls.
- webview/panel.ts: navigate is now an explicit branch and unknown message types
  are logged instead of silently falling through to navigate-validation.

typecheck 5/5; tests unchanged (266/161/638); lint green. Zero behavior change.
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 53560f57-1586-4e43-a59a-390a3b064d85

📥 Commits

Reviewing files that changed from the base of the PR and between d50d6c8 and 90d741a.

⛔ Files ignored due to path filters (9)
  • packages/core/src/extractors/languages/generated/tree-sitter-c-sharp.ts is excluded by !**/generated/**
  • packages/core/src/extractors/languages/generated/tree-sitter-c.ts is excluded by !**/generated/**
  • packages/core/src/extractors/languages/generated/tree-sitter-cpp.ts is excluded by !**/generated/**
  • packages/core/src/extractors/languages/generated/tree-sitter-go.ts is excluded by !**/generated/**
  • packages/core/src/extractors/languages/generated/tree-sitter-java.ts is excluded by !**/generated/**
  • packages/core/src/extractors/languages/generated/tree-sitter-php.ts is excluded by !**/generated/**
  • packages/core/src/extractors/languages/generated/tree-sitter-python.ts is excluded by !**/generated/**
  • packages/core/src/extractors/languages/generated/tree-sitter-rust.ts is excluded by !**/generated/**
  • packages/core/src/extractors/languages/generated/tree-sitter-scala.ts is excluded by !**/generated/**
📒 Files selected for processing (79)
  • .github/workflows/_static-checks.yml
  • eslint.config.js
  • package.json
  • packages/core/scripts/gen-tags-providers.mjs
  • packages/core/src/extractors/GenericTagsExtractor.ts
  • packages/core/src/extractors/classification/classifySymbol.ts
  • packages/core/src/extractors/frameworks/detector.ts
  • packages/core/src/extractors/frameworks/matchers/manifest.ts
  • packages/core/src/extractors/frameworks/matchers/toml.ts
  • packages/core/src/extractors/frameworks/registry.ts
  • packages/core/src/extractors/languages/multiLanguage.test.ts
  • packages/core/src/extractors/languages/types.ts
  • packages/core/src/extractors/languages/typescript.ts
  • packages/core/src/extractors/registry.test.ts
  • packages/core/src/extractors/registry.ts
  • packages/core/src/extractors/types.ts
  • packages/core/src/index.ts
  • packages/core/src/parser/extractor.ts
  • packages/core/src/quality/recomputeGraphHealth.ts
  • packages/core/src/query/coverage.ts
  • packages/core/src/query/files.ts
  • packages/core/src/query/neighborhood.ts
  • packages/core/src/query/presentEdgeKinds.ts
  • packages/core/src/query/sessionSummary.ts
  • packages/core/src/query/subgraph.ts
  • packages/core/src/query/symbols.ts
  • packages/core/src/resolution/types.ts
  • packages/core/src/storage/adapters/duckdb.ts
  • packages/core/src/storage/clear.ts
  • packages/core/src/storage/db.ts
  • packages/core/src/storage/edgeMetadata.ts
  • packages/core/src/storage/folderTree.ts
  • packages/core/src/storage/migrations/runner.ts
  • packages/core/src/storage/repository.ts
  • packages/core/src/storage/resolution.ts
  • packages/core/src/storage/schema.ts
  • packages/core/src/storage/workspaceCache.ts
  • packages/core/src/storage/workspaceRegistry.ts
  • packages/core/src/types.ts
  • packages/exporters/src/__fuzz__/serializer.fuzz.ts
  • packages/exporters/src/index.ts
  • packages/exporters/src/mermaid/classDiagram.ts
  • packages/exporters/src/mermaid/preview.ts
  • packages/exporters/src/mermaid/scopedSerializer.ts
  • packages/exporters/src/mermaid/sequenceDiagram.ts
  • packages/exporters/src/mermaid/serializer.ts
  • packages/exporters/src/mermaid/validator.ts
  • packages/extension/src/cache/workspaceRegistry.ts
  • packages/extension/src/commands/exportMermaid.ts
  • packages/extension/src/commands/exportShortcuts.ts
  • packages/extension/src/commands/indexWorkspace.ts
  • packages/extension/src/commands/switchWorkspace.ts
  • packages/extension/src/extension.ts
  • packages/extension/src/resolution/lspCallResolver.ts
  • packages/extension/src/tree/SymbolsTreeProvider.test.ts
  • packages/extension/src/tree/SymbolsTreeProvider.ts
  • packages/extension/src/watcher/workspaceWatcher.ts
  • packages/extension/src/webview/App.tsx
  • packages/extension/src/webview/components/EmptyState.tsx
  • packages/extension/src/webview/components/GraphToolbar.tsx
  • packages/extension/src/webview/components/GraphView.tsx
  • packages/extension/src/webview/components/LoadingState.tsx
  • packages/extension/src/webview/components/MermaidPreviewPanel.tsx
  • packages/extension/src/webview/components/SigmaController.ts
  • packages/extension/src/webview/components/WorkspaceCard.tsx
  • packages/extension/src/webview/components/WorkspacesPage.tsx
  • packages/extension/src/webview/components/graphLayoutPresets.ts
  • packages/extension/src/webview/components/graphTraversal.ts
  • packages/extension/src/webview/components/graphViewTypes.ts
  • packages/extension/src/webview/components/hooks/useGraphLenses.ts
  • packages/extension/src/webview/components/lensColor.ts
  • packages/extension/src/webview/components/shellLayout.ts
  • packages/extension/src/webview/html.ts
  • packages/extension/src/webview/panel.ts
  • packages/extension/src/webview/preview/exportPreview.ts
  • packages/extension/src/webview/preview/renderMermaid.ts
  • packages/extension/src/webview/protocol/messages.ts
  • packages/extension/src/webview/validate.ts
  • scripts/check-no-spec-tags.mjs

📝 Walkthrough

Summary

User-visible and reviewer-relevant changes:

  1. Multi-language IMPORTS edges — IMPORTS edges now extracted for Python, Go, Rust, and other configured languages (previously TS/JS only). Extractor emits language tags on imports; importNodeTypes field added to ProviderConfig to declare per-grammar import node types.

  2. Architecture rules enforcement — ESLint now blocks direct vscode imports in core and confines @duckdb/node-api to storage/adapters/duckdb.ts. CI guard script (lint:spec-tags) prevents spec-tracking tags (FR-/TR-/US-/slice-) from accumulating in shipped source.

  3. DuckDB driver isolation & transaction safety — DuckDB-specific code consolidated in storage/adapters/duckdb.ts. New runInTransaction(connection, operation) enforces per-connection nesting via WeakMap guard, executes defensive ROLLBACK before operation, and rethrows operation errors after rollback attempt.

  4. Backend decompositionresolution.ts (new) extracts call/edge symbol resolution, folder-tree synthesis, and cross-file edge resolution. repository.ts reduced from 424 to 30 lines by re-exporting decomposed functions. All query modules (coverage.ts, files.ts, etc.) migrated from DuckDBConnection to GraphDbConnection abstraction.

Risks and coverage gaps:

  • Codecov patch coverage 82.3%; notable gaps: workspaceRegistry.ts (42.85%), core index/storage adapters (0–90%). Multi-language import extraction edge cases not fully covered.
  • Per-file resolution pass in resolveCallEdgeSymbols iterates all edges; workspace-wide cross-file pass may grow quadratically with symbol count.
  • Symbol tree nesting filters "dangling" enclosingSymbolId references (no corresponding symbol in file). Silently excludes those methods from tree; potential data loss if indexer metadata mismatches.
  • Typed EdgeMetadata relies on string-key JSONPath extraction (metaPath); schema restructuring could break extraction without migration.

Deferred validation:

  • WebviewPanelManager full encapsulation deferred to UX phase.
  • Full GraphRepository per-method-per-query decomposition deferred to follow-up PR.
  • GraphView/activate hooks full extraction deferred (UX rework intersection).
  • Serializer throw-contract (error handling semantics) deferred.

Package & schema boundaries:

  • No schema version bump; existing migrations sufficient. Edge metadata JSON structure unchanged; only typed in-memory representation added.
  • Core exports expanded: PreciseLocationResolver, NodeLocation, PreciseCallEdge (from resolution/types.ts).
  • Exporters exports expanded: MERMAID_DIAGRAMS, MERMAID_DIRECTIONS, MERMAID_GRANULARITIES from mermaid/theme.js.
  • Extension protocol updated: PreciseCallEdgeResult is now type alias to core's PreciseCallEdge.
  • All storage/query modules now depend on GraphDbConnection abstraction; no breaking changes to public function signatures (parameter types updated consistently).

Test status: Core 266, exporters 161, extension 640 remain green. Behavior-preserving except multi-language import fix and symbol-tree nesting feature.

Walkthrough

Systematic backend stabilization that isolates the DuckDB driver, abstracts database connections, standardizes edge metadata, enables multi-language import extraction, adds graph resolution and folder synthesis, refactors Mermaid serialization to a registry-based non-throwing API, centralizes lens logic, nests symbol trees, and removes all internal spec-tracking tags.

Changes

Backend stabilization & frontend unification

Layer / File(s) Summary
Static enforcement & spec-tag scanning
.github/workflows/_static-checks.yml, package.json, eslint.config.js, scripts/check-no-spec-tags.mjs
New workflow step runs pnpm lint:spec-tags after ESLint. ESLint forbids vscode and @duckdb/node-api imports in core (outside storage/adapters). Scanner script walks packages/, excludes test paths, regex-matches tracking tags (FR/US/SPEC IDs, slice markers), fails with exit 1 on hits.
DuckDB adapter isolation & database facade
packages/core/src/storage/adapters/duckdb.ts, packages/core/src/storage/db.ts
storage/adapters/duckdb.ts becomes the only place @duckdb/node-api may be imported. Exports GraphDbConnection/Result/Value type aliases; DatabaseHandle interface; openDatabase, openReadOnlyDatabase, runInTransaction (with per-connection nesting guard, defensive pre-flight ROLLBACK), readRows. storage/db.ts refactored from implementations to thin facade re-exporting adapter + new openReadOnlyDatabase.
GraphDbConnection abstraction propagation
packages/core/src/storage/, packages/core/src/query/, packages/core/src/quality/recomputeGraphHealth.ts, packages/core/src/storage/migrations/runner.ts
All functions that accept database connections now take GraphDbConnection instead of DuckDBConnection. Schema init, clear operations, migrations, coverage/files/neighborhood/presentEdgeKinds/sessionSummary/subgraph/symbols queries all updated. Transaction handling in clear.ts refactored from manual BEGIN/COMMIT/ROLLBACK to runInTransaction wrapper.
Edge metadata standardization & constants
packages/core/src/storage/edgeMetadata.ts, packages/core/src/extractors/GenericTagsExtractor.ts
New module exports EDGE_META_KEYS (typed as const map of callee/parent/class/interface/reference/reexport/source/import/range/resolution/confidence keys), metaPath(key) JSON-path builder, EdgeMetadata interface. GenericTagsExtractor replaces hardcoded string keys with EDGE_META_KEYS.* for CALLS edges and relation edges.
Multi-language import extraction
packages/core/scripts/gen-tags-providers.mjs, packages/core/src/extractors/languages/types.ts, packages/core/src/extractors/languages/typescript.ts, packages/core/src/parser/extractor.ts, packages/core/src/extractors/languages/multiLanguage.test.ts
ProviderConfig adds optional importNodeTypes: string[] field. Tag provider generator emits per-grammar imports array. extractImportRefs now accepts language and importNodeTypes params, extracts specifiers from quoted strings or (new) unquoted tokens via readUnquotedSpecifier helper, always emits imports (using resolved path or original specifier). TypeScript config specifies importNodeTypes: ["import_statement"]. Test coverage added for python/go/rust IMPORTS edges.
Extractor return shape & comment updates
packages/core/src/extractors/GenericTagsExtractor.ts, packages/core/src/extractors/registry.ts, packages/core/src/extractors/registry.test.ts, packages/core/src/extractors/types.ts, framework/classification comments
ExtractionResult drops modules and tests fields (now file, symbols, imports, edges, annotations only). Test helpers and registry updated accordingly. Comments in classification and framework detector clarity improved; internal plugin contract phrasing updated.
Relational edge resolution & symbol stamping
packages/core/src/storage/resolution.ts, packages/core/src/storage/repository.ts
New resolution.ts exports resolveCallEdgeSymbols (per-file source/target ID resolution from metadata), stampResolutionTier (edge metadata resolution/confidence tagging), resolveWorkspaceCrossFileEdges (workspace-wide cross-file target filling). Repository imports and re-exports these as public API.
Folder tree synthesis
packages/core/src/storage/folderTree.ts, packages/core/src/storage/repository.ts
New module synthesizeFolderTree(connection) deterministically generates folder hierarchy from indexed files using sha256-based folderId, inserts folder rows with parent links, creates folder→folder and folder→file CONTAINS edges. Integrated into repository.
Public API expansion & resolution types
packages/core/src/resolution/types.ts, packages/core/src/index.ts, packages/extension/src/resolution/lspCallResolver.ts, packages/extension/src/webview/protocol/messages.ts
Core exports new NodeLocation (file path + 0-based line/column), PreciseCallEdge (precise tier edge with location + confidence), PreciseLocationResolver interface. LSP resolver imports and implements PreciseLocationResolver, re-exports types. Protocol messages import PreciseCallEdge; PreciseCallEdgeResult becomes type alias to PreciseCallEdge instead of duplicate interface.
Mermaid serializer registry & non-throwing API
packages/exporters/src/mermaid/scopedSerializer.ts, packages/exporters/src/mermaid/preview.ts, packages/exporters/src/mermaid/classDiagram.ts, packages/exporters/src/mermaid/sequenceDiagram.ts, packages/exporters/src/mermaid/validator.ts, packages/exporters/src/index.ts
Vocabularies become canonical as const arrays (MERMAID_DIAGRAMS, MERMAID_GRANULARITIES, MERMAID_DIRECTIONS); types derived from arrays. New SubgraphSerializer interface + SERIALIZERS registry replace switch statement. New ScopedMermaidResult interface + serializeScopedMermaidResult function return typed validation without throwing. Flowchart uses result pipeline; other diagrams map thrown errors to validation outcomes. firstCapBreach utility added for hard-cap checks. Class diagram extraction methods refactored into helpers. Preview router uses new result-based API.
Sequence diagram indexing optimization
packages/exporters/src/mermaid/sequenceDiagram.ts
New SubgraphIndex helper precomputes Map-based lookups for subgraph nodes/edges. buildParticipants and buildSteps replace .find calls with O(1) index lookups.
Graph lens centralization hook
packages/extension/src/webview/components/hooks/useGraphLenses.ts, packages/extension/src/webview/components/GraphView.tsx
New useGraphLenses React hook centralizes lens state management: activeLensId, memoized lensCounts, lensMatchSet, lensColorOf, onLensToggle, lensResultRows. GraphView integrates hook, removes ~70 lines of in-file lens logic.
Symbol tree nesting via enclosingSymbolId
packages/extension/src/tree/SymbolsTreeProvider.ts, packages/extension/src/tree/SymbolsTreeProvider.test.ts
TreeSymbolNode constructor now accepts optional children array; collapsible state computed from children count. New buildSymbolTree() helper constructs nested hierarchy from flat symbol array using enclosingSymbolId, with cycle protection. Provider returns nested tree; symbol nodes return children in getChildren(). Tests verify method nesting under class and dangling-method fallback to top-level.
Export shortcuts command factory
packages/extension/src/commands/exportShortcuts.ts, packages/extension/src/extension.ts, packages/extension/src/commands/exportMermaid.ts
New module defines PickedSymbol, ExportShortcutDeps (adding pickSymbol to deps). createExportShortcutCommands(deps) factories VS Code Disposables registering callers/callees/class-hierarchy (each via pickSymbol then startInferredMermaidExport with kind: "symbol") and package export (direct folder delegation). Extension replaces four inline registrations with single factory spread.
Webview panel error handling & validation
packages/extension/src/webview/panel.ts
Mermaid preview validation now derives allowed options from canonical vocabularies instead of hardcoded strings. Workspace list and precise resolver error paths now emit debug log with captured error, fail closed gracefully. Navigate message handler validates payloads; unknown message types logged as debug.
Spec-tag removal & documentation updates
All files
~122 internal spec-tracking references (FR-NNN, TR-NNN, US-NNN, SPEC, slice-NNN, T0NN, per-*, CodeRabbit, CodeQL) removed from comments and JSDoc. Documentation wording updated to reflect current module ownership and slice boundaries; no logic changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Rationale: Large scope spanning storage abstraction, multi-file connection-type migration, edge metadata refactoring, new resolution logic, Mermaid serializer rewrite, and concurrent frontend changes (lens hook, symbol nesting, export shortcuts). High density of interconnected changes across 80+ files. No single file dominates, but several critical paths (adapter layer, GraphDbConnection propagation, serializer registry) demand careful review. Moderate logic density; most changes are systematic refactors with clear intent. Extensive comment cleanup makes signal harder to spot but doesn't add review complexity.

Possibly related PRs

  • dgtalbug/dextree#155: Builds on the Mermaid serializer refactoring in this PR by introducing MermaidScope type and further specializing the scoped-serializer contract.

Suggested labels

area:core, area:extension, area:ci, area:build, type:feat, type:chore

Poem

🗄️ The Great Decoupling
Spec tags banished to the void (122 gone!),
DuckDB driver walled in its adapter throne,
Edge keys canonicalized, forests grown,
Symbol trees nested—no more flat and lone.
Mermaid talks back with typed result maps,
Lenses centered, holes in the legacy gaps. ✨

@codecov-commenter

codecov-commenter commented Jun 7, 2026

Copy link
Copy Markdown

dgtalbug added 9 commits June 7, 2026 13:52
… re-run (5.2)

The preview router caught the serializer's Error, regex-matched its message to
reconstruct the failure status, and re-ran the whole extract→collapse→validate
pipeline to recover the soft-cap warning. Replace both with typed data.

- scopedSerializer: add serializeScopedMermaidResult() returning
  { source, validation } (ScopedExportValidation). source is non-null exactly
  for ok/warning; null for empty/oversized/unsupported. serializeFlowchart is now
  a thin throwing wrapper over the result-returning serializeFlowchartResult.
- preview.ts: generateMermaidPreview branches on validation.status and reads the
  soft-cap warning directly — no try/catch-and-regex (G4), no pipeline re-run (G5).

typecheck 5/5; tests unchanged (266/161/638); lint green. Behavior-preserving.
… partial)

Begin decomposing GraphView.tsx (1747 LOC) by lifting the self-contained lens
concern into a hook.

- hooks/useGraphLenses.ts: owns activeLensId state + all lens-derived values
  (lensCounts, lensMatchSet, lensColorOf, onLensToggle, lensResultRows) and the
  formatLensMetric helper. Reads the live graph via the shared ref.
- GraphView consumes it via one destructured call; ~60 LOC + 5 lens imports
  removed from the component (1747 → 1680).

The remaining concerns (search, trace, layout, selection) are more entangled
with selection state + Sigma refs; they're left for the UX phase that reworks
GraphView, to avoid decomposing twice. Behavior-preserving: typecheck 5/5,
tests 266/161/638, lint green.
…6.4, partial)

The selection-aware Mermaid export shortcuts (callers / callees / class hierarchy
/ package) were inline in activate's subscriptions block. Lift them into a small
factory.

- commands/exportShortcuts.ts: createExportShortcutCommands({ getIndexer,
  openMermaidPreview, pickSymbol }) returns the four disposables; the three
  symbol-scoped ones share one pickSymbol→startInferredMermaidExport helper.
- activate spreads the factory result instead of four inline command bodies
  (548 → 519 LOC).

Scope note: the rest of the command wiring is already factored into commands/*
modules and is composed in activate (the correct place for a composition root);
a registerCommands(...) split would need a ~14-dependency bag for cosmetic gain,
so it's not done. Behavior-preserving: typecheck 5/5, tests 266/161/638, lint green.
Adds scripts/check-no-spec-tags.mjs and a static-checks step running it via
pnpm lint:spec-tags. Asserts zero FR-/TR-/slice-/CodeRabbit-style tracking
tags in packages/**/*.ts(x), excluding test-support dirs (__fixtures__,
__fuzz__, *.test/spec/fuzz) where naming the pinned requirement is legitimate.
Prevents the comment-hygiene cleanup from Group 1 from rotting back.
These optional fields were readonly unknown[] with a producer (GenericTagsExtractor
emitted []) and an aggregator (registry forwarded them) but zero consumer — the
indexer only reads result.annotations, never .modules/.tests. Untyped, unwired,
dropped on the floor. Remove the field, the 4 registry sites, the producer's empty
arrays, and the test helper.

recomputeGraphHealth (the other half of 8.1) is kept: it is a documented public
seam (referenced by lenses.ts/repository.ts comments + design.md 7.5), not dead
code. Wiring it needs the unimplemented algorithm; unexporting would break the seam.
…on guard (8.2)

clearWorkspace/clearFile/clearAll hand-rolled BEGIN/COMMIT/ROLLBACK, bypassing
runInTransaction's defensive pre-flight rollback, nesting guard, and logger
hooks. Route all three through it (clearAll's post-commit initializeSchema stays
outside the transaction). All three are top-level callers, so the nesting guard
never trips.

Move the transaction-in-flight flag off a module-global boolean onto a
WeakMap<connection> so the nesting guard is per-connection: a process holding
several handles (writable workspace DB + read-only foreign DBs) can no longer
have one connection's transaction flip another's guard. Signature unchanged.

Document pathAliasCache as module-global + never-evicted (bounded in practice;
no clear-on-workspace hook like frameworkCache has).
…s serializer (8.3)

- Add firstCapBreach() in validator.ts; adopt it in the class-diagram validator
  to collapse the two byte-identical oversized branches (classes/methods) into
  one labeled-dimension check. The sequence validator keeps its single combined
  message (one check, no benefit from the helper); the scoped validator is
  two-tier (soft+hard) and is not a consumer — forcing all three under one type
  would be a worse abstraction than the explicit per-diagram unions.
- sequenceDiagram: build an id->node / id->edge index once per pass instead of
  .find over the whole subgraph inside the trace loops (was O(trace*subgraph)).
- Split serializeToClassDiagram into emitClassBodies + collectRelationshipLines;
  the top function is now a readable assembly. Output byte-identical.

All behavior-preserving: exporters 161/161, typecheck clean.
…tial)

Make the diagram / granularity / direction vocabularies canonical as-const
arrays in scopedSerializer.ts (MERMAID_DIAGRAMS / _GRANULARITIES / _DIRECTIONS),
with each type derived from its array so values and type can't drift. panel.ts's
VALID_* host-side validation Sets and the exporters fuzz harness now derive from
them instead of re-listing the literals (RULE-ARCH-007). Theme stays separate:
the webview protocol's lowercase light/dark differs from the serializer's
MermaidTheme ('Light'/'Dark'/'Print'). The MermaidPreviewPanel dropdowns keep
their explicit {value,label} lists — values are already type-bound to the
canonical types, and the lists carry deliberate disabled/partial UI states.

The WebviewPanelManager singleton-encapsulation half of 8.4 is deferred to the
UX phase: it's ~30 call sites across extension.ts/panel.ts, the same files the
UX rework touches (cf. deferred 6.3/6.4). Group 8 is optional spin-offs.

Behavior-preserving: exporters 161/161, extension 638/638, typecheck clean.
…8.5)

The symbols tree returned a file's symbols flat — a class and its methods as
siblings. Nest them via the existing StoredSymbol.enclosingSymbolId: a class/
interface renders collapsible with its members as children, member-less symbols
stay leaves. A symbol whose enclosing id is absent from the file is surfaced at
top level rather than dropped; a malformed enclosing cycle is guarded so the
recursion can't loop. getChildren returns a symbol node's nested members instead
of always []. Extension 640/640 (two new tests for nesting + orphan).
@dgtalbug
dgtalbug marked this pull request as ready for review June 7, 2026 10:37
@dgtalbug
dgtalbug merged commit a898290 into main Jun 7, 2026
16 of 17 checks passed
@dgtalbug
dgtalbug deleted the chore/stability-audit-pre-ux branch June 7, 2026 10:37
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Jun 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backend stabilization: comment hygiene, ARCH-rule enforcement, decomposition (pre-UX cut)

2 participants