Skip to content

Commit 6040eef

Browse files
Point to nuget packages
1 parent 95da6e5 commit 6040eef

80 files changed

Lines changed: 361 additions & 369 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/ci-prep/SKILL.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ name: ci-prep
33
description: Prepares the current branch for CI by running the exact same steps locally and fixing issues. If CI is already failing, fetches the GH Actions logs first to diagnose. Use before pushing, when CI is red, or when the user says "fix ci".
44
argument-hint: "[--failing] [optional job name to focus on]"
55
---
6-
<!-- agent-pmo:d58c330 -->
6+
<!-- agent-pmo:29b9dcf -->
77

88
# CI Prep
99

1010
Prepare the current state for CI. If CI is already failing, fetch and analyze the logs first.
1111

1212
## Arguments
1313

14-
- `--failing` -- Indicates a GitHub Actions run is already failing. When present, you MUST execute **Step 1** before doing anything else.
14+
- `--failing` Indicates a GitHub Actions run is already failing. When present, you MUST execute **Step 1** before doing anything else.
1515
- Any other argument is treated as a job name to focus on (but all failures are still reported).
1616

1717
If `--failing` is NOT passed, skip directly to **Step 2**.
1818

19-
## Step 1 -- Fetch failed CI logs (only when `--failing`)
19+
## Step 1 Fetch failed CI logs (only when `--failing`)
2020

2121
You MUST do this before any other work.
2222

@@ -40,23 +40,23 @@ gh run view "$RUN_ID" --log-failed
4040

4141
Read **every line** of `--log-failed` output. For each failure note the exact file, line, and error message. If a job name argument was provided, prioritize that job but still report all failures.
4242

43-
## Step 2 -- Analyze the CI workflow
43+
## Step 2 Analyze the CI workflow
4444

4545
1. Find the CI workflow file. Look in `.github/workflows/` for `ci.yml`, `build.yml`, `test.yml`, `checks.yml`, `main.yml`, `pull_request.yml`, or any workflow triggered on `pull_request` or `push`.
4646
2. Read the workflow file completely. Parse every job and every step.
47-
3. Extract the ordered list of commands the CI actually runs (e.g., `make lint`, `make fmt-check`, `make test`, `make coverage-check`, `make build`, or whatever the workflow specifies -- it may use `npm`, `cargo`, `dotnet`, raw shell commands, or anything else).
47+
3. Extract the ordered list of commands the CI actually runs (e.g., `make lint`, `make fmt-check`, `make test`, `make coverage-check`, `make build`, or whatever the workflow specifies it may use `npm`, `cargo`, `dotnet`, raw shell commands, or anything else).
4848
4. Note any environment variables, matrix strategies, or conditional steps that affect execution.
4949

5050
**Do NOT assume the steps are `make lint`, `make test`, `make coverage-check`, `make build`.** The actual CI may run different commands, in a different order, with different targets. Extract what the CI *actually does*.
5151

52-
## Step 3 -- Run each CI step locally, in order
52+
## Step 3 Run each CI step locally, in order
5353

5454
Work through failures in this priority order:
5555

56-
1. **Formatting** -- run auto-formatters first to clear noise
57-
2. **Compilation errors** -- must compile before lint/test
58-
3. **Lint violations** -- fix the code pattern
59-
4. **Runtime / test failures** -- fix source code to satisfy the test
56+
1. **Formatting** run auto-formatters first to clear noise
57+
2. **Compilation errors** must compile before lint/test
58+
3. **Lint violations** fix the code pattern
59+
4. **Runtime / test failures** fix source code to satisfy the test
6060

6161
For each command extracted from the CI workflow:
6262

@@ -67,20 +67,21 @@ For each command extracted from the CI workflow:
6767

6868
### Hard constraints
6969

70-
- **NEVER modify test files** -- fix the source code, not the tests
71-
- **NEVER add suppressions** (`#pragma warning disable`, `// eslint-disable`, `#[allow(...)]`)
70+
- **NEVER modify test files** — fix the source code, not the tests
71+
- **NEVER add suppressions** (`#[allow(...)]`, `// eslint-disable`, `#pragma warning disable`)
72+
- **NEVER use `any` in TypeScript** to silence type errors
7273
- **NEVER delete or ignore failing tests**
7374
- **NEVER remove assertions**
7475

7576
If stuck on the same failure after 5 attempts, ask the user for help.
7677

77-
## Step 4 -- Report
78+
## Step 4 Report
7879

7980
- List every step that was run and its result (pass/fail/fixed).
8081
- If any step could not be fixed, report what failed and why.
8182
- Confirm whether the branch is ready to push.
8283

83-
## Step 5 -- Commit/Push (only when `--failing`)
84+
## Step 5 Commit/Push (only when `--failing`)
8485

8586
Once all CI steps pass locally:
8687

@@ -96,10 +97,10 @@ Once all CI steps pass locally:
9697
- Fix issues found in each step before moving to the next
9798
- Never skip steps or suppress errors
9899
- If the CI workflow has multiple jobs, run all of them (respecting dependency order)
99-
- Skip steps that are CI-infrastructure-only (checkout, setup-node/python/rust actions, cache steps, artifact uploads) -- focus on the actual build/test/lint commands
100+
- Skip steps that are CI-infrastructure-only (checkout, setup-node/python/rust actions, cache steps, artifact uploads) focus on the actual build/test/lint commands
100101

101102
## Success criteria
102103

103104
- Every command that CI runs has been executed locally and passed
104105
- All fixes are applied to the working tree
105-
- The CI passes successfully (if you are correcting an existing failure)
106+
- The CI passes successfully (if you are correcting and existing failure)

.claude/skills/code-dedup/SKILL.md

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
---
22
name: code-dedup
3-
description: Searches for duplicate code, duplicate tests, and dead code, then safely merges or removes them. Use when the user says "deduplicate", "find duplicates", "remove dead code", "DRY up", or "code dedup". Requires test coverage -- refuses to touch untested code.
3+
description: Searches for duplicate code, duplicate tests, and dead code, then safely merges or removes them. Use when the user says "deduplicate", "find duplicates", "remove dead code", "DRY up", or "code dedup". Requires test coverage refuses to touch untested code.
44
---
5-
<!-- agent-pmo:d58c330 -->
5+
<!-- agent-pmo:29b9dcf -->
66

77
# Code Dedup
88

9-
Carefully search for duplicate code, duplicate tests, and dead code across the repo. Merge duplicates and delete dead code -- but only when test coverage proves the change is safe.
9+
Carefully search for duplicate code, duplicate tests, and dead code across the repo. Merge duplicates and delete dead code but only when test coverage proves the change is safe.
1010

11-
## Prerequisites -- hard gate
11+
## Prerequisites hard gate
1212

1313
Before touching ANY code, verify these conditions. If any fail, stop and report why.
1414

15-
1. Run `make test` -- all tests must pass. If tests fail, stop. Do not dedup a broken codebase.
16-
2. Run `make coverage-check` -- coverage must meet the repo's threshold. If it doesn't, stop.
17-
3. This is a C# repo with static typing -- proceed.
15+
1. Run `make test` — all tests must pass. If tests fail, stop. Do not dedup a broken codebase.
16+
2. Run `make coverage-check` — coverage must meet the repo's threshold. If it doesn't, stop.
17+
3. Verify the project uses **static typing**. Check for:
18+
- C#: typed by default — proceed
19+
- Python: must have type annotations AND a type checker configured (pyright, mypy, or Basilisk in pyproject.toml / Makefile) — proceed
20+
- **Untyped Python: STOP. Refuse to dedup.** Print: "This codebase has no static type checking. Deduplication without types is reckless — too high a risk of silent breakage. Add type checking first."
1821

1922
## Steps
2023

