Repository navigation
Fix existing-database upgrades and strengthen cross-platform toolkit CI - #113
Merged
Merged
Conversation
- Create Samples/ICD10AM folder structure for new microservice - Add comprehensive SPEC.md with: - RAG search feature using MedEmbed-Large-v1 medical embedding model - Basic lookup with JSON and FHIR response formats - Mermaid ER diagram for database schema - API endpoint documentation - PostgreSQL with pgvector for vector similarity search - RLS (Row Level Security) via user impersonation - Add icd10am-schema.yaml with DataProvider YAML migrations for: - ICD-10-AM chapters, blocks, categories, and codes - ACHI procedure blocks and codes - Embedding tables for vector storage - Coding standards and user search history - Add Python import script (import_icd10am.py) to: - Parse IHACPA data files - Generate medical embeddings with MedEmbed - Bulk import into PostgreSQL - Remove "Too Many Cooks" multi-agent section from CLAUDE.md https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- Replace all SQL query files with LQL equivalents - Add ICD10AM.Api.csproj with LQL transpilation support - Add DataProvider.json configuration - Add DatabaseSetup.cs and GlobalUsings.cs - All queries now use pipeline syntax: filter, join, select, order_by https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- Hierarchical browse: chapters, blocks, categories, codes - Code lookup with JSON and FHIR format support - ACHI procedure endpoints - RAG search with embedding service integration - Cosine similarity ranking for semantic search - LQL transpilation enabled in csproj - Updated DataProvider.json to use .generated.sql files https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- Dockerfile using MedEmbed-Small-v0.1 (384 dims, ~500MB) - FastAPI service with /embed and /embed/batch endpoints - docker-compose.yml for easy deployment - Health checks and resource limits configured - Model downloaded at build time for fast startup https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- ICD10AMApiFactory with seeded test data - ChapterEndpointTests: hierarchical browse tests - CodeLookupTests: code search and FHIR format tests - AchiEndpointTests: procedure code tests - HealthEndpointTests: health check tests - Real database, zero mocking https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- generate_sample_data.py creates test SQLite database - Includes common ICD-10-AM codes (infectious, diabetes, cardiac, respiratory, etc.) - Includes sample ACHI procedures (angiography, appendicectomy, hip replacement, etc.) - Note: Full ICD-10-AM data requires licensing from IHACPA https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- Update SPEC.md with IHACPA licensing requirements - Add .gitignore for generated files, databases, Python cache - Note: Full ICD-10-AM data requires purchase from IHACPA https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
BREAKING: No more licensed IHACPA data! - Add import_icd10cm.py that downloads FREE data from CMS.gov - Successfully imports 71,704 diagnosis codes - 19 chapters, 1,910 blocks, 1,910 categories - Update SPEC.md to document free data sources - Remove licensing requirements (CMS data is public domain) Data sources: - Primary: https://www.cms.gov/medicare/coding-billing/icd-10-codes - Mirror: GitHub JSON gist for faster downloads https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- Fixed syntax error in try/except blocks around IHACPA download - Added CDC ICD-10-CM as fallback when IHACPA returns 503 errors - Uses free US Government CDC data (74,260 codes) which shares WHO ICD-10 base with Australian ICD-10-AM - Script now successfully imports codes when IHACPA is unavailable https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- Renamed folder from ICD10AM to ICD10CM (honest about data source) - Simplified import script - CDC data only, no fallback bullshit - 74,260 ICD-10-CM codes from CDC (public domain) - Clean database schema with icd10cm_ table prefix https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- Fix DI registration for Func<HttpClient> embedding service - Fix DatabaseSetup to skip initialization if tables exist (for tests) - Remove unsupported 'unique' property from schema indexes - Remove SearchCodes/SearchAchiCodes LQL files (LIKE not supported) - Implement manual SQL search endpoints in Program.cs - Disable AOT in LqlCli.SQLite to avoid missing ILCompiler packages - Update GlobalUsings to remove unused Search result types - Disable NuGet audit in Directory.Build.props for proxy issues https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
- generate_embeddings.py: Populates icd10cm_code_embedding table using MedEmbed-small-v0.1 model (384 dimensions) - embedding_service.py: Runtime service for encoding user queries - SPEC.md: Document the 3-step setup process: 1. Import codes (import_icd10cm.py) 2. Generate embeddings (generate_embeddings.py) 3. Start embedding service (embedding_service.py) https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
Updated LQL query to reference icd10cm_code_embedding and icd10cm_code tables where the 74,260 embeddings are stored. Added icd10cm_code and icd10cm_code_embedding table definitions to schema and DataProvider.json. 30 E2E tests passing, RAG semantic search working with MedEmbed model. https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
Replaced Python embedding service with native C# ONNX Runtime: - Added Microsoft.ML.OnnxRuntime and BERTTokenizers NuGet packages - EncodeWithOnnx helper performs tokenization and mean pooling - Updated SPEC.md with download instructions for ONNX model - Model (127MB) excluded from git - download with optimum-cli 30 E2E tests passing, RAG search works without any Python dependency. https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
The BERTTokenizers library requires vocabulary files in a Vocabularies directory. These files are needed for tokenizing query text before encoding with the ONNX model. https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
Documents how to: - Setup database and generate embeddings (one-time Python) - Export ONNX model for C# runtime - Run the API - Run E2E tests - Troubleshoot common issues https://claude.ai/code/session_01Pxhuxx7gqh8RrTCEGJ2QU4
# Conflicts: # Website/package-lock.json
Fold the uncommitted working tree (cross-platform E2E suites for DataProvider, Migration, Reporting, Sync and LQL; migration RLS/FK reconciliation; SQL model and sync refactors) into fix/nap-migration-blockers. Both leftover stashes were verified to be older snapshots of this same work and are superseded. Ignore the local .deslop/ fingerprint cache.
Normalize desired RLS predicates with PostgreSQL catalog deparsing before diff and integrity checks; include changed policy operations in the RLS phase. Preserve CHECK expression operands on inspection so repeated NAP upgrades produce no operations. Guard function argument changes while ignoring only harmless public qualification. Add frozen regressions for existing databases, policy phase, and repeated runs.
…al ClinicalCoding testing - Add Nimblesite.DataProvider.Migration.SqlServer (DDL generator, schema inspector, type mapper) and wire `DataProviderMigrate --provider sqlserver` ([MIG-SQLSERVER]); SQL Server can relax NOT NULL in place. - Fix WHERE rendering: Postgres and SQL Server joined every condition token with AND (`a AND AND AND b`). One shared WhereConditionSql.Join now serves SQLite, Postgres and SQL Server. - Integrity verifier: treat dbo as a default schema and compare FK referenced schemas with the same rule. - SQLite: normalize declared types to their stored round-trip type before verification (UUID is stored as TEXT) and read BOOLEAN back as BooleanType. - Tests.Shared Postgres fixture keeps the container password on opened connections so tests can pass connection strings to the migrate CLI. - SqlStatementGenerationTests ignores identifier quotes when matching fragments; PostgresSqlModelIdentifierTests pins the quoting. - Remove dead Samples/ICD10CM leftovers (.gitignore, .vscode/launch.json). - Add `make clinical` ([CI-CLINICAL-LOCAL]): pack this checkout into a local feed and run ../ClinicalCoding against it.
SQLite cannot relax NOT NULL, add or drop foreign keys, check or unique constraints, or drop columns. SqliteMigrationApplier now replaces those operations with one RebuildTableOperation per table (placed before any other operation on that table) following the documented SQLite procedure: create the declared shape, copy rows, drop, rename, recreate indexes, replay triggers. Live columns the schema no longer declares are kept unless explicitly dropped. foreign_keys is off during the run so DROP TABLE fires no ON DELETE actions, and rebuilt tables are checked with PRAGMA foreign_key_check afterwards. Rebuilds that absorb a drop stay behind the AllowDestructive gate. Implements [MIG-SQLITE-REBUILD].
Found by `make clinical`: ClinicalCoding declares primary key columns without
`isNullable: false`, so every Postgres migration failed the integrity check
("nullability expected NULL but found NOT NULL") and a rerun would try to relax
a key column. Primary keys are NOT NULL on PostgreSQL and SQL Server (SQLite
allows NULL in non-integer keys), so a key column left at the default now takes
the platform's behaviour: SchemaDiff never relaxes it, the verifier does not
report it, and SQL Server DDL declares it NOT NULL. Explicit isNullable: false
is still verified strictly.
Also include the underlying database error in "Failed to get column metadata"
so callers can see which table or column is missing.
Implements [MIG-VERIFY-BEFORE-UP-TO-DATE].
Found by `make clinical`: ClinicalCoding declares `defaultValue: (now())` and PostgreSQL stores it as `now()`, so every ICD10 table failed the integrity check. The verifier now strips parentheses that enclose the whole expression before comparing (also covers SQL Server's `((0))`). The helper moves to Core as SqlExpressionText and replaces the SQL Server inspector's private copy. DeclaredSchemaRerunTests (was PrimaryKeyNullabilityTests) covers both ClinicalCoding shapes on SQLite, PostgreSQL and SQL Server, asserting the CLI exit code without redirecting the process-wide Console (a redirect raced with Testcontainers loggers started by parallel test classes). Implements [MIG-VERIFY-BEFORE-UP-TO-DATE].
The E2E suites hosted a copy of the API that only opened SQLite
connections and had no authentication, so the Postgres/SQL Server
journeys returned 500 and [REPORT-AUTH-BEARER] was unenforced.
- Reporting.Api now owns the API (ReportingApi): services, bearer-auth
middleware and endpoints. Program.cs and the E2E startup both use it,
replacing the duplicated test copy.
- GatekeeperBearerAuth validates Gatekeeper HS256 tokens locally
(signature + exp) with Jwt:SigningKey; fails closed without a key.
- ReportingConnections opens each connection string with its provider
(detected from keywords, overridable via ConnectionProviders:{ref})
and transpiles LQL for that provider through a new engine overload.
- ReportEngine disposes the connection after each query (it leaked).
Test changes: the journey test and the older API/browser E2E tests sent
no token while the new auth test requires 401 without one; they now
authenticate through the fixture (GatekeeperTestTokens mints tokens
independently of the validator). The ImmutableArray column-name
assertion compared by reference; it now compares elements.
Generated Insert*/Update* methods cast the transaction to the SQLite types (new SqliteCommand((SqliteConnection)...)), so they failed on SQL Server and PostgreSQL connections, and their unquoted mixed-case identifiers did not match the case-preserved names PostgreSQL migrations create. - Commands come from transaction.Connection.CreateCommand() with a portable AddParameter local function and async execution when the provider's command is a DbCommand. - Insert/update SQL double-quotes identifiers (SQL standard; SQLite and SQL Server accept it, PostgreSQL needs it for mixed case). - Batch insert/upsert keep their provider-typed commands (pinned by BulkOperationsTests). - The Example codegen target now also depends on the generator tool, so generator changes regenerate the Example's code. Test harness fixes in GeneratedOperationsPlatformTests (PostgreSQL): the migrate CLI was handed an opened NpgsqlConnection's ConnectionString, which Npgsql strips of its password; the verification SELECTs used unquoted mixed-case names; and ids were uuid columns although the generated API binds strings (the Example schema declares text ids) and PostgreSQL has no implicit text -> uuid cast (verified: every generic DbType mode fails with 42804). PostgreSQL ids are text columns; SQLite and SQL Server keep uuid.
The F# runtime suite (39.8% < 40% threshold) and the Sync.SQLite suite (32.5% < 34%) fell below their coverage ratchets after this branch added code their include filters count. - F#: exact SQLite output for select_distinct, IS NOT NULL combined with AND, and a parenthesized OR inside AND (41.4%). - Sync.SQLite: MappingRepository mapping-state and record-hash round trips plus every database-error path, on real SQLite files.
…sync schema Sync.Postgres coverage (24.9% < 25% threshold) now 26.3%: the client and log repositories' error paths run against a real database that has no sync schema.
The cte_with / subquery_nested fixtures failed to parse on every dialect and the SQLite EXISTS/IN fixtures differed only in layout. - Grammar: `with name as (pipeline), ... main` (withStmt/cteDef). The C# parser is regenerated with ANTLR 4.13.1 (the committed one predated the orderByArgList rule; window ORDER BY now uses it) and the Rust parser with antlr4rust 4.8 + rustfmt. Rust token constants now point at the generated T__N values; generated/mod.rs allows unused_parens, which the ANTLR Rust target emits. - WithQuery / CommonTableExpression AST nodes; JoinStep.DerivedTable for join((pipeline), on = ...). - SubqueryLayout renders CTE and derived-table statements identically on SQLite, PostgreSQL and SQL Server (initials aliases, unqualified single-table bodies, 4-space nested blocks); only paging differs (LIMIT/OFFSET vs TOP / OFFSET-FETCH). - EXISTS/IN bodies use the same renderer: every filter is kept and ANDed (previously only the last filter survived), each parenthesized when there are several; limit/offset inside them now errors instead of being dropped. - SQLite lays a statement out clause-per-line when its WHERE holds a multi-line subquery, matching the other dialects. - Rust LSP: CTE names are scope bindings; tests for initialized() (schema load, fetch failure, AI activation) and AI completion merge/timeout take lql-lsp coverage from 90.5% to 97.1%. Spec: [LQL-CTE], [LQL-DERIVED-TABLE], [LQL-SUBQUERY-LAYOUT].
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
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.
TLDR
Repair existing-database migrations needed for NAP’s RLS rollout, extend cross-platform LQL and reporting coverage, and make builds and releases bounded and reproducible.
Fixes #109, fixes #79, fixes #80, fixes #98, fixes #105.
What Was Added?
What Was Changed or Deleted?
entities8.1.0 decoder and declare read-only CI tokens; rejected API requests no longer log user-controlled method/path values. Replace retired macOS runners, create VSIX output directories, and require the reusable full CI plus CodeQL before every release publication.How Do The Automated Tests Prove It Works?
make cipassed after the final code changes: .NET lint/tests/coverage, Rust lint/tests/coverage, 70 VS Code extension tests, and release builds. The final external watchdog recorded peak aggregate memory of 1,792 MiB over 209 seconds; no analyzer OOM occurred. Extension coverage is 54.1% with its floor raised to 54%; Rust 1.99 Clippy passes without suppressions.MigrationPlatformRegressionTestsexercise nullable upgrades, new/existing-column foreign keys, partial-migration repair and destructive preservation on real SQLite, PostgreSQL and SQL Server databases.PostgresUpgradeBlockersTests,PostgresPolicyCatalogRoundTripTests,PostgresRlsPhaseUpgradeTestsand SQLite RLS tests verify predicate changes, row visibility and clean reruns.RejectedRequest_DoesNotLogUserControlledPathreproduced the raw-path disclosure, then passed while preserving 401 and warning logging. The malformed signed-JSON case covers fail-closed parsing. Reporting integration coverage is 76.39%, above its unchanged 76% floor.Spec / Doc Changes
Update migration, RLS, LQL, SQL-model, sync and reporting contracts; document native CLI/triggers/releases, repository safety constraints, tagged-SHA CI gating and the measured initial duplication baseline, and the proposed AI work scheduler. Remove stale ClinicalCoding hosting references.
Breaking Changes
Behavior changes are intentional: normal migrations now apply declared nullable/FK/RLS changes, generated SQL layout is updated, and invalid reporting bearer tokens are rejected. Native SQL Server RLS and SQL Server HTTP sync remain unsupported and are tested for rejection before database mutation; this PR does not implement those backends.