Skip to content

Fix existing-database upgrades and strengthen cross-platform toolkit CI - #113

Merged
MelbourneDeveloper merged 100 commits into
mainfrom
fix/nap-migration-blockers
Oct 3, 2026
Merged

MelbourneDeveloper merged 100 commits into
mainfrom
fix/nap-migration-blockers

Conversation

@MelbourneDeveloper

@MelbourneDeveloper MelbourneDeveloper commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

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?

  • Additive nullability operations, foreign-key repair on existing tables, semantic RLS predicate comparison, and SQLite table rebuilds with transactional foreign-key validation.
  • SQL Server table/constraint migration support; declarative PostgreSQL/SQLite guard triggers; reflection-free YAML/JSON migration serialization and native migration CLI packaging.
  • LQL CTEs, derived-table joins, shared subquery layout and qualifier/paging handling across PostgreSQL, SQLite and SQL Server; matching parser/LSP updates.
  • Shared reporting API registration, provider-aware connections, HS256 bearer validation, and live cross-provider report/API tests.
  • Release manifests, version-stamping tests, signed native binaries and platform VSIX workflows, Homebrew/Scoop publishing, website release pages, and security/dependency checks.

What Was Changed or Deleted?

  • Normal migration now relaxes NOT NULL and creates missing foreign keys after their dependencies exist. A rerun repairs a database where a prior attempt added only the column.
  • Policies with unchanged names reconcile changed USING/WITH CHECK clauses and scope. PostgreSQL catalog deparsing and SQLite trigger/view readback preserve convergence. Destructive cleanup retains every declared foreign-key relationship.
  • SQLite rebuilds validate foreign keys before commit and preserve rollback safety, indexes, triggers and additive-only columns.
  • Reuse transaction, code-generation, SQLite type mapping, sync repository/mapping and test-fixture logic. Reporting rejects malformed/future JWT claims and recognizes PostgreSQL connection-string aliases.
  • Upgrade Exhaustion to 1.0.1 with the analyzer enabled. Bound .NET heap/concurrency and test commands; constrain formatter discovery and handle macOS file-watcher/dSYM hangs. Keep Colima Docker configuration scoped to Rust tests.
  • Consolidate SQL Server generation under the CLI without requiring obsolete source-generator configuration; tighten cross-dialect query tests and coverage floors. Share platform resolution and process-wide migration CLI console capture to remove platform coverage differences and parallel writer races.
  • Patch js-yaml advisories with 4.3.2/3.15.2 and async-trait with 0.1.92 for Rust 1.99 Clippy compatibility. Replace double entity unescaping with the entities 8.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?

  • Literal make ci passed 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.
  • MigrationPlatformRegressionTests exercise nullable upgrades, new/existing-column foreign keys, partial-migration repair and destructive preservation on real SQLite, PostgreSQL and SQL Server databases.
  • PostgresUpgradeBlockersTests, PostgresPolicyCatalogRoundTripTests, PostgresRlsPhaseUpgradeTests and SQLite RLS tests verify predicate changes, row visibility and clean reruns.
  • Reporting security regressions were reproduced before the fixes and now pass all 13 cases; the SQL Server source-generator delegation regression also passed after reproducing its obsolete-configuration error.
  • Release-stamp tests check dry-run immutability, stable/prerelease versions and all declared version carriers using the actual stamping CLI. Four isolated DocFX CLI fixtures prove single-pass entity decoding; the website build passes.
  • RejectedRequest_DoesNotLogUserControlledPath reproduced 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.
  • Rust coverage now explicitly uses LLVM on both Linux and macOS, retaining the 98% floor and exclusions; this removes the former ptrace/LLVM metric mismatch. Fresh GitHub checks validate the Linux run.
  • Deslop 0.36.0 passes at the documented initial adoption ceiling of 39.44%, replacing the unmeasured 5% setting introduced by this PR. Identical configuration measures main at 44.20213% (47,489 duplicated LOC) and this branch at 39.43497% (45,993 duplicated LOC). The written justification and reproduction are in CI spec. All findings remain visible; no new exclusions were added. Genuine debt remains, and subsequent changes must ratchet the ceiling down. Assertion false positives remain reported in Deslop #534.
  • Existing native-AOT smoke tests still report three skips when no native binary is provided; managed CLI migration regressions run normally. Remote PR checks must all pass before merging.

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

  • No public API signature removals.

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.

MelbourneDeveloper and others added 30 commits December 28, 2025 19:30
- 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].
@github-advanced-security

Copy link
Copy Markdown

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:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Comment thread .github/workflows/ci.yml Fixed
Comment thread .github/workflows/ci.yml Fixed
Comment thread .github/workflows/ci.yml Fixed
Comment thread Reporting/Nimblesite.Reporting.Api/ReportingApi.cs Fixed
@MelbourneDeveloper
MelbourneDeveloper enabled auto-merge (squash) October 3, 2026 18:12
@MelbourneDeveloper
MelbourneDeveloper merged commit 62b3062 into main Oct 3, 2026
11 checks passed
@MelbourneDeveloper
MelbourneDeveloper deleted the fix/nap-migration-blockers branch October 3, 2026 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment