You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Introduces Gatekeeper and modernizes C# data tooling (#1)
TLDR
Introduces the Gatekeeper microservice for passkey-only authentication and fine-grained authorization, alongside a major overhaul of the C# data access layer to use Nimblesite Postgres tooling and improve CI.
Details
Adds the new Gatekeeper microservice: Provides passkey (WebAuthn/FIDO2) authentication and a comprehensive role-based access control (RBAC) system with resource-level permissions.
Modernizes C# data access tooling: Migrates all C# projects from MelbourneDev to Nimblesite DataProvider, LQL, and Migration packages. This transition shifts schema introspection from SQLite to direct PostgreSQL interaction.
Removes committed generated code: All DataProvider-generated C# (Generated/*.g.cs) and SQL (*.generated.sql) files are no longer tracked in version control. They are now generated dynamically on every build against a live PostgreSQL instance, ensuring up-to-date and type-accurate code.
Enhances CI/CD and local dev workflow: The Makefile now includes explicit targets (db-up, db-migrate, db-down, db-reset) for managing a local Docker Compose-based PostgreSQL database. These are integrated into make build, make test, and make lint to ensure a consistent and robust environment.
Improves testing reliability: Test execution is now consolidated and ordered to fail fast across projects. A new ICD10.TestSupport project simplifies ICD-10 database setup in integration tests.
Simplifies PR template: Updates the pull request template for a more streamlined experience.
How Do The Automated Tests Prove It Works?
New Gatekeeper.Api.Tests contain integration tests for passkey registration and login flows, as well as comprehensive authorization checks for RBAC and resource-level grants.
The main make test command orchestrates execution of all test projects in a specified order, ensuring foundational services are tested before their consumers. The stopOnFail configuration in xUnit and set -e in the Makefile ensures immediate failure on any broken test.
The make ci workflow now explicitly starts and migrates the PostgreSQL database before running any builds or tests, verifying the entire data access and generation pipeline functions correctly.
Copy file name to clipboardExpand all lines: .claude/skills/ci-prep/SKILL.md
+17-16Lines changed: 17 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,20 +3,20 @@ name: ci-prep
3
3
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".
4
4
argument-hint: "[--failing] [optional job name to focus on]"
5
5
---
6
-
<!-- agent-pmo:d58c330-->
6
+
<!-- agent-pmo:29b9dcf-->
7
7
8
8
# CI Prep
9
9
10
10
Prepare the current state for CI. If CI is already failing, fetch and analyze the logs first.
11
11
12
12
## Arguments
13
13
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.
15
15
- Any other argument is treated as a job name to focus on (but all failures are still reported).
16
16
17
17
If `--failing` is NOT passed, skip directly to **Step 2**.
18
18
19
-
## Step 1 -- Fetch failed CI logs (only when `--failing`)
19
+
## Step 1 — Fetch failed CI logs (only when `--failing`)
20
20
21
21
You MUST do this before any other work.
22
22
@@ -40,23 +40,23 @@ gh run view "$RUN_ID" --log-failed
40
40
41
41
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.
42
42
43
-
## Step 2 -- Analyze the CI workflow
43
+
## Step 2 — Analyze the CI workflow
44
44
45
45
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`.
46
46
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).
48
48
4. Note any environment variables, matrix strategies, or conditional steps that affect execution.
49
49
50
50
**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*.
51
51
52
-
## Step 3 -- Run each CI step locally, in order
52
+
## Step 3 — Run each CI step locally, in order
53
53
54
54
Work through failures in this priority order:
55
55
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
60
60
61
61
For each command extracted from the CI workflow:
62
62
@@ -67,20 +67,21 @@ For each command extracted from the CI workflow:
67
67
68
68
### Hard constraints
69
69
70
-
-**NEVER modify test files** -- fix the source code, not the tests
-**NEVER use `any` in TypeScript** to silence type errors
72
73
-**NEVER delete or ignore failing tests**
73
74
-**NEVER remove assertions**
74
75
75
76
If stuck on the same failure after 5 attempts, ask the user for help.
76
77
77
-
## Step 4 -- Report
78
+
## Step 4 — Report
78
79
79
80
- List every step that was run and its result (pass/fail/fixed).
80
81
- If any step could not be fixed, report what failed and why.
81
82
- Confirm whether the branch is ready to push.
82
83
83
-
## Step 5 -- Commit/Push (only when `--failing`)
84
+
## Step 5 — Commit/Push (only when `--failing`)
84
85
85
86
Once all CI steps pass locally:
86
87
@@ -96,10 +97,10 @@ Once all CI steps pass locally:
96
97
- Fix issues found in each step before moving to the next
97
98
- Never skip steps or suppress errors
98
99
- 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
100
101
101
102
## Success criteria
102
103
103
104
- Every command that CI runs has been executed locally and passed
104
105
- 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)
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.
4
4
---
5
-
<!-- agent-pmo:d58c330-->
5
+
<!-- agent-pmo:29b9dcf-->
6
6
7
7
# Code Dedup
8
8
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.
10
10
11
-
## Prerequisites -- hard gate
11
+
## Prerequisites — hard gate
12
12
13
13
Before touching ANY code, verify these conditions. If any fail, stop and report why.
14
14
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."
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.
44
53
4. List all dead code found with file paths and line numbers. Do NOT delete yet.
45
54
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.
47
58
48
59
1. Look for functions/methods with identical or near-identical logic
49
60
2. Look for copy-pasted blocks (same structure, maybe different variable names)
50
61
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)
53
64
6. List all duplicates found. Do NOT merge yet.
54
65
55
-
### Step 4 -- Scan for duplicate tests
66
+
### Step 4 — Scan for duplicate tests
67
+
68
+
Search for tests that verify the same behavior.
56
69
57
70
1. Look for test functions with identical assertions against the same code paths
58
71
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)
60
73
4. List all duplicate tests found. Do NOT delete yet.
61
74
62
-
### Step 5 -- Apply changes (one at a time)
75
+
### Step 5 — Apply changes (one at a time)
63
76
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**.
65
78
66
79
#### 5a. Remove dead code
80
+
- Delete dead code identified in Step 2
67
81
- 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
69
84
70
85
#### 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
72
88
- 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.
74
91
75
92
#### 5c. Remove duplicate tests
76
93
- Delete the redundant test (keep the more thorough one)
77
94
- 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.
79
96
80
-
### Step 6 -- Final verification
97
+
### Step 6 — Final verification
81
98
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
85
102
4. Report: what was removed, what was merged, final coverage vs baseline
86
103
87
104
## Rules
88
105
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.
0 commit comments