Skip to content

Commit 657bbc8

Browse files
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.
1 parent cc5a50d commit 657bbc8

171 files changed

Lines changed: 7272 additions & 4579 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.

0 commit comments

Comments
 (0)