Conversation
# Conflicts: # .gitignore # Cargo.lock
Two audit documents recording the Wave 10 and follow-up work: - PERFORMANCE-AUDIT.md: planner diff -44%% via Vec capacity hints + BTreeSet adjacency + index-lookup sort - PERFORMANCE-AUDIT-FOLLOWUP.md: SeaORM FK target cache + entity_count optimization (1.08x-1.90x on new benches); Task D reverted; skipped items documented
Empty .gitkeep files reserve apps/vscode-extension/ and apps/zed-extension/ for Session B scaffolding (VSCode + Zed extensions). LICENSE already at workspace root satisfies Zed's Oct 2025 license requirement.
Pure data layer for the LSP — no LSP handlers yet: - ParserPool wraps tree-sitter-json + tree-sitter-yaml in Mutex<Parser> (Parser is !Send; V1 full reparse is fine for <5KB model files) - DocumentState couples FullTextDocument (UTF-16-aware) with Tree - DocumentStore is a DashMap<Uri, DocumentState> — justified hot path exception to BTreeMap policy; documented inline - Backend now holds Arc<DocumentStore>; handlers come in W2-T2 lsp-textdocument 0.5 uses upstream lsp_types 0.97 directly (distinct from tower-lsp-server's re-exported ls_types), so lsp-types is pulled in as a direct dependency for change-event construction at the data layer.
…kspace index - position.rs: UTF-16 <-> byte offset + ls_types <-> lsp_types bridges - workspace_index.rs: BTreeMap<table_name, Uri> via tree-sitter walk - store.rs: with_doc() accessor returning (text, tree) - backend.rs: did_open/did_change/did_close handlers + reindex helper Property-style position tests cover CJK + emoji surrogate pairs.
- diagnostics/ module is LSP-types-free domain layer - 3-tier validation: tree-sitter syntax → serde parse → planner validate_schema - mapper translates DomainDiagnostic → ls_types::Diagnostic at I/O seam - Backend wires publish on did_open/did_change, clears on did_close - Diagnostic codes: syntax-error, parse-error, validate-schema
- hover/: column metadata + FK target preview markdown - definition/: cross-file FK ref_table → target file location - Backend declares hover_provider + definition_provider - All domain modules LSP-types-free; bridges in position.rs
…e refs) - completion/ module is LSP-types-free domain layer - Context detection via tree-sitter key path ancestry - Hardcoded vespertide schema knowledge (V1; V2 may read schemas.json) - Cross-file ref_columns: deserialize target table, list its columns - Sort priority follows sqls pattern (specific > generic) - New backend handler + completion_provider capability
Drift detection — unique to vespertide-lsp, no competitor offers this: - Loads models + applied migrations via vespertide-loader - Reconstructs baseline via schema_from_plans - Diffs against current models; emits Info diagnostic per drifted table - Pure file-based — no live DB connection required Formatting: - JSON: serde_json pretty (2-space indent), round-trip semantic equivalence - YAML: serde_yaml default - Falls through silently on parse errors (diagnostics surface those)
Triggers on tag push matching lsp-v* (or workflow_dispatch). Builds: - linux-x86_64 / linux-aarch64 (via cross) - darwin-x86_64 (macos-13) / darwin-aarch64 (macos-latest) - windows-x86_64 (msvc) Packages as tar.gz (Unix) or zip (Windows), with SHA256. Uploads assets to the matching GitHub Release via softprops/action-gh-release@v2. Consumed by Zed extension's latest_github_release() lookup.
Scaffolds apps/vscode-extension/ with: - package.json: vscode-languageclient 9.0.1, esbuild 0.28, vsce 3.9 - engines.vscode ^1.105.0 (2026-05 baseline) - contributes.languages: vespertide-json + vespertide-yaml with file glob patterns - src/extension.ts: LSP client launch with stdio transport, binary resolver (vespertide.serverPath override -> bundled platform-specific binary) - Commands: vespertide.restartServer - Status bar item showing connection state - Platform-specific binaries via bin/<platform>/ (populated by Session B Wave 9 CI) - DevFive-branded README
Scaffolds apps/zed-extension/ as a standalone crate (NOT workspace member):
- Cargo.toml: cdylib + zed_extension_api 0.7.0, edition 2021 (Zed convention)
- workspace Cargo.toml: exclude = [\"apps/zed-extension\"] to preserve edition + target
- extension.toml: registers vespertide-lsp language server for JSON + YAML
- src/lib.rs: language_server_command + GitHub Release binary auto-download
- PATH lookup -> cached binary -> download from latest GH Release
- Cleans up old versions on update
- Pure asset-matching unit test
- languages/{vespertide-json,vespertide-yaml}/config.toml: file associations
- LICENSE: Apache-2.0 (REQUIRED by Zed registry since Oct 2025)
- DevFive-branded README
Triggers on tag push matching vscode-v* (or workflow_dispatch with lsp_tag input). 5-platform matrix: - Downloads matching vespertide-lsp asset from latest (or specified) lsp-v* GH Release - Extracts to apps/vscode-extension/bin/<platform>/ - Builds via bun + esbuild - Packages platform-specific .vsix via vsce - Publishes to VS Code Marketplace (VSCE_PAT) + Open VSX (OVSX_PAT) - Uploads .vsix to the vscode-v* GH Release for manual install
Documents three release channels with their tag patterns and workflows: - lsp-v* -> cross-compile + publish 5 binaries to GH Release - vscode-v* -> bundle binaries into platform-specific VSIX, publish to Marketplace + Open VSX - zed-v* -> manual PR to zed-industries/extensions (with layout fallback) Includes prerequisites, rollback procedures, and pre-release vs stable versioning convention.
Hardens vespertide-lsp's pure compute_* domain functions against arbitrary byte input: - compute_diagnostics / compute_hover / compute_definition - compute_completion / format_text Sweeps byte offsets and both JSON+YAML formats per input. Wired into the existing nightly fuzz workflow.
RUSTDOCFLAGS=-D warnings cargo doc fails on a public->private intra-doc link (rustdoc::private_intra_doc_links). The macro entry doc referenced the private vespertide_migration_impl via a doc-link; demote it to a plain code span. Doc-only change, no behavior delta.
…e 100% gate The --fail-under 100 tarpaulin gate was non-deterministic: the same commit measured 99.81% on CI vs 99.97% locally with disjoint uncovered-line sets. Root causes: (1) parallel test execution + LLVM coverage instrumentation give slightly different line attribution per run/machine; (2) proptest branch coverage is seed-random (proptest 1.x has no seed env var). Pin RUST_TEST_THREADS=1 for stable attribution and PROPTEST_CASES=1024 so property-test branches are hit every run. Deterministic source-level coverage of must-cover branches is handled by unit tests, not env.
…er 100 gate The CI coverage job reported 21 deterministic uncovered lines (identical across runs once RUST_TEST_THREADS=1 stabilised attribution). Add focused deterministic unit tests (NOT proptest-seed-dependent) driving each branch: - lsp: locator missing-constraint fallback, network simple types, drift models-load-failure path, inlay-hint non-scalar ref_columns, percent-decode valid triplet, find_all URI/range sort, classify_yaml non-scalar type walk, symbols table emission + YAML quoted-range trim - planner: check_expr_parser literal-start/keyword/eat_keyword arms, check_self_contradiction flatten_and leaf branch, schema PK-presence - cli/core/query: erd dot relationship label, normalize idempotence (fixed fixture), MySQL FK ON DELETE/ON UPDATE 3-backend rstest cargo test green across all 5 crates; fmt/clippy/line-budget clean.
Adds a direct test exercising every DOT-record metacharacter escape arm plus the plain passthrough arm in escape_record_field. Real branch coverage of a previously test-less escaping path.
…/query
Genuine missing tests:
- planner/check_expr_parser: OR/AND second-operand unparseable paths
- planner/check_self_contradiction: OR-conjunct skip in group_predicates_by_column
- planner/schema: nullable primary-key column rejection
- lsp/position: has_windows_drive_prefix (call site is cfg!(windows)-gated)
- lsp/{drift::compute,references::search,symbols}: path_to_uri leading-slash branch
Eliminate defensive/unreachable branches (mirrors symbols.rs while-let pattern):
- check_expr_parser: drop unreachable parse_predicate guard + dead bump()
- unwrap_yaml else (types/inlay_hints/classify_yaml): fused while-let
- locator: fuse pair_key_matches let-else; symbols: drop dead let _ = stripped
Restructure LLVM attribution-flaky regions to single coverage regions:
- cli/erd/dot.rs: escape arm -> escaped.extend
- query/add_constraint/foreign_key: closure chains -> explicit for loops
- type_narrowing: equal-length/Varchar->Char boundary + exact per-backend impact strings (verified 0 missed) - check_default: per-op boundary tests for apply_op_i64/f64/str/bool, evaluate_op + literal_equals arms, incl. exact-EPSILON (1.0+f64::EPSILON) cases for the float-tolerance < comparisons (verified 0 missed) - check_strengthening: AND/OR conjunct set-logic, BETWEEN narrowing bound tests, exact-EPSILON literal_equals (verified 0 missed); exclude the equivalent classify_strengthening || guard via mutants.toml - check_expr_parser: trailing-operator/incomplete-exponent EOF (buffer over-read guards) + 70-group sequential-paren depth-leak test
…lent The *_par_*_threshold() functions in parallel_config.rs (planner + query) are perf-only dispatch knobs: replacing the returned threshold with 0/1 only changes when the Rayon path is taken, and the sequential vs parallel paths produce byte-identical output. Same category as the existing E1 cmd_export perf-threshold exclusion.
- topological_sort_tables: cycle error lists only the cyclic tables (pins the not-yet-placed filter !result.any(name == t.name)) - sort_delete_tables: child-before-parent FK delete ordering (pins the <=1 short-circuit, Kahn's *degree -= 1 decrement, and == 0 enqueue) - sort_enum_default_dependencies: no reorder when old default is not a removed enum value (pins the &&); exclude the equivalent < -> <= index compare (two distinct action indices, never equal)
find_plan_violations / find_missing_fill_with / find_missing_enum_fill_with / find_schema_violations / diff_schemas / build_plan_queries all dispatch sequential vs Rayon on len() < *_par_*_threshold(). Mutating < only changes the path, not the output (both paths proven identical by result tests). Perf-only equivalents, same category as the E1 cmd_export exclusion.
…tch numeric label - check_self_contradiction: eq-then-ne and ne-then-eq same-literal contradictions (pins both disjuncts of the equality-vs-negation check); exclude the equivalent self-pair loop (i+1).. -> (i*1).. - check_type_mismatch: numeric-column mismatch renders numeric(P, S) label (pins complex_type_label Numeric arm); exclude the (Json,_) / (Custom,_) arms that duplicate the _ => false catch-all - pk_additions: exclude the NewColumns/Mixed arm (both -> continue)
…to-inc PK guards - fk_addcolumn_nullable: an out-of-line FK on a different column of the same table must not implicate an unrelated AddColumn (pins the table&&col match against a || mutant) - sequence_exhaustion: a composite (2-column) auto-increment PK is not a single-sequence exhaustion risk (pins columns.len()==1 in both the AddConstraint and CreateTable paths)
…on/constraint_ops - constraint_type_changes: a PK-less CreateTable must not absorb a PK removal (pins the CreateTable PrimaryKey match guard against a -> true mutant) - drop_resolution: rename candidates scoped to the dropped column's table (pins add_table == table guard against a -> true mutant) - apply/constraint_ops: clear_inline_constraint_fields clears the NAMED PK column only (pins &c.name == col_name against !=); exclude the equivalent clear_index_fields < -> <= (filtered == names when nothing removed)
- core: validate_unique_column_names accepts distinct names (pins the !seen.insert negation); exclude normalize_proptest.rs (proptest oracle behind feature=arbitrary, test infra) - loader: non-extension files are ignored by collect_model_paths / collect_migration_paths (and their _internal variants) - pins the is_file() && has_*_extension filter against a || mutant - loader: exclude the perf-only len() < LOAD_FILES_PAR_THRESHOLD dispatch
- foreign_key_constraint_exists: an inline single-column FK is still materialized despite a pre-existing composite FK sharing the first column (pins the columns.len()==1 && guard against a || mutant) - index_constraint_exists: an inline named index is deduped against an existing same-name table-level index (pins the (Some,Some)=>n1==n2 arm against deletion and == -> !=)
Kills: - timezones: validate_offset :59 boundary, parse_two_digit digit guards - fill_with::wrap_if_spaces / narrowing::quote_value_for_target half-quoted && - svg/model: measure_table_width exact title-dominated width, build_boxes first-PK-row tracking; svg/layout: rebalance_groups boundary split - cmd_revision_core: single Edge#1 error stays bare (not Multiple) Exclusions (equivalent / interactive / display-only, see mutants.toml): - compute_ranks > -> >= (redundant assign) and n+1 -> n-1 (DAG converges) - print_fill_with_header/footer, print_strategy_descriptions (pure println) - prompt_drop_resolution (interactive Select dialoguer)
…migration Adding a NOT-NULL, no-default, non-FK column requires an interactively collected fill_with value. A value-supplying mock provides a sentinel; the written migration must embed it. Pins the if !missing.is_empty() gate (mod.rs:492) - a delete-! mutant skips collection, omitting the value.
… exclude regex) The first mutation CI pass left 3 ineffective fixes: - svg/model build_boxes: original test asserted pk_row==Some(1), but the loop overwrites pk_row on the later PK row so the || mutant also yields Some(1). Use a PK-less table (orig None vs mutant Some(0)) - verified kills the mutant. - sequence_exhaustion AddConstraint guard: baseline_existing_risky_pk suppressed the smallint PK so the mutant emitted nothing. Use a safe bigint baseline PK with risky non-PK columns - verified kills the mutant. - check_type_mismatch:366 exclude_re used .Json (one char) but the arm is (SimpleColumnType::Json, _); widen to .* in is_definitely_mismatch.
The earlier test only exercised the (Some,Some) name-match arm (line 394). The surviving mutant is line 395, the (None,None) arm comparing UNNAMED indexes by columns (cols.as_slice() == columns). Add a dedup test for an inline \index: true\ (auto-name -> None) against an existing unnamed table-level index on the same columns; verified it fails on the != mutant.
The original gate was red on BOTH 155 missed AND 55 timeout entries; the timeouts were masked on shards 4/9/10 by a transient install-action 504. These 24 mutants replace a monotonic advance (i += 1 / self.pos += 1) or the scanner's loop condition with a non-advancing op -> infinite loop. cargo-mutants flags them TIMEOUT (a hang the test can't assertion-catch). Exclude the tokenize_spanned scanner advances + line-408 loop condition, the parse_predicate IN-list advance, and the rebalance_groups loop counter.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.