From f794afee86887a745b8ffe5b2d2978c51319859d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Amorim?= Date: Wed, 12 Aug 2026 19:50:17 +0100 Subject: [PATCH 1/3] Adopt the claude-rules library-team profile as the shared ruleset The flat rule files under .claude/rules/ were hand-copied early on and had drifted from the shared modules in the claude-rules repo. Replace them with the library-team profile (core x5, library archetype, team workflow, benchmarks overlay) copied verbatim via tools/sync.ps1, so future drift is auditable with the script's check mode. Sqlbound-only conventions (milestone planning, feature/M-number branches, phase-based semver, Roslyn snapshot testing, Dapper/ADO.NET benchmark baselines) move to a project-specific rule file outside the synced set, keeping the shared modules byte-identical to their source. The EF Core records exception is dropped deliberately: SqlBound builds on System.Data.Common and never maps EF entities. Co-Authored-By: Claude Fable 5 --- .claude/rules/archetype/library.md | 20 +++++++++ .claude/rules/architecture.md | 8 ---- .claude/rules/coding-standards.md | 13 ------ .claude/rules/core/architecture.md | 13 ++++++ .claude/rules/core/coding-standards.md | 31 +++++++++++++ .claude/rules/{ => core}/design-principles.md | 2 +- .claude/rules/core/testing-philosophy.md | 28 ++++++++++++ .claude/rules/core/workflow-core.md | 26 +++++++++++ .claude/rules/overlays/benchmarks.md | 10 +++++ .claude/rules/overlays/workflow-team.md | 8 ++++ .claude/rules/profiles/library-team.md | 9 ++++ .claude/rules/project/sqlbound.md | 44 +++++++++++++++++++ .claude/rules/testing.md | 19 -------- .claude/rules/workflow.md | 15 ------- CLAUDE.md | 12 ++--- 15 files changed, 197 insertions(+), 61 deletions(-) create mode 100644 .claude/rules/archetype/library.md delete mode 100644 .claude/rules/architecture.md delete mode 100644 .claude/rules/coding-standards.md create mode 100644 .claude/rules/core/architecture.md create mode 100644 .claude/rules/core/coding-standards.md rename .claude/rules/{ => core}/design-principles.md (98%) create mode 100644 .claude/rules/core/testing-philosophy.md create mode 100644 .claude/rules/core/workflow-core.md create mode 100644 .claude/rules/overlays/benchmarks.md create mode 100644 .claude/rules/overlays/workflow-team.md create mode 100644 .claude/rules/profiles/library-team.md create mode 100644 .claude/rules/project/sqlbound.md delete mode 100644 .claude/rules/testing.md delete mode 100644 .claude/rules/workflow.md diff --git a/.claude/rules/archetype/library.md b/.claude/rules/archetype/library.md new file mode 100644 index 0000000..11cf7fd --- /dev/null +++ b/.claude/rules/archetype/library.md @@ -0,0 +1,20 @@ +# Archetype — Library (shipped, reusable package) + +For code consumed by other projects (NuGet packages, shared libraries). +Compose with the five core rules. + +Structure (deltas from `core/architecture.md`) +- Unit tests under `test/.UnitTests/`; integration tests that need + a real dependency under `test/.IntegrationTests/`. + +Packaging & compatibility +- `dotnet pack` runs in CI from day one so packaging bugs surface early. +- Target the full supported TFM matrix (e.g. `net8.0;net10.0`); CI runs the + matrix on every OS you claim to support. +- The public API is a contract: follow semantic versioning, keep XML docs + complete (they ship in the package), and treat any breaking change as a + deliberate, documented major bump. + +Testing +- Cover the public surface directly; internal helpers are tested through it, + not around it. diff --git a/.claude/rules/architecture.md b/.claude/rules/architecture.md deleted file mode 100644 index 1b87216..0000000 --- a/.claude/rules/architecture.md +++ /dev/null @@ -1,8 +0,0 @@ -# Architecture - -Rules governing physical project and solution structure (as opposed to logical design, which lives in `design-principles.md`): - -- Repo/solution layout: source under `src//`, unit tests under `test/.UnitTests/` (singular `test`), integration tests requiring a real dependency (e.g. a database provider) under `test/.IntegrationTests/`, benchmark projects (BenchmarkDotNet) under `bench//`, one solution file (`.slnx`) per repo or example, at its root, referencing every project beneath it. -- Benchmark projects join the solution so CI builds them, but CI never runs them — benchmark numbers from shared runners are noise; baselines are produced locally and documented in `docs/`. -- Centralize shared MSBuild properties (`TargetFramework`, `Nullable`, `TreatWarningsAsErrors`, etc.) in a `Directory.Build.props` at that same root instead of repeating them per `.csproj`. -- `dotnet pack` runs in CI from day one so packaging bugs surface early. diff --git a/.claude/rules/coding-standards.md b/.claude/rules/coding-standards.md deleted file mode 100644 index 53ac9e8..0000000 --- a/.claude/rules/coding-standards.md +++ /dev/null @@ -1,13 +0,0 @@ -# Coding Standards - -Always follow the Microsoft C# coding conventions and .NET naming guidelines: - -- PascalCase for types, methods, properties, constants, and public members; camelCase for locals and parameters; `_camelCase` for private fields (`private static readonly` values are constant-like and stay PascalCase); `I` prefix for interfaces; `Async` suffix for async methods. -- One top-level type per file; file name matches the type name. Exception: a small supporting type (typically a record or struct) that exists only to serve the file's primary type — a companion DTO, result, or value type it owns and produces — may be declared in the same file. The exception covers helpers bound to that one type; it does not license unrelated types or a type intended for reuse across the codebase, which still get their own file. -- Use file-scoped namespaces, `var` when the type is apparent, expression-bodied members only when they improve readability. -- Enable and respect nullable reference types (`enable`); never suppress warnings with `!` without a comment justifying it. -- Prefer records for immutable data, `readonly` where possible, and pattern matching over type checks/casts. Exception: ORM-mapped entities that require mutable, parameterless-constructible state (e.g., EF Core) may remain classes. -- Public APIs must have XML doc comments; internal code is documented only where intent is not obvious from the code. Test projects are exempt — their `public` types exist only for test-framework discovery, not as a consumed API surface. -- Never include unnecessary using directives. -- Codify these conventions in an `.editorconfig` at the solution root (naming rules, `file_scoped` namespaces, `IDE0005` for unused usings, etc.) so they are tool-enforced rather than prose-only, and set `true` so style violations fail the build alongside `TreatWarningsAsErrors`. -- All code must pass `dotnet format` and build with zero warnings (`TreatWarningsAsErrors` is on). diff --git a/.claude/rules/core/architecture.md b/.claude/rules/core/architecture.md new file mode 100644 index 0000000..a75e139 --- /dev/null +++ b/.claude/rules/core/architecture.md @@ -0,0 +1,13 @@ +# Architecture + +Rules governing physical project and solution structure (as opposed to logical +design, which lives in `design-principles.md`). This is the invariant skeleton; +archetype files add the parts that vary — test-project naming, `bench/`, +integration-test projects, packaging. + +- Source lives under `src//`; tests under `test/` (singular). +- One solution file (`.slnx`) per repo, at its root, referencing every project + beneath it. +- Centralize shared MSBuild properties (`TargetFramework`, `Nullable`, + `TreatWarningsAsErrors`, etc.) in a `Directory.Build.props` at that same root + instead of repeating them per `.csproj`. diff --git a/.claude/rules/core/coding-standards.md b/.claude/rules/core/coding-standards.md new file mode 100644 index 0000000..819a510 --- /dev/null +++ b/.claude/rules/core/coding-standards.md @@ -0,0 +1,31 @@ +# Coding Standards + +Always follow the Microsoft C# coding conventions and .NET naming guidelines: + +- PascalCase for types, methods, properties, constants, and public members; + camelCase for locals and parameters; `_camelCase` for private instance + fields (`private static readonly` values are constant-like and stay + PascalCase); `I` prefix for interfaces; `Async` suffix for async methods. +- One top-level type per file; file name matches the type name. Exception: a + small supporting type (typically a record or struct) that exists only to + serve the file's primary type — a companion DTO, result, or value type it + owns and produces — may be declared in the same file. The exception covers + helpers bound to that one type; it does not license unrelated types or a type + intended for reuse across the codebase, which still get their own file. +- Use file-scoped namespaces, `var` when the type is apparent, expression-bodied + members only when they improve readability. +- Enable and respect nullable reference types (`enable`); + never suppress warnings with `!` without a comment justifying it. +- Prefer records for immutable data, `readonly` where possible, and pattern + matching over type checks/casts. +- Public APIs must have XML doc comments; internal code is documented only where + intent is not obvious from the code. Test projects are exempt — their `public` + types exist for test-framework discovery, not as a consumed API surface. +- Never include unnecessary using directives. +- Codify these conventions in an `.editorconfig` at the solution root (naming + rules, `file_scoped` namespaces, `IDE0005` for unused usings, etc.) so they + are tool-enforced rather than prose-only, and set + `true` so style violations + fail the build alongside `TreatWarningsAsErrors`. +- All code must pass `dotnet format` and build with zero warnings + (`TreatWarningsAsErrors` is on). diff --git a/.claude/rules/design-principles.md b/.claude/rules/core/design-principles.md similarity index 98% rename from .claude/rules/design-principles.md rename to .claude/rules/core/design-principles.md index e424425..7174b56 100644 --- a/.claude/rules/design-principles.md +++ b/.claude/rules/core/design-principles.md @@ -1,4 +1,4 @@ -# Design Principles +# Design Principles - Always apply well-established object-oriented design practices: favor composition over inheritance, encapsulate invariants inside domain types, keep classes small and cohesive, and depend on abstractions at layer boundaries. - Adhere to SOLID to keep the code adaptive to change: diff --git a/.claude/rules/core/testing-philosophy.md b/.claude/rules/core/testing-philosophy.md new file mode 100644 index 0000000..219e50b --- /dev/null +++ b/.claude/rules/core/testing-philosophy.md @@ -0,0 +1,28 @@ +# Testing — Test-Driven Development + +YOU MUST follow a test-driven development approach for all production code: + +1. **Red** — write a failing test that specifies the desired behavior before + writing implementation code. +2. **Green** — write the minimum implementation to make the test pass. +3. **Refactor** — clean up the code and tests while keeping everything green. + +Rules: + +- Never write production code without a failing test that motivates it. Never + mark a task complete while any test fails. Exception: when porting or adapting + already-designed code (e.g., a pre-written draft) rather than discovering new + behavior, there is no red step — treat `dotnet test` passing as the gate. +- Ensure all relevant edge cases are covered: null/empty inputs, boundary + values, invalid state transitions, concurrency where applicable, and failure + paths (exceptions, timeouts, cancellation via `CancellationToken`). +- When a task explicitly scopes test coverage (e.g., "one test", "happy path + only"), that explicit scope takes precedence over this checklist — but say so + out loud (commit message, notes, or conversation) rather than silently + under-testing. +- Test naming: `Should_ExpectedOutcome_When_Scenario` (e.g., + `Should_ThrowInsufficientStockException_When_InventoryInsufficient`). +- Structure tests as Arrange–Act–Assert. +- Unit tests must be fast and deterministic: no real I/O, network, clock, or + `Task.Delay`. Abstract time behind `TimeProvider`. +- Run `dotnet test` after every change and before declaring any work finished. diff --git a/.claude/rules/core/workflow-core.md b/.claude/rules/core/workflow-core.md new file mode 100644 index 0000000..0281b86 --- /dev/null +++ b/.claude/rules/core/workflow-core.md @@ -0,0 +1,26 @@ +# Workflow — Core + +Applies to every project regardless of team size or archetype. Compose with +exactly one of `overlays/workflow-solo.md` or `overlays/workflow-team.md`. + +- Make minimal, focused changes; do not refactor unrelated code in the same + change. +- One logical change per commit, with an imperative-mood message explaining + *why*. +- In anything the forge renders — commit messages, PR titles/descriptions, and + review comments — write `#N` (or an issue/PR URL) only for an item that + actually exists and is being deliberately referenced; verify with + `gh issue view N` / `gh pr view N` when in doubt. Every other number- or + token-like reference — step numbers, analyzer IDs, external ticket keys, + version numbers — is wrapped in backticks as inline code, so autolinking + never fabricates a link and closing keywords (`Fixes #N`) never fire against + the wrong item. +- When unsure between two designs, present both with trade-offs and ask before + implementing. +- Never commit or push directly to the default branch (`master`/`main`). All + work happens on a `feature/`-prefixed branch. +- Merge by squash so each feature arrives as a single logical commit on the + default branch, consistent with the "one logical change per commit" rule + above; the squash commit message keeps the imperative, *why*-focused form. +- Update the applicable workflow rule file when a new convention or correction + is established. diff --git a/.claude/rules/overlays/benchmarks.md b/.claude/rules/overlays/benchmarks.md new file mode 100644 index 0000000..b1990dd --- /dev/null +++ b/.claude/rules/overlays/benchmarks.md @@ -0,0 +1,10 @@ +# Overlay — Benchmarks (BenchmarkDotNet) + +Add when the project tracks performance. + +- Benchmark projects live under `bench//` and join the solution so + CI *builds* them. +- CI never *runs* benchmarks — numbers from shared runners are noise. Produce + baselines locally and record them in `docs/`. +- Smoke-test a benchmark's plumbing with `--job Dry` + (e.g. `dotnet run -c Release --project bench/ -- --job Dry`). diff --git a/.claude/rules/overlays/workflow-team.md b/.claude/rules/overlays/workflow-team.md new file mode 100644 index 0000000..db36f22 --- /dev/null +++ b/.claude/rules/overlays/workflow-team.md @@ -0,0 +1,8 @@ +# Workflow — Team project (PR required) + +Compose with `core/workflow-core.md`. Use on any multi-contributor repo. + +- The branch lands on the default branch only through a reviewed pull request. +- Enforce with branch protection: require a PR, disallow direct pushes, require + the squash-merge strategy — so it can't be bypassed by accident. +- Never open a pull request automatically — confirm with the maintainer first. diff --git a/.claude/rules/profiles/library-team.md b/.claude/rules/profiles/library-team.md new file mode 100644 index 0000000..24c1a7d --- /dev/null +++ b/.claude/rules/profiles/library-team.md @@ -0,0 +1,9 @@ +# Profile: library-team — reusable package, multiple contributors +@../core/coding-standards.md +@../core/design-principles.md +@../core/architecture.md +@../core/testing-philosophy.md +@../core/workflow-core.md +@../overlays/workflow-team.md +@../archetype/library.md +@../overlays/benchmarks.md diff --git a/.claude/rules/project/sqlbound.md b/.claude/rules/project/sqlbound.md new file mode 100644 index 0000000..00ca67f --- /dev/null +++ b/.claude/rules/project/sqlbound.md @@ -0,0 +1,44 @@ +# SqlBound — project-specific rules + +Rules that apply only to this repository, composed on top of the shared +`library-team` profile. Shared modules under `core/`, `archetype/`, and +`overlays/` are copied verbatim from the `claude-rules` repo and must stay +byte-identical so `tools/sync.ps1 -Check` audits cleanly — never edit them +here. Sqlbound-specific conventions land in this file; corrections to a shared +rule go upstream to `claude-rules` first and are then re-synced. + +## Workflow — milestones, phases, versioning + +- For each milestone, draft a plan first and present it to the user; execution + starts only after the user approves the plan. +- Milestones (M1–M16) are used to track the progress of the project. All + milestone work happens on a `feature/M-`-prefixed branch. +- Versioning follows semantic versioning: each phase gets its own minor version + (Phase 1 → `0.1.x`, Phase 2 → `0.2.x`, …; Phase 6 ships `1.0.0`). +- When a phase completes, tag it on the default branch with an annotated tag + (e.g., `git tag -a v0.1.0 -m "..."`) and push the tag to GitHub for + reference. +- `PackageVersion` carries a prerelease suffix (`X.Y.0-preview.N`) during a + phase's active development. Closing the phase drops the suffix to the clean + `X.Y.0` in the same commit that gets tagged, so the tag always matches the + package version it marks exactly. The next phase's first commit starts the + new prerelease line (`X.(Y+1).0-preview.1`). +- Each phase has one matching GitHub milestone (titled + `Phase N — (0.Y.x)`), not one per M-number; every M-number's PR in + that phase is associated with the phase's milestone on creation, and the + milestone is closed when the phase's final PR merges. The milestone's + description lists each composing M-number with its own description as a + bullet, so the phase-level summary and the per-milestone detail both stay + visible in one place. + +## Testing + +- Generator output is snapshot-tested with the Roslyn testing SDK. +- Benchmarks compare against Dapper and raw ADO.NET (the `bench/` layout and + CI policy come from the shared benchmarks overlay). + +## Architecture + +- The shared "one solution file (`.slnx`) per repo, at its root" rule extends + here to "per repo or example": a self-contained example project gets its own + `.slnx` at its own root. diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md deleted file mode 100644 index 2482724..0000000 --- a/.claude/rules/testing.md +++ /dev/null @@ -1,19 +0,0 @@ -# Testing — Test-Driven Development - -YOU MUST follow a test-driven development approach for all production code: - -1. **Red** — write a failing test that specifies the desired behavior before writing implementation code. -2. **Green** — write the minimum implementation to make the test pass. -3. **Refactor** — clean up the code and tests while keeping everything green. - -Rules: - -- Never write production code without a failing test that motivates it. Never mark a task complete while any test fails. -- Ensure all relevant edge cases are covered: null/empty inputs, boundary values, invalid state transitions, concurrency where applicable, and failure paths (exceptions, timeouts, cancellation via `CancellationToken`). -- When a task explicitly scopes test coverage (e.g., "one test", "happy path only"), that explicit scope takes precedence over this checklist — but say so out loud (commit message, notes, or conversation) rather than silently under-testing. -- Test naming: `Should_ExpectedOutcome_When_Scenario` (e.g., `Should_ThrowInsufficientStockException_When_InventoryInsufficient`). -- Structure tests as Arrange–Act–Assert. -- Unit tests must be fast and deterministic: no real I/O, network, clock, or `Task.Delay`. Abstract time behind `TimeProvider`. -- Run `dotnet test` after every change and before declaring any work finished. -- Generator output is snapshot-tested with the Roslyn testing SDK. -- Benchmarks (BenchmarkDotNet, vs Dapper and raw ADO.NET) live in the repo. diff --git a/.claude/rules/workflow.md b/.claude/rules/workflow.md deleted file mode 100644 index 2f18348..0000000 --- a/.claude/rules/workflow.md +++ /dev/null @@ -1,15 +0,0 @@ -# Workflow - -- For each milestone, draft a plan first and present it to the user; execution starts only after the user approves the plan. -- Never open a pull request automatically — always confirm with the user first. -- Make minimal, focused changes; do not refactor unrelated code in the same change. -- One logical change per commit, with an imperative-mood message explaining *why*. -- When unsure between two designs, present both with trade-offs and ask before implementing. -- Never commit or push directly to the default branch (`master`/`main`). Milestones are used to track the progress of the project. All work happens on a `feature/M-`-prefixed branch. -- The branch lands on the default branch only through a reviewed pull request. Enforce this with branch protection (require a PR, disallow direct pushes, require the squash-merge strategy) so it can't be bypassed by accident. -- Merge by squash so each feature arrives as a single logical commit on the default branch, consistent with the "one logical change per commit" rule above; the squash commit message keeps the imperative, *why*-focused form. -- Versioning follows semantic versioning: each phase gets its own minor version (Phase 1 → `0.1.x`, Phase 2 → `0.2.x`, …; Phase 6 ships `1.0.0`). -- When a phase completes, tag it on the default branch with an annotated tag (e.g., `git tag -a v0.1.0 -m "..."`) and push the tag to GitHub for reference. -- `PackageVersion` carries a prerelease suffix (`X.Y.0-preview.N`) during a phase's active development. Closing the phase drops the suffix to the clean `X.Y.0` in the same commit that gets tagged, so the tag always matches the package version it marks exactly. The next phase's first commit starts the new prerelease line (`X.(Y+1).0-preview.1`). -- Each phase has one matching GitHub milestone (titled `Phase N — (0.Y.x)`), not one per M-number; every M-number's PR in that phase is associated with the phase's milestone on creation, and the milestone is closed when the phase's final PR merges. The milestone's description lists each composing M-number with its own description as a bullet, so the phase-level summary and the per-milestone detail both stay visible in one place. -- Update this file when a new convention or correction is established. diff --git a/CLAUDE.md b/CLAUDE.md index 2343335..1115d7b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -36,8 +36,10 @@ Follow the design constraints below; they are deliberate decisions, not suggesti Work proceeds milestone by milestone (M1–M16) across six phases: Bedrock (skeleton/CI, execution core, Dapper-coexistence sample), Codegen (materialization, query shapes, AOT + benchmarks), Verification (SQL Server introspection, diagnostics, offline snapshots), Providers, Migrations & CLI, and Ship (API freeze, NuGet 1.0). The Dapper-coexistence sample project (M3) doubles as a permanent CI regression test. Codegen precedes verification because the generator defines the shapes the verifier checks. ## Conventions -@.claude/rules/coding-standards.md -@.claude/rules/architecture.md -@.claude/rules/design-principles.md -@.claude/rules/testing.md -@.claude/rules/workflow.md + +Shared rules come from the `library-team` profile of the `claude-rules` repo, +copied in with its `tools/sync.ps1` (audit drift with `-Check`); sqlbound-only +conventions live in the project file. + +@.claude/rules/profiles/library-team.md +@.claude/rules/project/sqlbound.md From 4ee1fd0b78f92bca60e041e5d4cde7f51635d6bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Amorim?= Date: Fri, 14 Aug 2026 10:35:19 +0100 Subject: [PATCH 2/3] Include the profile manifest in the never-edit synced set The drift audit covers nine files including `profiles/library-team.md`, but the project rule file named only `core/`, `archetype/`, and `overlays/` as never-edit-here, leaving the profile manifest it imports unprotected by the same instruction. Co-Authored-By: Claude Fable 5 --- .claude/rules/project/sqlbound.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.claude/rules/project/sqlbound.md b/.claude/rules/project/sqlbound.md index 00ca67f..96138b0 100644 --- a/.claude/rules/project/sqlbound.md +++ b/.claude/rules/project/sqlbound.md @@ -2,9 +2,10 @@ Rules that apply only to this repository, composed on top of the shared `library-team` profile. Shared modules under `core/`, `archetype/`, and -`overlays/` are copied verbatim from the `claude-rules` repo and must stay -byte-identical so `tools/sync.ps1 -Check` audits cleanly — never edit them -here. Sqlbound-specific conventions land in this file; corrections to a shared +`overlays/`, plus the profile manifest under `profiles/`, are copied +verbatim from the `claude-rules` repo and must stay byte-identical so +`tools/sync.ps1 -Check` audits cleanly — never edit them here. +Sqlbound-specific conventions land in this file; corrections to a shared rule go upstream to `claude-rules` first and are then re-synced. ## Workflow — milestones, phases, versioning From ab806f1bc5bc55f6f867bf149bcbf889d88ee80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Amorim?= Date: Fri, 14 Aug 2026 13:09:16 +0100 Subject: [PATCH 3/3] Correct the versioning and milestone rules to match actual practice The prerelease rule described only an `X.Y.0-preview.N` line dropping to a clean `X.Y.0` at phase close, but Phase 6 went straight from `0.5.0` to `1.0.0-rc.1` and was tagged mid-phase on that suffixed version, with the milestone deliberately left open until GA. The milestone-title template said `(0.Y.x)`, which the live `Phase 6 - Ship (1.0.x)` does not fit. Two adjacent bullets carried the same drift: tagging was described as happening only at phase completion, and a phase was said to get its own minor version though Phase 6 took a major bump. This file is loaded as project instructions, so a wrong rule gets followed. State instead the tag-matches-PackageVersion invariant that actually holds across all six tags, cover both the `-preview.N` and `-rc.N` lines, and spell out the remaining GA promotion so the open Phase 6 can be finished from the rule alone. Co-Authored-By: Claude Fable 5 --- .claude/rules/project/sqlbound.md | 38 +++++++++++++++++++------------ 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/.claude/rules/project/sqlbound.md b/.claude/rules/project/sqlbound.md index 96138b0..ad02e32 100644 --- a/.claude/rules/project/sqlbound.md +++ b/.claude/rules/project/sqlbound.md @@ -14,23 +14,31 @@ rule go upstream to `claude-rules` first and are then re-synced. starts only after the user approves the plan. - Milestones (M1–M16) are used to track the progress of the project. All milestone work happens on a `feature/M-`-prefixed branch. -- Versioning follows semantic versioning: each phase gets its own minor version +- Versioning follows semantic versioning: each phase gets its own version line (Phase 1 → `0.1.x`, Phase 2 → `0.2.x`, …; Phase 6 ships `1.0.0`). -- When a phase completes, tag it on the default branch with an annotated tag - (e.g., `git tag -a v0.1.0 -m "..."`) and push the tag to GitHub for - reference. -- `PackageVersion` carries a prerelease suffix (`X.Y.0-preview.N`) during a - phase's active development. Closing the phase drops the suffix to the clean - `X.Y.0` in the same commit that gets tagged, so the tag always matches the - package version it marks exactly. The next phase's first commit starts the - new prerelease line (`X.(Y+1).0-preview.1`). +- Tag the default branch with an annotated tag (e.g., + `git tag -a v0.1.0 -m "..."`) when a phase completes and for each release + candidate cut along the way, then push the tag to GitHub for reference. +- `PackageVersion` in `Directory.Build.props` carries a prerelease suffix + while a phase is in flight: `X.Y.Z-preview.N` during development, and + `X.Y.Z-rc.N` once the phase is tracking a stable release. Closing the phase + drops the suffix to the clean `X.Y.Z` in the same commit that gets tagged. + Every tag — release candidates included — is cut on a commit whose + `PackageVersion` matches the tag name minus the leading `v`, so a tag always + names its package version exactly. The next phase opens at the version the + roadmap assigns it, not at a mechanical bump of the previous minor. +- A release candidate does not close its phase: `PackageVersion` moves to + `X.Y.Z-rc.N`, `CHANGELOG.md` gets its own `## [X.Y.Z-rc.N]` entry, and the + annotated tag records that the candidate is not published to nuget.org. + Further candidates bump `N`; the clean `X.Y.Z` and its `vX.Y.Z` tag at GA + are what close the phase and its milestone. - Each phase has one matching GitHub milestone (titled - `Phase N — (0.Y.x)`), not one per M-number; every M-number's PR in - that phase is associated with the phase's milestone on creation, and the - milestone is closed when the phase's final PR merges. The milestone's - description lists each composing M-number with its own description as a - bullet, so the phase-level summary and the per-milestone detail both stay - visible in one place. + `Phase N — (..x)`), not one per M-number; every + M-number's PR in that phase is associated with the phase's milestone on + creation, and the milestone is closed when the phase's final PR merges. The + milestone's description lists each composing M-number with its own + description as a bullet, so the phase-level summary and the per-milestone + detail both stay visible in one place. ## Testing