Skip to main content

implement-capability

Use when implementing a capability-matrix feature in the Supabase C# SDK — given a feature card (area, group, name, description, key such as auth.oauth_admin.delete_client, status, note), a bare capability key, or a request to close a parity gap with supabase-js ("implement X", "add support for the Y endpoint", "finish the partially implemented Z"). Takes one or several features; several are dispatched to parallel agents in separate worktrees. Researches the contract, gets the public API approved, drives it test-first to 100% coverage and zero surviving mutants on changed lines, passes the quality gate, and opens a draft PR.

소스 정보

저장소
supabase/supabase-csharp
최근 소스 활동
2026년 10월 29일 15:23
감지된 SKILL.md 언어
영어
스타
706
포크
111

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
5 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
implement-capability
description
Use when implementing a capability-matrix feature in the Supabase C# SDK — given a feature card (area, group, name, description, key such as auth.oauth_admin.delete_client, status, note), a bare capability key, or a request to close a parity gap with supabase-js ("implement X", "add support for the Y endpoint", "finish the partially implemented Z"). Takes one or several features; several are dispatched to parallel agents in separate worktrees. Researches the contract, gets the public API approved, drives it test-first to 100% coverage and zero surviving mutants on changed lines, passes the quality gate, and opens a draft PR.
# Implement a capability You are closing one row of the capability matrix. The deliverable is a draft PR the maintainer can merge without rework: a minimal, discoverable public API they approved up front, behavior that matches the capability's contract on every path, tests written first that cover and mutation-proof every changed line, and a passing gate. Standards, in force throughout — read the sections you touch and treat them as a checklist, not background: - `../_shared/references/CONVENTIONS.md` — how the code looks (v8 column for anything marked v9). - `../_shared/references/QUALITY_RUBRIC.md` — when it is done. - `references/sources.md` — where each area's contract, reference and C# home live. Several features at once → follow `references/parallel.md` instead of running the phases below yourself. ## Input A feature card: area, group, name, description, **key**, status, optional note. The key is the identity: everything else is looked up from it. A bare key is enough. ## 1. Locate Resolve the key to its sources (`references/sources.md`): 1. The canonical entry in `capabilities/<area>.yaml` — confirm the key exists and the name/description match the card. 2. The capability spec `specs/<area>/<group>/<method>.md`, **if one exists**. It is normative: it states the SDK-layer obligations (defaults, state changes, checks before the wire) and wins over everything else. 3. The service's API spec (OpenAPI) — the operations, request/response shapes, status codes and error codes. Present for most features even without a capability spec. 4. The supabase-js implementation — read it to learn the behavior, not the code. 5. The current C# surface: `grep -rn '"<key>"' packages` for an existing `[PartialCapability]`, the client interface that owns the group, neighbouring methods, the package's test `Support/` fixtures. 6. Open issues: `gh issue list --repo supabase/supabase-csharp --search "<name>" --state all`. 7. Whether the local stack serves the feature: the service's own configuration defaults (for auth, `internal/conf` in supabase/auth), then what `supabase/config.toml` overrides. The CLI sets only what `config.toml` exposes, so a missing CLI option does not mean the feature is off. Confirm against the running stack before calling a path untestable. If the capability cannot apply to a .NET SDK (browser-only API, platform storage), stop and report why instead of building it. ## 2. Contract Write the behavior contract — the single artifact every later phase reads. It ends up verbatim in the PR description. - **Operations**: method + path for each call, and the auth it needs (user JWT, service role, anon). - **Inputs**: required vs optional, defaults the SDK fills in, checks the SDK makes before the wire. - **Outputs**: what the caller gets back, and how an empty or absent body maps to it. - **Failures**: each server answer the caller can hit (status, `error_code`) and the typed exception/reason it becomes; argument misuse that throws `ArgumentException` before I/O. - **State**: anything the SDK stores, clears or emits (session, events). - **Reference deltas**: what supabase-js does that this SDK deliberately does differently, and why. The capability spec and the API spec are the contract; supabase-js fills gaps and shows the edges. **Never port, transliterate or adapt JS code.** JS idioms (untyped option bags, string unions, `{ data, error }` tuples, swallowed errors) do not carry over, and where the JS is loose the C# does better. Where the sources disagree, the capability spec wins, then the API spec, then supabase-js; note the disagreement in the PR. For a `partially_implemented` card, the contract is the gap the existing note describes; everything already shipped stays as is. ## 3. Propose the public API — stop for approval Present what a developer will see, and nothing else: ``` Placement: IGotrueAdminClient (Supabase.Gotrue) — next to <neighbour> Use case: Gotrue/CreateCustomProvider/ — <its types>; Common/: <types shared with other use cases, or "none"> Signature: Task DeleteOAuthClientAsync(string clientId, CancellationToken cancellationToken = default); New types: <public records/enums with their members, or "none"> Throws: GotrueException (Reason = FailureHint.Reason.X) when …; ArgumentException when … Example: var admin = new AdminClient(serviceRoleKey, options); await admin.DeleteOAuthClientAsync("my-client-id"); Deviations: <from supabase-js, with the reason, or "none"> ``` Design rules: v8 error model (throw the package's typed exception, no `Result`); `Async` suffix and a trailing `CancellationToken` that reaches the HTTP call; immutable `init`-only records for new request/response/options types; read-only collections; enums over strings; one optional `XxxOptions` record over a parameter list; names from .NET/Supabase vocabulary, not JS; consistent with the neighbouring members a caller already knows; nothing public that a caller does not need. **Wait for the maintainer's approval.** Do not write production code before it. Revise and re-present on feedback. ## 4. Branch From the repository root, on a fresh branch off the latest master — never on the maintainer's current checkout: ``` git fetch origin master git worktree add ../wt/<key> -b feat/<key> origin/master ``` Work only inside that worktree from here on. If the feature needs a service enabled on the local stack, change `supabase/config.toml` in the branch (CI starts the stack from it) and restart the local stack once. ## 5. Drive — double-loop TDD 1. **Outer loop: a failing E2E** (`[TestCategory("E2E")]`) proving the approved example works against the real stack. Self-isolating: unique names, guaranteed teardown. Reuse the package's E2E fixture. When the test needs state that another, unimplemented capability creates (a provider to delete, a client to update), seed it through the service's API from the test with a plain `HttpClient`, never through SDK code that does not exist yet. 2. **Inner loop**, red → green → refactor, through the public surface only: - **Contract** (`[TestCategory("Contract")]`): the package's WireMock server pins method, path, headers, query and the mapping of every failure in the contract to its exception. - **Wire-shape approval** (`Contract`, the package's `RequestApprovalFixture` + Verify): snapshot the exact request body. Review the `.verified` file: the approved bytes must match the API spec. - **Unit** (`[TestCategory("Unit")]`): pure logic, checks before the wire. 3. Every failure and edge in the contract has a test. A test that is awkward to write is design feedback: change the API, never expose an internal or add test-only production code. Test style: `Sut_ShouldConsequence_GivenScenario`; class named for the element under test, in the use-case folder that mirrors production (`Gotrue.Tests/CreateCustomProvider/`, CONVENTIONS §2); FluentAssertions fluent and inline; NSubstitute for collaborators; reason strings cite the spec; no magic numbers; no comments. Inner loop: `scripts/quality-gate/gate.sh packages/<Name> --fast`. ## 6. Refine - Orchestration reads as named intent; mechanics in named private helpers. No comments in code. - Use-case layout (CONVENTIONS §2): every new type sits in the folder of the one use case that uses it; the product's `Common/` holds only what two or more use cases share. When a later capability needs a type an earlier one created, the later PR moves it to `Common/`. - XML `<summary>` on every new public member, `<example>` on the entry point — on the interface; the implementation uses `<inheritdoc/>`. - `ConfigureAwait(false)` on every await; the token reaches the HTTP call. - New I/O participates in the package's instrumentation. - Annotate the entry point: `[ImplementedCapability("<key>")]` — or swap an existing `[PartialCapability]` for it. Supporting types are not annotated. Never edit `sdk-compliance.yaml`; it is generated after merge. - Declare the new public surface with the analyzer, not by hand: `dotnet format analyzers packages/<Name>/<Name>/<Name>.csproj --severity info --diagnostics RS0016 RS0017`. It writes the exact entries (enum ordinals included) to `PublicAPI.Unshipped.txt`. ## 7. Verify All three, in this order; each must pass before the next: 1. **Changed-line coverage — 100%.** `python3 -I .claude/skills/implement-capability/scripts/changed-lines-coverage.py packages/<Name>` exits 0. Each `UNCOVERED` line is either a missing test or dead code to delete. 2. **Mutation — zero survivors on changed lines, and every changed line tested.** In the worktree, `--since` finds no changes, so name each changed production file: ``` (cd packages/<Name>/<Name>.Tests && STRYKER_MUTATION=true dotnet stryker -m '**/<File>.cs' -m '**/<Other>.cs') scripts/quality-gate/gate.sh packages/<Name> --mutation ``` Then list the mutants on changed lines from `StrykerOutput/*/reports/mutation-report.json` with their status. A survivor is a missing assertion, or code that does nothing. A run that tested no mutant on the changed lines is not a pass, whatever the gate prints: find out why (compile errors, filters) and rerun. 3. **Full gate** — invoke `sdk-quality-gate` on `packages/<Name>`. PASS is required. If the local stack is unavailable or shared with parallel work, the local verdict is INCOMPLETE; then the CI run on the draft PR is the gate (step 8). Then walk QUALITY_RUBRIC §8 item by item, and re-read the diff as the reviewer: anything that would draw a comment is fixed now. ## 8. Ship 1. Commit with `feat(<product>): <what a caller can now do>` — product = `auth`, `storage`, `postgrest`, `realtime`, `functions`, `supabase`. No co-author trailer, no generated-by footer. 2. `git push -u origin feat/<key>`. 3. `gh pr create --draft --base master` with the body from `references/pr-template.md`. No generated-by footer. 4. `gh pr checks <number> --watch`. Every check green — `Build and Test` (full gate incl. E2E), `Mutation`, `Validate capability annotations`. Fix and push until they are. 5. Report: PR link, gate verdict, coverage and mutation results, deviations, anything left for the maintainer's judgment. ## Never - Copy, transliterate or adapt supabase-js code. - Write production code before the API is approved. - Introduce a `Result` type or any v9 construct on v8 surface. - Edit `sdk-compliance.yaml`, a `.gate-baseline.json`, or analyzer severities to get green. - Suppress a warning, skip/ignore/re-categorize a test, or retry a flaky E2E. - Commit on the maintainer's checkout, push to master, or mark a PR ready for review. - Stack a PR on another feature branch. Every PR branches off `master` (references/parallel.md). - Call another capability's SDK method from a test before that capability is in `master`. Seed and verify through the service's API with a plain `HttpClient`, or assert on the method under test's own result.
GitHub에서 보기