@@ -30,65 +33,80 @@ Dedup Progress:
3033
- [ ] Step 6: Verification passed (tests green, coverage stable)
3134
```
3235

33-
### Step 1 -- Inventory test coverage
36+
### Step 1 — Inventory test coverage
37+
38+
Before deciding what to touch, understand what is tested.
3439

3540
1. Run `make test` and `make coverage-check` to confirm green baseline
36-
2. Note the current coverage percentage -- this is the floor. It must not drop.
41+
2. Note the current coverage percentage this is the floor. It must not drop.
3742
3. Identify which files/modules have coverage and which do not. Only files WITH coverage are candidates for dedup.
3843

39-
### Step 2 -- Scan for dead code
44+
### Step 2 — Scan for dead code
45+
46+
Search for code that is never called, never imported, never referenced.
4047

4148
1. Look for unused exports, unused functions, unused classes, unused variables
42-
2. C# analyzer warnings for unused members -- check `make lint` output
43-
3. For each candidate: **grep the entire codebase** for references. Only mark as dead if truly zero references.
49+
2. Use language-appropriate tools where available:
50+
- C#: analyzer warnings for unused members
51+
- Python: look for functions/classes with zero imports across the codebase
52+
3. For each candidate: **grep the entire codebase** for references (including tests, scripts, configs). Only mark as dead if truly zero references.
4453
4. List all dead code found with file paths and line numbers. Do NOT delete yet.
4554

46-
### Step 3 -- Scan for duplicate code
55+
### Step 3 — Scan for duplicate code
56+
57+
Search for code blocks that do the same thing in multiple places.
4758

4859
1. Look for functions/methods with identical or near-identical logic
4960
2. Look for copy-pasted blocks (same structure, maybe different variable names)
5061
3. Look for multiple implementations of the same algorithm or pattern
51-
4. Check across module boundaries -- duplicates often hide in different projects
52-
5. For each duplicate pair: note both locations, what they do, and how they differ
62+
4. Check across module boundaries duplicates often hide in different packages/projects
63+
5. For each duplicate pair: note both locations, what they do, and how they differ (if at all)
5364
6. List all duplicates found. Do NOT merge yet.
5465

55-
### Step 4 -- Scan for duplicate tests
66+
### Step 4 — Scan for duplicate tests
67+
68+
Search for tests that verify the same behavior.
5669

5770
1. Look for test functions with identical assertions against the same code paths
5871
2. Look for test fixtures/helpers that are duplicated across test files
59-
3. Look for integration tests that fully cover what a unit test also covers (keep the integration test)
72+
3. Look for integration tests that fully cover what a unit test also covers (keep the integration test, mark the unit test as redundant per CLAUDE.md rules)
6073
4. List all duplicate tests found. Do NOT delete yet.
6174

62-
### Step 5 -- Apply changes (one at a time)
75+
### Step 5 Apply changes (one at a time)
6376

64-
For each change: **change -> test -> verify coverage -> continue or revert**.
77+
For each change, follow this cycle: **change test verify coverage continue or revert**.
6578

6679
#### 5a. Remove dead code
80+
- Delete dead code identified in Step 2
6781
- After each deletion: run `make test` and `make coverage-check`
68-
- If tests fail or coverage drops: **revert immediately**
82+
- If tests fail or coverage drops: **revert immediately** and investigate
83+
- Dead code removal should never break tests or drop coverage
6984

7085
#### 5b. Merge duplicate code
71-
- Extract shared logic into a single function/module, update all call sites
86+
- For each duplicate pair: extract the shared logic into a single function/module
87+
- Update all call sites to use the shared version
7288
- After each merge: run `make test` and `make coverage-check`
73-
- If tests fail: **revert immediately**
89+
- If tests fail: **revert immediately**. The duplicates may have subtle differences you missed.
90+
- If coverage drops: the shared code must have equivalent test coverage. Add tests if needed before proceeding.
7491

7592
#### 5c. Remove duplicate tests
7693
- Delete the redundant test (keep the more thorough one)
7794
- After each deletion: run `make coverage-check`
78-
- If coverage drops: **revert immediately**
95+
- If coverage drops: **revert immediately**. The "duplicate" test was covering something the other wasn't.
7996

80-
### Step 6 -- Final verification
97+
### Step 6 Final verification
8198

82-
1. Run `make test` -- all tests must still pass
83-
2. Run `make coverage-check` -- coverage must be >= the baseline from Step 1
84-
3. Run `make lint` and `make fmt-check` -- code must be clean
99+
1. Run `make test` all tests must still pass
100+
2. Run `make coverage-check` coverage must be >= the baseline from Step 1
101+
3. Run `make lint` and `make fmt-check` code must be clean
85102
4. Report: what was removed, what was merged, final coverage vs baseline
86103

87104
## Rules
88105

89-
- **No test coverage = do not touch.** If a file has no tests covering it, leave it alone entirely.
90-
- **Coverage must not drop.** The coverage floor from Step 1 is sacred.
91-
- **One change at a time.** Never batch multiple dedup changes before testing.
92-
- **When in doubt, leave it.**
93-
- **Preserve public API surface.**
94-
- **Three similar lines is fine.** Only dedup when shared logic is substantial (>10 lines) or 3+ copies.
106+
- **No test coverage = do not touch.** If a file has no tests covering it, leave it alone entirely. You cannot safely dedup what you cannot verify.
107+
- **Coverage must not drop.** If removing or merging code causes coverage to decrease, revert and investigate. The coverage floor from Step 1 is sacred.
108+
- **Untyped code = refuse to dedup.** Untyped Python is too dangerous. Types are the safety net that catches breakage at compile time. Without them, silent runtime errors are near-certain.
109+
- **One change at a time.** Make one dedup change, run tests, verify coverage. Never batch multiple dedup changes before testing.
110+
- **When in doubt, leave it.** If two code blocks look similar but you're not 100% sure they're functionally identical, leave both. False dedup is worse than duplication.
111+
- **Preserve public API surface.** Do not change function signatures, class names, or module exports that external code depends on. Internal refactoring only.
112+
- **Three similar lines is fine.** Do not create abstractions for trivial duplication. The cure must not be worse than the disease. Only dedup when the shared logic is substantial (>10 lines) or when there are 3+ copies.

.config/dotnet-tools.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"csharpier": {
6+
"version": "1.2.6",
7+
"commands": [
8+
"csharpier"
9+
],
10+
"rollForward": false
11+
},
12+
"nimblesite.dataprovider.migration.cli": {
13+
"version": "0.2.0-beta",
14+
"commands": [
15+
"migration-cli"
16+
],
17+
"rollForward": false
18+
},
19+
"nimblesite.lql.cli.sqlite": {
20+
"version": "0.2.0-beta",
21+
"commands": [
22+
"lqlcli-sqlite"
23+
],
24+
"rollForward": false
25+
},
26+
"nimblesite.dataprovider.sqlite.cli": {
27+
"version": "0.2.0-beta",
28+
"commands": [
29+
"dataprovider-sqlite"
30+
],
31+
"rollForward": false
32+
}
33+
}
34+
}

.github/pull_request_template.md

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
1-
<!-- agent-pmo:d58c330 -->
1+
<!-- agent-pmo:29b9dcf -->
22

33
## TLDR
44
<!-- One sentence: what does this PR do? -->
55

6-
## What Was Added?
7-
<!-- New functionality, new files, new dependencies. Delete section if nothing new. -->
8-
9-
## What Was Changed or Deleted?
10-
<!-- Modified behaviour, removed code, breaking changes. -->
6+
## Details
7+
<!-- New functionality, new files, new dependencies. What changed? -->
118

129
## How Do The Automated Tests Prove It Works?
1310
<!-- Name specific tests or describe what the test output demonstrates. -->
1411
<!-- "Tests pass" is not acceptable. Be specific. -->
15-
16-
## Spec / Doc Changes
17-
<!-- If any spec, CLAUDE.md, README, or doc was updated, summarise here. -->
18-
<!-- Delete section if no docs changed. -->
19-
20-
## Breaking Changes
21-
- [ ] None
22-
<!-- Or describe any breaking API / behaviour changes below -->

.github/workflows/ci.yml

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# agent-pmo:d58c330
1+
# agent-pmo:29b9dcf
22
name: CI
33

44
on:
@@ -12,8 +12,8 @@ concurrency:
1212
cancel-in-progress: true
1313

1414
jobs:
15-
lint:
16-
name: Lint
15+
ci:
16+
name: CI
1717
runs-on: ubuntu-latest
1818
timeout-minutes: 10
1919
steps:
@@ -29,21 +29,6 @@ jobs:
2929
- name: Lint
3030
run: make lint
3131

32-
test:
33-
name: Test
34-
runs-on: ubuntu-latest
35-
timeout-minutes: 10
36-
needs: lint
37-
steps:
38-
- uses: actions/checkout@v4
39-
40-
- uses: actions/setup-dotnet@v4
41-
with:
42-
dotnet-version: '10.0.x'
43-
44-
- run: dotnet restore
45-
- run: dotnet tool restore
46-
4732
- name: Test
4833
run: make test
4934

@@ -61,19 +46,5 @@ jobs:
6146
TestResults/**/coverage.*
6247
retention-days: 7
6348

64-
build:
65-
name: Build
66-
runs-on: ubuntu-latest
67-
timeout-minutes: 10
68-
needs: test
69-
steps:
70-
- uses: actions/checkout@v4
71-
72-
- uses: actions/setup-dotnet@v4
73-
with:
74-
dotnet-version: '10.0.x'
75-
76-
- run: dotnet restore
77-
7849
- name: Build
7950
run: make build

Clinical/Clinical.Api/Clinical.Api.csproj

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
<PackageReference Include="Nimblesite.DataProvider.Core" Version="0.2.0-beta" />
1616
<PackageReference Include="Nimblesite.Lql.Postgres" Version="0.2.0-beta" />
1717
<PackageReference Include="Nimblesite.Sync.Postgres" Version="0.2.0-beta" />
18-
<PackageReference Include="Selecta" Version="0.4.0" />
1918
<PackageReference Include="Nimblesite.DataProvider.Migration.Core" Version="0.2.0-beta" />
2019
<PackageReference Include="Nimblesite.DataProvider.Migration.Postgres" Version="0.2.0-beta" />
2120
</ItemGroup>
@@ -37,7 +36,7 @@
3736
<!-- Create database from YAML using Migration.Cli (installed as dotnet tool) -->
3837
<Target Name="CreateDatabaseSchema" BeforeTargets="TranspileLqlAndGenerateDataProvider">
3938
<Exec
40-
Command="dotnet migration-cli -- --schema &quot;$(MSBuildProjectDirectory)/clinical-schema.yaml&quot; --output &quot;$(MSBuildProjectDirectory)/clinical.db&quot; --provider sqlite"
39+
Command="dotnet migration-cli --schema &quot;$(MSBuildProjectDirectory)/clinical-schema.yaml&quot; --output &quot;$(MSBuildProjectDirectory)/clinical.db&quot; --provider sqlite"
4140
WorkingDirectory="$(MSBuildProjectDirectory)"
4241
StandardOutputImportance="High"
4342
StandardErrorImportance="High"
@@ -58,15 +57,15 @@
5857
</ItemGroup>
5958
<Message Importance="High" Text="Transpiling LQL files (@(LqlFiles))" />
6059
<Exec
61-
Command="dotnet lqlcli-sqlite -- --input &quot;%(LqlFiles.Identity)&quot; --output &quot;%(LqlFiles.RootDir)%(LqlFiles.Directory)%(LqlFiles.Filename).generated.sql&quot;"
60+
Command="dotnet lqlcli-sqlite --input &quot;%(LqlFiles.Identity)&quot; --output &quot;%(LqlFiles.RootDir)%(LqlFiles.Directory)%(LqlFiles.Filename).generated.sql&quot;"
6261
Condition="'$(EnableLqlTranspile)' == 'true' and @(LqlFiles) != ''"
6362
WorkingDirectory="$(MSBuildProjectDirectory)"
6463
StandardOutputImportance="High"
6564
StandardErrorImportance="High"
6665
ContinueOnError="WarnAndContinue"
6766
/>
6867
<Exec
69-
Command="dotnet dataprovider-sqlite-cli -- --project-dir &quot;$(MSBuildProjectDirectory)&quot; --config &quot;$(MSBuildProjectDirectory)/DataProvider.json&quot; --out &quot;$(MSBuildProjectDirectory)/Generated&quot; --connection-type NpgsqlConnection"
68+
Command="dotnet dataprovider-sqlite --project-dir &quot;$(MSBuildProjectDirectory)&quot; --config &quot;$(MSBuildProjectDirectory)/DataProvider.json&quot; --out &quot;$(MSBuildProjectDirectory)/Generated&quot; --connection-type NpgsqlConnection"
7069
WorkingDirectory="$(MSBuildProjectDirectory)"
7170
StandardOutputImportance="High"
7271
StandardErrorImportance="High"

Clinical/Clinical.Api/DatabaseSetup.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using Migration;
2-
using Migration.Postgres;
1+
using Nimblesite.DataProvider.Migration.Core;
2+
using Nimblesite.DataProvider.Migration.Postgres;
33
using InitError = Outcome.Result<bool, string>.Error<bool, string>;
44
using InitOk = Outcome.Result<bool, string>.Ok<bool, string>;
55
using InitResult = Outcome.Result<bool, string>;

0 commit comments

Comments
 (0)