dotnet-production-agent-skills 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +117 -9
  2. package/RELEASE_NOTES.md +50 -2
  3. package/copilot/production-instructions.md +2 -0
  4. package/dist/src/cli.js +7 -2
  5. package/dist/src/git-hook.js +32 -0
  6. package/dist/src/hooks.js +107 -17
  7. package/dist/src/skills/validation.js +13 -5
  8. package/hooks/commit-msg +16 -0
  9. package/hooks/guard.mjs +13 -6
  10. package/package.json +1 -1
  11. package/skills/api-contract-safety/SKILL.md +2 -0
  12. package/skills/api-endpoint-deprecation/SKILL.md +2 -0
  13. package/skills/aspnet-core-api-development/SKILL.md +2 -0
  14. package/skills/background-services-dotnet/SKILL.md +14 -0
  15. package/skills/bug-investigation/SKILL.md +2 -0
  16. package/skills/code-quality/SKILL.md +2 -0
  17. package/skills/code-review/SKILL.md +2 -0
  18. package/skills/context-reset/SKILL.md +2 -0
  19. package/skills/dependency-management/SKILL.md +2 -0
  20. package/skills/deployment-readiness-dotnet/SKILL.md +12 -0
  21. package/skills/diff-review/SKILL.md +2 -0
  22. package/skills/distributed-workflows/SKILL.md +2 -0
  23. package/skills/dotnet-architecture/SKILL.md +2 -0
  24. package/skills/dotnet-implementation/SKILL.md +2 -0
  25. package/skills/ef-core-safety/SKILL.md +2 -0
  26. package/skills/exception-handling/SKILL.md +2 -0
  27. package/skills/git-workflow/SKILL.md +7 -6
  28. package/skills/google-bigquery-dotnet/SKILL.md +2 -0
  29. package/skills/google-cloud-pubsub-dotnet/SKILL.md +2 -0
  30. package/skills/google-firestore-dotnet/SKILL.md +2 -0
  31. package/skills/http-client-integrations/SKILL.md +14 -0
  32. package/skills/integration-testing-dotnet/SKILL.md +14 -0
  33. package/skills/observability-dotnet/SKILL.md +13 -0
  34. package/skills/performance-diagnostics-dotnet/SKILL.md +12 -0
  35. package/skills/poc-development/SKILL.md +2 -0
  36. package/skills/production-debugging/SKILL.md +2 -0
  37. package/skills/production-hotfix/SKILL.md +2 -0
  38. package/skills/production-logging/SKILL.md +2 -0
  39. package/skills/redis-dotnet/SKILL.md +2 -0
  40. package/skills/relational-database-dotnet/SKILL.md +2 -0
  41. package/skills/retry-resilience/SKILL.md +2 -0
  42. package/skills/safe-terminal/SKILL.md +2 -0
  43. package/skills/shared-code-impact/SKILL.md +2 -0
  44. package/skills/task-router/SKILL.md +2 -0
  45. package/skills/unit-testing/SKILL.md +3 -1
package/README.md CHANGED
@@ -32,6 +32,7 @@ A focused collection of `SKILL.md` guidance built to reduce repeated prompting,
32
32
  - [Composition Workflows](#composition-workflows)
33
33
  - [Quality Policies & Standards](#quality-policies--standards)
34
34
  - [TypeScript CLI Reference](#typescript-cli-reference)
35
+ - [Git hook setup and troubleshooting](#reject-co-author-trailers-with-git)
35
36
  - [Installation Targets & Paths](#installation-targets--paths)
36
37
  - [Safety & Conflict Handling](#safety--conflict-handling)
37
38
  - [Host Compatibility](#host-compatibility)
@@ -170,8 +171,8 @@ The catalog is grouped by task so agents can load only the guidance relevant to
170
171
 
171
172
  | Skill | Focus & Trigger | Progressive References |
172
173
  | :--- | :--- | :--- |
173
- | [`dotnet-architecture`](skills/dotnet-architecture/SKILL.md) | Design and preserve clean boundaries, layering, and DI registrations for substantial changes. | [architecture-patterns](skills/dotnet-architecture/references/architecture-patterns.md) |
174
- | [`dotnet-implementation`](skills/dotnet-implementation/SKILL.md) | Implement robust production .NET & ASP.NET Core behavior adhering to established repository conventions. | [idiomatic-csharp](skills/dotnet-implementation/references/idiomatic-csharp.md) |
174
+ | [`dotnet-architecture`](skills/dotnet-architecture/SKILL.md) | Design and preserve clean boundaries, layering, and DI registrations for substantial changes. | [design-checks](skills/dotnet-architecture/references/design-checks.md) |
175
+ | [`dotnet-implementation`](skills/dotnet-implementation/SKILL.md) | Implement robust production .NET & ASP.NET Core behavior adhering to established repository conventions. | [runtime-safety](skills/dotnet-implementation/references/runtime-safety.md) |
175
176
  | [`shared-code-impact`](skills/shared-code-impact/SKILL.md) | Identify all consumers, analyze ripple effects, and strictly constrain changes to shared libraries/helpers. | — |
176
177
  | [`dependency-management`](skills/dependency-management/SKILL.md) | Assess, add, prune, or upgrade NuGet dependencies conservatively without breaking transitive graphs. | — |
177
178
 
@@ -182,14 +183,15 @@ The catalog is grouped by task so agents can load only the guidance relevant to
182
183
  | [`aspnet-core-api-development`](skills/aspnet-core-api-development/SKILL.md) | Build thin controllers/minimal APIs with validation, structured responses, and complete OpenAPI specs. | — |
183
184
  | [`api-contract-safety`](skills/api-contract-safety/SKILL.md) | Guard HTTP contracts against unintended breaking changes across routes, payloads, error formats, and headers. | — |
184
185
  | [`api-endpoint-deprecation`](skills/api-endpoint-deprecation/SKILL.md) | Execute formal multi-stage API deprecation, migration windows, consumer verification, and safe retirement. | — |
185
- | [`exception-handling`](skills/exception-handling/SKILL.md) | Establish clear recovery, translation, cancellation, and logging boundaries across .NET application tiers. | [api-boundaries](skills/exception-handling/references/api-boundaries.md) |
186
+ | [`exception-handling`](skills/exception-handling/SKILL.md) | Establish clear recovery, translation, cancellation, and logging boundaries across .NET application tiers. | [customer-facing-api](skills/exception-handling/references/customer-facing-api.md) |
186
187
 
187
188
  ### 4. 🧪 Quality, Testing & Review
188
189
 
189
190
  | Skill | Focus & Trigger | Progressive References |
190
191
  | :--- | :--- | :--- |
191
192
  | [`code-quality`](skills/code-quality/SKILL.md) | Apply Clean-as-You-Code principles, Roslyn analyzers, and Sonar expectations to new/modified code. | — |
192
- | [`unit-testing`](skills/unit-testing/SKILL.md) | Target 90–100% meaningful coverage of new business logic using parameterized tests without test bloat. | — |
193
+ | [`unit-testing`](skills/unit-testing/SKILL.md) | Cover changed business behavior with meaningful tests and follow repository coverage policy. | — |
194
+ | [`integration-testing-dotnet`](skills/integration-testing-dotnet/SKILL.md) | Test HTTP boundaries and persistence integrations with isolated dependencies and realistic provider behavior. | — |
193
195
  | [`code-review`](skills/code-review/SKILL.md) | Review diffs rigorously for correctness, security, concurrency, performance, and regression risks. | — |
194
196
  | [`targeted-validation`](skills/targeted-validation/SKILL.md) | Run proportionate verification (from single-test execution to full suite runs) aligned with change risk. | — |
195
197
  | [`diff-review`](skills/diff-review/SKILL.md) | Perform a final pre-commit audit of working tree diffs for accidental mutations, formatting drift, and secrets. | — |
@@ -211,6 +213,8 @@ The catalog is grouped by task so agents can load only the guidance relevant to
211
213
  | :--- | :--- | :--- |
212
214
  | [`distributed-workflows`](skills/distributed-workflows/SKILL.md) | Build idempotent consumers, handle partial failures, manage distributed retries, and design background workers. | — |
213
215
  | [`retry-resilience`](skills/retry-resilience/SKILL.md) | Add explicitly requested retries or review existing transient failure policies; avoid automatic retries. | — |
216
+ | [`http-client-integrations`](skills/http-client-integrations/SKILL.md) | Build and review outbound HTTP clients with safe lifetimes, timeouts, and resource handling. | — |
217
+ | [`background-services-dotnet`](skills/background-services-dotnet/SKILL.md) | Build bounded hosted workers with scoped dependencies and graceful shutdown. | — |
214
218
  | [`dotnet-security`](skills/dotnet-security/SKILL.md) | Threat-model .NET boundaries, protect against SSRF/XSS/SQLi, enforce authorization, and handle secrets safely. | — |
215
219
  | [`production-logging`](skills/production-logging/SKILL.md) | Produce structured, high-signal, sensitive-data-masked, and cost-efficient Serilog/ILogger production logs. | — |
216
220
 
@@ -220,6 +224,9 @@ The catalog is grouped by task so agents can load only the guidance relevant to
220
224
  | :--- | :--- | :--- |
221
225
  | [`bug-investigation`](skills/bug-investigation/SKILL.md) | Isolate symptoms to an empirical root cause before proposing or writing code modifications. | — |
222
226
  | [`production-debugging`](skills/production-debugging/SKILL.md) | Diagnose production failures from telemetry, dumps, traces, and metrics without mutating live state. | — |
227
+ | [`observability-dotnet`](skills/observability-dotnet/SKILL.md) | Design traces, metrics, propagation, sampling, and useful operational signals. | — |
228
+ | [`performance-diagnostics-dotnet`](skills/performance-diagnostics-dotnet/SKILL.md) | Measure and diagnose .NET performance using bounded evidence collection. | — |
229
+ | [`deployment-readiness-dotnet`](skills/deployment-readiness-dotnet/SKILL.md) | Assess deployment compatibility, health, rollout, and rollback readiness. | — |
223
230
  | [`production-hotfix`](skills/production-hotfix/SKILL.md) | Formulate and validate emergency incident hotfixes with minimal blast radius and rapid evidence-based testing. | — |
224
231
  | [`git-workflow`](skills/git-workflow/SKILL.md) | Carry out requested branch, commit, and push operations using efficient batch commands and clean Git hygiene. | — |
225
232
 
@@ -266,8 +273,8 @@ flowchart LR
266
273
  - Automatically inspects `.editorconfig`, repository analyzers, Roslyn rules, and SonarCloud settings before writing C#.
267
274
  - Adheres to [Clean as You Code](https://docs.sonarsource.com/sonarqube-cloud/standards/about-new-code/): fixes new defects and complexity in modified code without derailing tasks into massive legacy cleanups.
268
275
 
269
- ### Targeted Unit-Test Coverage (90–100%)
270
- - Focuses on 90–100% meaningful coverage of new or modified business logic.
276
+ ### Targeted Unit-Test Coverage
277
+ - Follows the repository coverage policy and focuses on meaningful tests for new or modified business logic.
271
278
  - Avoids redundant test counts and brittle implementation testing; prioritizes framework-native parameterized tests (`[Theory]`, `[TestCase]`) and real observable outcomes.
272
279
 
273
280
  ### Formal API Deprecation Lifecycle
@@ -287,11 +294,111 @@ External consumers are never assumed absent just because no internal repository
287
294
  | :--- | :--- | :--- |
288
295
  | Universal engineering rules | Managed section in project `.github/copilot-instructions.md` | Every Copilot coding task in that project |
289
296
  | Specialized .NET knowledge | Individual `SKILL.md` files | The coding agent selects relevant skills from their descriptions and the request |
290
- | Deterministic command enforcement | Project hooks/guardrails | Installed for Codex, Copilot, Claude Code, Cursor, and Antigravity in project scope |
297
+ | Command guardrails | Project hooks/guardrails | Configured for selected hosts during project-scope installation; subject to host activation and permissions |
291
298
 
292
- The CLI installs and manages guidance; it does not route prompts or load every skill for every task. Clear skill descriptions help the coding agent select relevant knowledge. Universal rules belong in repository instructions. Command blocking belongs in host-supported hooks. Project installs now configure native hooks for every supported coding agent using one shared, dependency-free guard script. Existing unrelated hook entries are preserved.
299
+ The CLI installs and manages guidance; it does not route prompts or load every skill for every task. Clear skill descriptions help the coding agent select relevant knowledge. Universal rules belong in repository instructions. Command blocking belongs in host-supported hooks. Project installs now configure native hooks for every supported coding agent using one shared, dependency-free guard script. The installer manages its own hook entries; review the proposed changes with `--dry-run`.
293
300
 
294
- The initial policy blocks force-push, destructive Git reset/clean/branch deletion, broad recursive deletion, and direct access to common credential-bearing files. Safe commands continue normally. Host configuration is written to `.codex/hooks.json`, `.github/hooks/dotnet-production-agent-skills.json`, `.claude/settings.json`, `.cursor/hooks.json`, or `.agents/hooks.json` for Antigravity.
301
+ The guard checks common forms of force-push, destructive Git operations, broad recursive deletion, and access to some credential-bearing files. These checks are best effort: shell syntax, alternative tools, host payloads, and unsupported operations can evade them, and matching can also block a benign command. They are not a sandbox or a complete security boundary. Use host permissions, sandboxing, least-privilege access, and server-side checks for stronger enforcement. Host configuration is written to `.codex/hooks.json`, `.github/hooks/dotnet-production-agent-skills.json`, `.claude/settings.json`, `.cursor/hooks.json`, or `.agents/hooks.json` for Antigravity.
302
+
303
+ Project hooks are configured on project-scope installation; user-scope skill installs do not add them. Hosts may require trust, enablement, a supported version, and a working Node.js executable. Confirm activation using the host's hook diagnostics. `doctor` inspects installed configuration and script contents; it does not prove that a host executed the hook. Host timeout and error behavior differ. Avoid logging hook inputs because they may contain secrets.
304
+
305
+ The separate Git `commit-msg` hook is opt-in. Local Git hooks can be bypassed and do not cover commits created through an API; add a required server-side check if enforcement is needed across all paths.
306
+
307
+ ### Reject co-author trailers with Git
308
+
309
+ The optional Git `commit-msg` hook rejects commits containing a `Co-authored-by:` line, regardless of which agent or developer runs Git. It checks the final message, including messages supplied through `-m`, `-F`, templates, and `--trailer`. The comparison is case-insensitive and blocks human co-author trailers too. A rejected commit is not created, and the hook does not rewrite its message.
310
+
311
+ #### 1. Install once per repository
312
+
313
+ Requires Git and Node.js 18 or later. Node.js must remain available on the PATH used by your terminal or IDE when it runs Git.
314
+
315
+ After **v0.3.3 is published**, run from your repository root:
316
+
317
+ ```sh
318
+ npx dotnet-production-agent-skills@0.3.3 git-hook
319
+ ```
320
+
321
+ Preview first, or select a repository explicitly:
322
+
323
+ ```sh
324
+ npx dotnet-production-agent-skills@0.3.3 git-hook --dry-run
325
+ npx dotnet-production-agent-skills@0.3.3 git-hook --project "/path/to/repository"
326
+ ```
327
+
328
+ For Windows Command Prompt, use your Windows project path:
329
+
330
+ ```bat
331
+ npx dotnet-production-agent-skills@0.3.3 git-hook --project "C:\Projects\MyApi"
332
+ ```
333
+
334
+ The command prints the installed hook path. It respects `core.hooksPath` and linked worktrees without changing Git configuration. If your configured hooks directory is shared between repositories, the installed hook applies wherever that directory is used. Re-running the command verifies an identical installed hook. A different existing hook is preserved, even with `--force`.
335
+
336
+ This is a separate opt-in: `install`, `update`, and `uninstall` for agent skills do not install, update, or remove this Git hook. Each developer or agent checkout needs its own setup; cloning a repository does not automatically activate local Git hooks.
337
+
338
+ #### 2. Commit normally
339
+
340
+ No extra flag or agent prompt is needed. When a message contains a co-author trailer, Git exits with an error:
341
+
342
+ ```text
343
+ Commit rejected: Co-authored-by trailers are forbidden. Remove the attribution and retry; do not bypass the hook.
344
+ ```
345
+
346
+ Remove the trailer from the proposed message and run the commit again. For agents, instruct them to correct the message and retry normally. Do not use `--no-verify` to work around the rejection.
347
+
348
+ #### 3. Check the hook without creating a commit
349
+
350
+ From your repository root, find the active hook path:
351
+
352
+ ```sh
353
+ git rev-parse --git-path hooks/commit-msg
354
+ ```
355
+
356
+ Create a temporary file named `hook-test-message.txt` containing:
357
+
358
+ ```text
359
+ Test the authorship policy
360
+
361
+ Co-authored-by: Example Agent <agent@example.invalid>
362
+ ```
363
+
364
+ Run the following, replacing the first quoted path with the path printed by Git:
365
+
366
+ ```sh
367
+ node "<active-hook-path>" hook-test-message.txt
368
+ ```
369
+
370
+ Expect the rejection message and exit code **1**. Remove the co-author line and run it again; expect no output and exit code **0**. Delete the temporary test file afterward. This check creates no commits.
371
+
372
+ #### Existing hooks and hook managers
373
+
374
+ If installation reports `Existing commit-msg hook preserved`, keep your existing hook. Copy the packaged [commit-message check](hooks/commit-msg) to a stable project path, for example `.githooks/no-coauthors.cjs`, and invoke it from your existing commit-message hook before that hook returns success.
375
+
376
+ For a shell-based hook or Husky commit-message hook, the integration line is:
377
+
378
+ ```sh
379
+ node .githooks/no-coauthors.cjs "$1" || exit $?
380
+ ```
381
+
382
+ Pass Git's original message-file argument and propagate a nonzero exit code. Keep all existing checks; do not replace the hook manager's configuration or reference a temporary npm-cache path.
383
+
384
+ #### Troubleshooting and removal
385
+
386
+ | Symptom | What to check |
387
+ | :--- | :--- |
388
+ | `git-hook` is an unknown command | Confirm v0.3.3 has been published and use the version-pinned command above. |
389
+ | Git says this is not a repository | Run inside a Git working tree or provide `--project`. |
390
+ | Node is unavailable when committing | Ensure the IDE/Git process can resolve Node.js on its PATH. A terminal and an IDE can have different environments. |
391
+ | Existing hook conflict | Use the manual integration above. The installer deliberately does not replace existing hooks. |
392
+ | The hook appears inactive | Inspect the path returned by `git rev-parse --git-path hooks/commit-msg`. Check that it is executable on POSIX, that no per-command hook-path override is in use, and that the commit is made through local Git. |
393
+ | A new package version contains a hook update | The installed hook is a copy. Review the new check and update your managed integration manually; the installer preserves differing existing files. |
394
+
395
+ To remove a standalone installation, locate the active hook with `git rev-parse --git-path hooks/commit-msg` and inspect it. Delete only the hook bearing the `dotnet-production-agent-skills: reject co-author attribution` marker if it is still the standalone check you installed. For a hook-manager integration, remove only the added invocation and its copied check. Preserve unrelated hooks and Git configuration.
396
+
397
+ #### Enforcement limits
398
+
399
+ The hook checks co-author trailer lines in local Git commits. AI signatures, generated-by footers, and PR titles/descriptions remain covered by agent instructions. GitHub/API-created commits do not run local Git hooks. Local hooks can also be bypassed with `--no-verify` or disabled through Git configuration. For merge enforcement, add a server-side PR check and require it in branch protection. See the [Git hook documentation](https://git-scm.com/docs/githooks#_commit_msg).
400
+
401
+ ### Terminal recovery and managed Copilot instructions
295
402
 
296
403
  Terminal recovery guidance keeps commands anchored to the intended repository, separates executable lookup from repository selection, and forbids moving into Git/tool installation directories as a workaround. Copilot project instructions include the critical rules so they are available even before the focused `safe-terminal` skill is selected. Skills and instructions guide the model; the existing hooks do not enforce these directory/recovery rules. See the skill's [shell recovery examples](skills/safe-terminal/references/shell-recovery.md) for diagnostics and primary sources.
297
404
 
@@ -318,6 +425,7 @@ Commands:
318
425
  list Display available skills and current installation status
319
426
  doctor Validate skill metadata and report host installation health
320
427
  uninstall Safely remove only skills tracked by this package
428
+ git-hook Opt in to a Git commit-msg hook in the current/--project repository
321
429
  ```
322
430
 
323
431
  ### Options & Flags
package/RELEASE_NOTES.md CHANGED
@@ -1,8 +1,56 @@
1
1
  # Release notes
2
2
 
3
+ ## v0.4.0 — Safer hook management and expanded .NET skills
4
+
5
+ Prepared for release with [PR #15](https://github.com/dprakash2101/dotnet-production-agent-skills/pull/15); not yet published to npm.
6
+
7
+ ### New
8
+
9
+ - Add six focused skills: `integration-testing-dotnet`, `http-client-integrations`, `observability-dotnet`, `performance-diagnostics-dotnet`, `background-services-dotnet`, and `deployment-readiness-dotnet`.
10
+ - Expand existing skills with practical guidance for contracts, migrations, diagnostics, distributed workflows, security, validation, and repository-specific conventions.
11
+
12
+ ### Improved
13
+
14
+ - Recognize additional destructive command variants and JSON-encoded tool arguments in the project guard. Document that its checks are best-effort and depend on the host loading the hook.
15
+ - Preserve unrelated hook handlers and Copilot hook entries during updates. Detect modified guard scripts before replacing them, and remove only owned files during uninstall.
16
+ - Use the same YAML-based skill validation for the CLI and standalone validator, with checks for instruction bodies, description lengths, and linked resources.
17
+ - Make Jira naming and coverage expectations follow the repository's own policies instead of imposing fixed conventions.
18
+
19
+ ### Compatibility and upgrade
20
+
21
+ - Existing targets, scopes, modes, and CLI options remain supported. Project hooks are a best-effort safeguard, not a sandbox; verify that your agent host loads and trusts them.
22
+ - Unmodified guards from the previous release migrate automatically. Customized or unrecognized guards without an ownership record require manual review; uninstall preserves untracked legacy scripts.
23
+ - After publication, update user skills with `npx dotnet-production-agent-skills@0.4.0 update --target all`. For a project installation, add `--scope project` and review local changes before updating.
24
+
25
+ ### Validation
26
+
27
+ `npm run validate` passed: 37 skills validated and all 32 tests passed. Documentation catalog syntax and Git whitespace checks passed. Live agent-host activation was not tested.
28
+
29
+ ## v0.3.3 — Strict coding-agent authorship rules
30
+
31
+ Prepared for release after PR #13 is merged; not yet published to npm.
32
+
33
+ ### Improved
34
+
35
+ - Add an opt-in `git-hook` CLI command that installs a Git `commit-msg` hook rejecting case-insensitive `Co-authored-by:` lines in final commit messages. Respect `core.hooksPath`, support dry-run and explicit project paths, and preserve existing hooks without changing Git configuration.
36
+ - Strengthen the `git-workflow` skill, managed Copilot project instructions, and global engineering guardrails to prohibit `Co-authored-by:` trailers, equivalent co-author metadata, AI/agent signatures, and generated-by footers in commits and pull requests.
37
+ - Cover indirect attribution through commit trailers, templates, API fields, and Git author/committer identity overrides.
38
+ - Require inspection of complete proposed commit/PR messages before creation and new commits before pushing. If tooling inserts attribution, stop before publishing and report the blocker without bypassing hooks or rewriting existing commits.
39
+
40
+ ### Compatibility and upgrade
41
+
42
+ - Existing CLI targets, scopes, flags, and copy/link modes are unchanged. Git hook installation is separate from skill installation and updates.
43
+ - After publication, run `npx dotnet-production-agent-skills@0.3.3 git-hook` inside each repository to opt in. Node.js must be available when Git runs. Existing hook managers require manual integration.
44
+ - The Git hook rejects co-author trailers locally; AI footers and PR text remain covered by agent instructions. API-created commits and hook bypasses require a server-side required check for merge enforcement.
45
+ - After publication, update installed skills with `npx dotnet-production-agent-skills@0.3.3 update --target all`. Add `--scope project` to refresh that project's managed Copilot instructions and installed skills. Review local edits before updating.
46
+
47
+ ### Validation
48
+
49
+ `npm run validate` passed: all 31 skills validated, the TypeScript build passed, and all 23 tests passed. Git hook tests cover real commits with inline, file-based, and trailer-based messages, installer idempotency, conflict preservation, custom hook paths, and dry-run behavior. Whitespace checks passed.
50
+
3
51
  ## v0.3.2 — Repository-safe terminal recovery
4
52
 
5
- Prepared for publication; this version has not yet been published to npm.
53
+ Released in [`dotnet-production-agent-skills@0.3.2`](https://www.npmjs.com/package/dotnet-production-agent-skills/v/0.3.2).
6
54
 
7
55
  ### Improved
8
56
 
@@ -21,7 +69,7 @@ Prepared for publication; this version has not yet been published to npm.
21
69
 
22
70
  - CLI targets, scopes, flags, and copy/link modes are unchanged.
23
71
  - These changes strengthen agent guidance; existing hooks do not enforce the new repository-directory recovery rules.
24
- - After publication, update installed skills with `npx dotnet-production-agent-skills@0.3.2 update --target all`. Run the update in project scope (`--scope project`) to refresh that project's managed Copilot instructions and installed skills. Review local edits before updating.
72
+ - Update installed skills with `npx dotnet-production-agent-skills@0.3.2 update --target all`. Run the update in project scope (`--scope project`) to refresh that project's managed Copilot instructions and installed skills. Review local edits before updating.
25
73
 
26
74
  ### Validation
27
75
 
@@ -7,4 +7,6 @@ Do not introduce retries automatically. Add them only when requested or required
7
7
  When behavior changes, check whether existing tests need updating. Avoid redundant tests that slow CI.
8
8
  Run the smallest appropriate validation, build, or test command after changing code.
9
9
 
10
+ Strict authorship rule for every coding agent: never add `Co-authored-by:` trailers (case-insensitive), co-author metadata, AI/agent signatures, credits, or generated-by footers to commits or pull request titles/descriptions. Do not inject attribution through `--trailer`, templates, API fields, or author/committer identity overrides. Inspect the complete proposed commit/PR text and remove automatically suggested attribution before creation; inspect the new commits' full messages before pushing. If a hook, tool, or host adds attribution, stop before publishing and report the blocker. Do not bypass hooks, change configuration, amend existing commits, or rewrite published history without explicit authorization. Apply the git-workflow skill for the full procedure.
11
+
10
12
  Before terminal commands, apply the safe-terminal skill and verify the actual shell and project working directory. After a failure, inspect the submitted/executed command and first actionable error before choosing a correction. Never add terminal control sequences or move into Git/tool installation folders as a workaround. Executable location and repository location are separate: keep commands in the project, verify Git's intended repository with `git -C "<project-path>" rev-parse --show-toplevel`, and use same-session executable lookup only for a genuine command-not-found error. Do not guess binary paths, switch shells, edit PATH/profiles/configuration, or reinstall tools to escape an unexplained failure. Retry only after an evidence-based correction; stop after at most three distinct corrections.
package/dist/src/cli.js CHANGED
@@ -9,6 +9,7 @@ import { createInterface } from "node:readline/promises";
9
9
  import { changeInstructions, inspectInstructions } from "./copilot/instructions.js";
10
10
  import { changeHooks, hookTargets, inspectHooks, removeSharedHookScript } from "./hooks.js";
11
11
  import { validateSkills } from "./skills/validation.js";
12
+ import { installGitHook } from "./git-hook.js";
12
13
  const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
13
14
  const SKILLS_ROOT = path.join(PACKAGE_ROOT, "skills");
14
15
  const MANIFEST_NAME = ".dotnet-agent-skills.json";
@@ -22,6 +23,7 @@ Commands:
22
23
  list List packaged skills and installation state
23
24
  doctor Validate packaged skills and inspect installation health
24
25
  uninstall Remove only skills tracked by this package
26
+ git-hook Opt in to a Git commit-msg hook in the current/--project repository
25
27
 
26
28
  Options:
27
29
  --target <all|shared|codex|copilot|claude|cursor|antigravity>
@@ -242,6 +244,7 @@ async function installOrUpdate(options, command) {
242
244
  }
243
245
  if (options.scope === "project") {
244
246
  await Promise.all(hookTargets(options.target).map((target) => inspectHooks(options.project, PACKAGE_ROOT, target)));
247
+ await Promise.all(hookTargets(options.target).map((target) => changeHooks(options.project, PACKAGE_ROOT, target, "install", true)));
245
248
  }
246
249
  const packaged = new Set(skills);
247
250
  const packageJson = JSON.parse(await readFile(path.join(PACKAGE_ROOT, "package.json"), "utf8"));
@@ -459,11 +462,13 @@ async function main() {
459
462
  console.log(usage());
460
463
  return;
461
464
  }
462
- const commands = new Set(["install", "update", "list", "doctor", "uninstall"]);
465
+ const commands = new Set(["install", "update", "list", "doctor", "uninstall", "git-hook"]);
463
466
  if (!commands.has(parsed.command))
464
467
  throw new Error(`unknown command: ${parsed.command}`);
465
468
  const command = parsed.command;
466
- if (command === "install" || command === "update")
469
+ if (command === "git-hook")
470
+ console.log(await installGitHook(parsed.options.project, PACKAGE_ROOT, parsed.options.dryRun));
471
+ else if (command === "install" || command === "update")
467
472
  await installOrUpdate(parsed.options, command);
468
473
  else if (command === "uninstall")
469
474
  await uninstall(parsed.options);
@@ -0,0 +1,32 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { chmod, lstat, mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ export async function installGitHook(project, packageRoot, dryRun) {
5
+ const result = spawnSync("git", ["rev-parse", "--git-path", "hooks/commit-msg"], { cwd: project, encoding: "utf8" });
6
+ if (result.error)
7
+ throw result.error;
8
+ if (result.status !== 0)
9
+ throw new Error(result.stderr.trim() || "Git repository required for git-hook.");
10
+ const destination = path.resolve(project, result.stdout.trim());
11
+ const source = await readFile(path.join(packageRoot, "hooks", "commit-msg"), "utf8");
12
+ let exists = false;
13
+ try {
14
+ const entry = await lstat(destination);
15
+ exists = true;
16
+ if (!entry.isFile() || await readFile(destination, "utf8") !== source) {
17
+ throw new Error(`Existing commit-msg hook preserved at ${destination}. Integrate the packaged hooks/commit-msg check into your hook manager manually.`);
18
+ }
19
+ }
20
+ catch (error) {
21
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
22
+ throw error;
23
+ }
24
+ if (dryRun)
25
+ return `would ${exists ? "verify" : "install"} commit-msg hook: ${destination}`;
26
+ if (!exists) {
27
+ await mkdir(path.dirname(destination), { recursive: true });
28
+ await writeFile(destination, source, { flag: "wx", mode: 0o755 });
29
+ }
30
+ await chmod(destination, 0o755);
31
+ return `${exists ? "verified" : "installed"} commit-msg hook: ${destination}`;
32
+ }
package/dist/src/hooks.js CHANGED
@@ -1,9 +1,12 @@
1
- import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
1
+ import { cp, mkdir, readFile, rm, rmdir, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { createHash } from "node:crypto";
3
4
  const OWNER = "dotnet-production-agent-skills";
4
5
  const COMMAND = "node .agent-guardrails/guard.mjs";
5
6
  const SCRIPT_DIRECTORY = ".agent-guardrails";
6
7
  const SCRIPT_NAME = "guard.mjs";
8
+ // Exact SHA-256 of the unmodified guard shipped before ownership markers.
9
+ const LEGACY_GUARD_HASHES = new Set(["5286623026e5adcf9bfd0cac0265aed0fa91186cb8294986201441b7354f685b"]);
7
10
  function isObject(value) {
8
11
  return typeof value === "object" && value !== null && !Array.isArray(value);
9
12
  }
@@ -38,31 +41,73 @@ function managedGroup(target) {
38
41
  return { matcher: target === "antigravity" ? "run_command|view_file|write_to_file|replace_file_content|multi_replace_file_content" : "Bash|PowerShell|Read|Write|Edit", hooks: [handler(target)] };
39
42
  }
40
43
  function containsManaged(value) {
41
- return JSON.stringify(value).includes(COMMAND);
44
+ return (JSON.stringify(value) ?? "").includes(COMMAND);
42
45
  }
43
46
  function withoutManaged(value) {
44
- return Array.isArray(value) ? value.filter((entry) => !containsManaged(entry)) : [];
47
+ if (!Array.isArray(value))
48
+ return [];
49
+ return value.flatMap((entry) => {
50
+ if (!isObject(entry))
51
+ return [entry];
52
+ if (typeof entry.command === "string" && entry.command.startsWith(`${COMMAND} `))
53
+ return [];
54
+ if (!Array.isArray(entry.hooks))
55
+ return [entry];
56
+ const retained = entry.hooks.filter((item) => !(isObject(item) && typeof item.command === "string" && item.command.startsWith(`${COMMAND} `)));
57
+ return retained.length ? [{ ...entry, hooks: retained }] : containsManaged(entry) ? [] : [entry];
58
+ });
45
59
  }
46
60
  function mergeConfig(current, target, install) {
47
61
  if (target === "copilot") {
48
- return install ? {
49
- version: 1,
50
- description: `${OWNER} project command guardrails`,
51
- hooks: { preToolUse: [{ type: "command", command: `${COMMAND} copilot`, timeoutSec: 10 }] },
52
- } : {};
62
+ const next = { ...current };
63
+ const hooks = isObject(current.hooks) ? { ...current.hooks } : {};
64
+ const entries = install && Array.isArray(hooks.preToolUse) && containsManaged(hooks.preToolUse) ? [...hooks.preToolUse] : withoutManaged(hooks.preToolUse);
65
+ if (install && !containsManaged(entries))
66
+ entries.push({ type: "command", command: `${COMMAND} copilot`, timeoutSec: 10 });
67
+ if (entries.length)
68
+ hooks.preToolUse = entries;
69
+ else
70
+ delete hooks.preToolUse;
71
+ if (install) {
72
+ next.version = current.version ?? 1;
73
+ next.description = current.description ?? `${OWNER} project command guardrails`;
74
+ }
75
+ else if (current.description === `${OWNER} project command guardrails`) {
76
+ delete next.description;
77
+ if (Object.keys(hooks).length === 0 && current.version === 1)
78
+ delete next.version;
79
+ }
80
+ if (Object.keys(hooks).length)
81
+ next.hooks = hooks;
82
+ else
83
+ delete next.hooks;
84
+ return next;
53
85
  }
54
86
  if (target === "antigravity") {
55
87
  const next = { ...current };
56
- if (install)
57
- next[OWNER] = { enabled: true, PreToolUse: [managedGroup(target)] };
88
+ const group = isObject(current[OWNER]) ? { ...current[OWNER] } : {};
89
+ const existing = group.PreToolUse;
90
+ if (install && !containsManaged(existing))
91
+ group.PreToolUse = [...(Array.isArray(existing) ? existing : []), managedGroup(target)];
92
+ if (!install) {
93
+ const retained = withoutManaged(existing);
94
+ if (retained.length)
95
+ group.PreToolUse = retained;
96
+ else
97
+ delete group.PreToolUse;
98
+ if (group.enabled === true && Object.keys(group).length === 1)
99
+ delete group.enabled;
100
+ }
101
+ if (Object.keys(group).length)
102
+ next[OWNER] = group;
58
103
  else
59
104
  delete next[OWNER];
60
105
  return next;
61
106
  }
62
107
  const hooks = isObject(current.hooks) ? { ...current.hooks } : {};
63
108
  const event = target === "cursor" ? "preToolUse" : "PreToolUse";
64
- const entries = withoutManaged(hooks[event]);
65
- if (install)
109
+ const entries = install && Array.isArray(hooks[event]) && containsManaged(hooks[event]) ? [...hooks[event]] : withoutManaged(hooks[event]);
110
+ if (install && !containsManaged(entries))
66
111
  entries.push(target === "cursor"
67
112
  ? { command: `${COMMAND} cursor`, timeout: 10, matcher: "Shell|Read|Write", failClosed: true }
68
113
  : managedGroup(target));
@@ -101,11 +146,30 @@ export async function changeHooks(projectRoot, packageRoot, target, action, dryR
101
146
  const current = await readJson(files.config);
102
147
  const next = mergeConfig(current, target, action === "install");
103
148
  const hasConfigChange = JSON.stringify(current) !== JSON.stringify(next);
104
- let scriptMatches = false;
149
+ let script = null;
150
+ try {
151
+ script = await readFile(files.script, "utf8");
152
+ }
153
+ catch (error) {
154
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
155
+ throw error;
156
+ }
157
+ const canonical = await expectedScript(packageRoot);
158
+ const scriptMatches = script === canonical;
159
+ const marker = `${files.script}.sha256`;
160
+ const hash = (value) => createHash("sha256").update(value).digest("hex");
161
+ let recorded = "";
105
162
  try {
106
- scriptMatches = await readFile(files.script, "utf8") === await expectedScript(packageRoot);
163
+ recorded = (await readFile(marker, "utf8")).trim();
164
+ }
165
+ catch (error) {
166
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
167
+ throw error;
168
+ }
169
+ const legacyMatch = script !== null && !recorded && LEGACY_GUARD_HASHES.has(hash(script));
170
+ if (action === "install" && script !== null && !scriptMatches && hash(script) !== recorded && !legacyMatch) {
171
+ throw new Error(`Modified or unmanaged guard script preserved: ${files.script}`);
107
172
  }
108
- catch { /* missing */ }
109
173
  if (action === "install") {
110
174
  if (!hasConfigChange && scriptMatches)
111
175
  return "skip";
@@ -114,6 +178,7 @@ export async function changeHooks(projectRoot, packageRoot, target, action, dryR
114
178
  await mkdir(path.dirname(files.script), { recursive: true });
115
179
  await writeFile(files.config, `${JSON.stringify(next, null, 2)}\n`, "utf8");
116
180
  await cp(path.join(packageRoot, "hooks", SCRIPT_NAME), files.script);
181
+ await writeFile(marker, `${hash(canonical)}\n`, "utf8");
117
182
  }
118
183
  return Object.keys(current).length ? "update" : "install";
119
184
  }
@@ -133,6 +198,31 @@ export function hookTargets(target) {
133
198
  return target === "shared" ? [] : [target];
134
199
  }
135
200
  export async function removeSharedHookScript(projectRoot, dryRun) {
136
- if (!dryRun)
137
- await rm(path.join(projectRoot, SCRIPT_DIRECTORY), { recursive: true, force: true });
201
+ if (dryRun)
202
+ return;
203
+ for (const target of hookTargets("all")) {
204
+ const config = await readJson(locations(projectRoot, target).config);
205
+ if (containsManaged(config))
206
+ return;
207
+ }
208
+ const script = locations(projectRoot, "codex").script;
209
+ const marker = `${script}.sha256`;
210
+ try {
211
+ const [content, recorded] = await Promise.all([readFile(script, "utf8"), readFile(marker, "utf8")]);
212
+ if (createHash("sha256").update(content).digest("hex") !== recorded.trim())
213
+ return;
214
+ await rm(script);
215
+ await rm(marker);
216
+ try {
217
+ await rmdir(path.dirname(script));
218
+ }
219
+ catch (error) {
220
+ if (!(error instanceof Error && "code" in error && (error.code === "ENOTEMPTY" || error.code === "ENOENT")))
221
+ throw error;
222
+ }
223
+ }
224
+ catch (error) {
225
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
226
+ throw error;
227
+ }
138
228
  }
@@ -1,4 +1,4 @@
1
- import { readFile, stat } from "node:fs/promises";
1
+ import { readFile, realpath } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import YAML from "yaml";
4
4
  const safeName = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -37,14 +37,19 @@ export async function validateSkills(root, names) {
37
37
  const fields = metadata;
38
38
  if (typeof fields.name !== "string" || fields.name !== name)
39
39
  errors.push(`${name}: frontmatter name does not match directory`);
40
- if (typeof fields.description !== "string" || !fields.description.trim())
41
- errors.push(`${name}: missing description`);
40
+ if (typeof fields.description !== "string" || !fields.description.trim() || fields.description.length > 1024)
41
+ errors.push(`${name}: description must be 1-1024 characters`);
42
+ const body = contents.slice(match[0].length);
43
+ if (!body.trim())
44
+ errors.push(`${name}: instruction body is empty`);
45
+ if (body.split(/\r?\n/).length - (body.endsWith("\n") ? 1 : 0) > 500)
46
+ errors.push(`${name}: instruction body exceeds 500 lines`);
42
47
  if (typeof fields.name === "string") {
43
48
  if (declared.has(fields.name))
44
49
  errors.push(`${name}: duplicate skill name ${fields.name}`);
45
50
  declared.add(fields.name);
46
51
  }
47
- for (const link of contents.matchAll(/\]\(([^)#]+)(?:#[^)]*)?\)/g)) {
52
+ for (const link of body.matchAll(/\]\(([^)#]+)(?:#[^)]*)?\)/g)) {
48
53
  const target = link[1];
49
54
  if (/^[a-z]+:/i.test(target) || target.startsWith("/"))
50
55
  continue;
@@ -54,7 +59,10 @@ export async function validateSkills(root, names) {
54
59
  continue;
55
60
  }
56
61
  try {
57
- await stat(resolved);
62
+ const actualDirectory = await realpath(directory);
63
+ const actual = await realpath(resolved);
64
+ if (!actual.startsWith(`${actualDirectory}${path.sep}`))
65
+ errors.push(`${name}: linked file escapes skill directory: ${target}`);
58
66
  }
59
67
  catch {
60
68
  errors.push(`${name}: missing linked file: ${target}`);
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+
3
+ // dotnet-production-agent-skills: reject co-author attribution in the final message.
4
+ (async () => {
5
+ const { readFile } = await import("node:fs/promises");
6
+ const file = process.argv[2];
7
+ if (!file) throw new Error("Expected the commit message file path.");
8
+ const message = await readFile(file, "utf8");
9
+ if (/^\s*co-authored-by\s*:/im.test(message)) {
10
+ process.stderr.write("Commit rejected: Co-authored-by trailers are forbidden. Remove the attribution and retry; do not bypass the hook.\n");
11
+ process.exitCode = 1;
12
+ }
13
+ })().catch((error) => {
14
+ process.stderr.write(`Commit message validation failed: ${error.message}\n`);
15
+ process.exitCode = 1;
16
+ });
package/hooks/guard.mjs CHANGED
@@ -12,18 +12,25 @@ try {
12
12
  }
13
13
 
14
14
  const tool = input.tool_name ?? input.toolName ?? input.toolCall?.name ?? "";
15
- const args = input.tool_input ?? input.toolArgs ?? input.toolCall?.args ?? {};
15
+ let args = input.tool_input ?? input.toolArgs ?? input.toolCall?.args ?? {};
16
+ if (typeof args === "string") {
17
+ try { args = JSON.parse(args); } catch { args = {}; }
18
+ }
19
+ if (!args || typeof args !== "object" || Array.isArray(args)) args = {};
16
20
  const command = String(args.command ?? args.CommandLine ?? args.script ?? "").trim();
17
21
  const file = String(args.file_path ?? args.path ?? args.TargetFile ?? args.AbsolutePath ?? "").replaceAll("\\", "/");
18
22
 
23
+ // These checks are best-effort protection, not a shell sandbox. Account for
24
+ // common option order, quoting and Git global options without executing input.
19
25
  const checks = [
20
- [/\bgit\s+push\b[^\n;&|]*(?:--force(?:-with-lease)?|-f)\b/i, "Force-push is blocked. Use a normal push or request explicit human approval."],
21
- [/\bgit\s+(?:reset\s+--hard|clean\s+-[^\s]*f[^\s]*|branch\s+-D)(?:\s|$)/i, "Destructive Git operations are blocked. Preserve work and request explicit human approval."],
22
- [/(?:^|[;&|]\s*)(?:rm\s+-[^\s]*r[^\s]*f|Remove-Item\b[^\n;&|]*-Recurse[^\n;&|]*-Force)\s+(?:\/|~|\$HOME|\$env:USERPROFILE)(?:\s|$)/i, "Recursive deletion of a broad system or home path is blocked."],
23
- [/(?:cat|type|Get-Content|more|less)\s+[^\n;&|]*(?:\.env(?:\.|\s|$)|id_(?:rsa|ed25519)|\.pem\b|\.pfx\b|secrets\.json\b)/i, "Reading credential-bearing files through the shell is blocked."],
26
+ [/\bgit\s+(?:(?:-C|--git-dir|--work-tree|-c)\s+(?:"[^"]*"|'[^']*'|\S+)\s+)*(?:push)\b[^\n;&|]*(?:--force(?:-with-lease)?|-f)\b/i, "Force-push is blocked. Use a normal push or request explicit human approval."],
27
+ [/\bgit\s+(?:(?:-C|--git-dir|--work-tree|-c)\s+(?:"[^"]*"|'[^']*'|\S+)\s+)*(?:reset\b[^\n;&|]*--hard\b|clean\s+-[^\s]*f[^\s]*|branch\s+-D(?:\s|$))/i, "Destructive Git operations are blocked. Preserve work and request explicit human approval."],
28
+ [/(?:^|[;&|]\s*)rm\s+-(?=[a-z]*r)(?=[a-z]*f)[a-z]+\s+["']?(?:\/|~|\$HOME)(?:["']?)(?:\s|$)/i, "Recursive deletion of a broad system or home path is blocked."],
29
+ [/(?:^|[;&|]\s*)Remove-Item\b(?=[^\n;&|]*-Recurse\b)(?=[^\n;&|]*-Force\b)[^\n;&|]*["']?(?:\$env:USERPROFILE|\$HOME|~|\/)(?:["']?)(?:\s|$)/i, "Recursive deletion of a broad system or home path is blocked."],
30
+ [/\b(?:cat|type|Get-Content|more|less|head|tail)\s+[^\n;&|]*(?:\.env(?:\.(?!example\b)[\w.-]+)?(?:["'\s]|$)|id_(?:rsa|ed25519)|\.pem\b|\.pfx\b|secrets\.json\b)/i, "Reading credential-bearing files through the shell is blocked."],
24
31
  ];
25
32
 
26
- const sensitivePath = /(?:^|\/)(?:\.env(?:\.[^/]*)?|id_(?:rsa|ed25519)|[^/]*\.(?:pem|pfx)|secrets\.json)$/i;
33
+ const sensitivePath = /(?:^|\/)(?:\.env(?:\.(?!example$)[^/]*)?|id_(?:rsa|ed25519)|[^/]*\.(?:pem|pfx)|secrets\.json)$/i;
27
34
  let reason = sensitivePath.test(file) ? "Direct access to a credential-bearing file is blocked." : "";
28
35
  if (!reason && command) reason = checks.find(([pattern]) => pattern.test(command))?.[1] ?? "";
29
36
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotnet-production-agent-skills",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Portable production .NET engineering skills for coding agents",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -12,3 +12,5 @@ Before editing, locate controller/endpoint definitions, DTOs, serializers/conver
12
12
  Prefer additive, backward-compatible changes. Do not rename/remove fields, change type or meaning, make optional input required, alter enum wire values, change status/error behavior, or tighten auth unless required. Distinguish missing, null, empty, and default values when clients can observe the difference.
13
13
 
14
14
  When a breaking change is unavoidable, identify affected consumers and use the repository's versioning/migration/deprecation approach. Test serialized wire behavior and representative failures, not only C# object equality. Update API documentation/generated clients only when part of the repository's established workflow.
15
+
16
+ When available, compare generated OpenAPI or serialized representative responses before and after the change. Include missing versus null fields, enum wire values, error payloads and a representative existing consumer in compatibility tests.
@@ -25,3 +25,5 @@ Before proposed removal:
25
25
  No code reference is not proof that no customer calls the endpoint. Do not remove the route, DTOs, handlers, tests, or documentation without explicit user direction to perform removal. A request to add or document a replacement alone is insufficient.
26
26
 
27
27
  During removal, preserve unrelated versions/routes, update contract tests and generated artifacts through established workflows, and verify the retired route behavior intentionally. Record approval and evidence in the repository's normal change process rather than inventing a new governance system.
28
+
29
+ Record replacement readiness, observed consumer usage, accountable decision owner, agreed migration window and intended retired-route behavior in the existing change process.
@@ -27,3 +27,5 @@ Return the established stable customer-facing validation and error shape. Never
27
27
  Propagate cancellation through service and I/O boundaries. Apply rate limits, idempotency, feature flags, health behavior, and telemetry only when the endpoint's requirements or repository architecture call for them.
28
28
 
29
29
  Test observable HTTP behavior: valid request, header/request validation, authorization boundaries, important business outcomes, sanitized failures, serialization, and cancellation where relevant. Always compose with `api-contract-safety` and `exception-handling` for the public contract and failure boundary. Load `production-logging` and provider-specific skills only when those concerns are part of the endpoint.
30
+
31
+ Use repository-supported HTTP integration tests for actual routing, serialization, authorization and error responses when these boundaries change.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: background-services-dotnet
3
+ description: Use when designing or changing .NET hosted services, background workers, bounded queues, scheduled work, shutdown, or worker dependency lifetimes.
4
+ ---
5
+
6
+ # Background Services Dotnet
7
+
8
+ Follow the existing hosting and scheduling architecture. Define ownership, concurrency, backpressure, cancellation, failure recovery and durable state before implementation.
9
+
10
+ - Observe the worker task and propagate shutdown. Stop intake and allow bounded in-flight completion before disposal; define what happens to unfinished work.
11
+ - Resolve scoped dependencies inside a scope per appropriate unit of work. Do not share scoped or non-thread-safe state concurrently.
12
+ - Bound queues and concurrency according to downstream capacity. Treat restarts, duplicate work and ambiguous outcomes explicitly; make side effects idempotent where required.
13
+ - Classify poison work and permanent failures separately from transient failures. Do not add retries unless explicitly requested or required by existing architecture.
14
+ - Test cancellation, host shutdown, capacity, failure handling and representative duplicate work with deterministic coordination.
@@ -16,3 +16,5 @@ Follow: symptom -> flow -> data -> divergence -> root cause -> minimal fix -> im
16
16
  7. If implementation is authorized, make the smallest fix that addresses the cause and add a regression test when practical.
17
17
 
18
18
  Do not fix unrelated warnings or failures. Report uncertainty, reproduction gaps, and unrelated failures explicitly.
19
+
20
+ Keep a compact evidence ledger separating observed facts, competing hypotheses, checks performed, and conclusions. Report missing reproduction evidence rather than presenting a plausible hypothesis as verified.
@@ -16,3 +16,5 @@ Prefer clear names, focused methods, guard clauses, accurate null handling, stru
16
16
  Avoid deep nesting, giant methods, unexplained magic values, unnecessary static state, swallowed or over-broad exceptions, dead/commented code, complex LINQ that obscures intent, sync-over-async, secret logging, hardcoded credentials, unjustified allocations on hot paths, and analyzer suppression as a substitute for a fix.
17
17
 
18
18
  Apply Clean-as-You-Code: introduce no new issues, vulnerabilities, security hotspots, or avoidable duplication in changed code. Improve a pre-existing issue only when the requested change materially touches it or it blocks safe implementation. Do not turn feature work into a historical Sonar cleanup. Run the repository's configured analyzer/Sonar-equivalent check when available and proportionate; do not invent a generic rule set when the repository defines one.
19
+
20
+ Use the repository analyzer configuration and the specific actionable diagnostic rather than inventing rules. Validate any fix with the narrow affected build or configured analyzer check.
@@ -12,3 +12,5 @@ Prioritize findings by impact: correctness/regression, security/data exposure, A
12
12
  Each finding should state the concrete failure mode, conditions that trigger it, impact, and precise file/line evidence. Avoid vague preferences, speculative claims without a plausible path, and requests for unrelated cleanup. Check whether tests already cover the concern before reporting it.
13
13
 
14
14
  Return findings in severity order. If none are found, say so and identify meaningful residual risks or unverified validation. A review request authorizes inspection and reporting, not edits, commits, or pushes.
15
+
16
+ For each finding, describe the triggering condition, concrete impact, and precise source location. Prefer a small set of demonstrated defects over speculative style comments.
@@ -14,3 +14,5 @@ When the latest explicit instruction changes the objective:
14
14
  5. Define the minimum files and commands needed for the new direction, then proceed narrowly.
15
15
 
16
16
  Do not repeatedly summarize the abandoned task or reload files solely because they mattered before. If the host supports context compaction, use it when stale context is large enough to impair the new task; preserve a short list of relevant verified facts first.
17
+
18
+ A status question or additional constraint does not by itself replace an active objective. Preserve the current task unless the user clearly redirects it; keep a concise handoff of decisions, modified files and remaining verification.
@@ -24,3 +24,5 @@ Establish the current and target versions, affected projects, target .NET compat
24
24
  For a major version, identify required code/configuration migrations before editing. Inspect restore output for downgrades, conflicts, duplicate transitive versions, analyzer changes, and unexpected output assets. For SDK/runtime upgrades, include deployment environment, container/base image, hosting bundle, SDK pinning, serialization, and changed defaults.
25
25
 
26
26
  Keep dependency work separate from unrelated refactoring. Validate the affected build and behavior, and document unresolved compatibility or rollback concerns.
27
+
28
+ Inspect global.json, target frameworks, central package versions and lock files before planning an upgrade. Use repository-supported audit and restore commands; record feed or environment limitations.
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: deployment-readiness-dotnet
3
+ description: Use when reviewing or preparing .NET application deployment, container hosting, readiness, configuration, rollout, or rollback.
4
+ ---
5
+
6
+ # Deployment Readiness Dotnet
7
+
8
+ Inspect the existing deployment pipeline, target runtime, image, configuration, traffic routing and infrastructure ownership. Do not deploy or modify live infrastructure without authorization.
9
+
10
+ Verify SDK/runtime and target framework compatibility, required configuration and secrets, non-root execution where supported, proxy/TLS settings, resource limits, health and readiness checks, and bounded graceful shutdown. Ensure readiness reflects ability to accept work without turning transient dependency faults into restart loops.
11
+
12
+ For changes affecting schemas or contracts, establish deployment order, mixed-version compatibility, rollback or roll-forward path, and observable recovery signals. Report prerequisites, commands actually run, and unverified environment assumptions.
@@ -20,3 +20,5 @@ Check for accidental deletion, unrelated formatting/renaming/refactoring, genera
20
20
  Revert only accidental agent-created changes, and only when ownership is clear. Never discard or overwrite user changes because they are unrelated. If changes overlap and cannot be safely separated, stop and explain the conflict.
21
21
 
22
22
  Finish when the requested behavior is present, unrelated behavior is preserved, appropriate tests/validation are complete or honestly reported, and no unnecessary file remains changed. Stop there; do not continue cleanup.
23
+
24
+ Inspect relevant untracked files separately: ordinary git diff does not include them. Check staged and unstaged changes and assess generated or binary files when they are part of the requested deliverable.
@@ -15,3 +15,5 @@ Assume timeouts, partial failure, duplicate delivery, reordering, and ambiguous
15
15
  - Attach correlation/trace identifiers and structured outcome metrics without sensitive payloads.
16
16
 
17
17
  Test duplicate execution, retry exhaustion, cancellation/shutdown, partial failure, and recovery—not just the happy path.
18
+
19
+ For an outbox or inbox, identify which records and business changes share a database transaction. Walk through crashes before commit, after commit, after publication and before acknowledgment. Set deduplication retention to cover the expected replay window.
@@ -20,3 +20,5 @@ Controller -> business/application service -> data or external integration
20
20
  For a major change, define affected components and contracts, concurrency and failure boundaries, configuration, observability, migration/rollout needs, and test seams before implementation. The valid change set may be large, but unrelated cleanup remains out of scope.
21
21
 
22
22
  Read [references/design-checks.md](references/design-checks.md) only when designing a new integration, background process, or public API.
23
+
24
+ Compare candidate designs against existing boundaries, operational complexity and change scope. Vertical slices, layered services and other established styles can all be appropriate depending on the repository.
@@ -18,3 +18,5 @@ Follow current project language version, nullable settings, analyzers, conventio
18
18
  For conditional runtime guidance, read only the relevant section of [references/runtime-safety.md](references/runtime-safety.md).
19
19
 
20
20
  Add meaningful tests for new or materially changed testable business logic. Validate once after a coherent change, escalating from focused tests/builds only as risk or evidence requires.
21
+
22
+ Before completion, verify the requested observable behavior, inspect the final diff, run proportionate relevant checks, and report any validation not performed.
@@ -17,3 +17,5 @@ Understand the entity model, mappings, query shape, indexes, tracking needs, tra
17
17
  Do not introduce a custom retry loop merely because a database failure might be transient. Add retry behavior only when explicitly requested or already required/configured by the architecture, prefer the provider's EF Core execution strategy, and verify idempotency, transaction boundaries, duplicate-write safety, timeout budget, bounded attempts, cancellation, and permanent-error classification.
18
18
 
19
19
  Validate query behavior and SQL/performance when risk warrants it. Test provider-specific behavior with the appropriate provider; do not assume an in-memory provider reproduces relational semantics.
20
+
21
+ For production schema changes, prefer an expand/backfill/contract sequence where mixed application versions must coexist. Review backfill batching, locks, resumability and compatibility before deployment. Verify migrations and constraints against the actual provider when practical.
@@ -14,3 +14,5 @@ Distinguish validation/domain failures, authentication/authorization, missing re
14
14
  Define one layer to own final exception logging. A lower layer may log a failure it fully handles or add diagnostic context, but avoid logging and rethrowing the same exception at every layer. Include the exception object in structured internal logs and keep correlation/trace identifiers.
15
15
 
16
16
  Test recovery, propagation, translation, cleanup, and cancellation behavior at the owning boundary. For a customer-facing HTTP API, read [references/customer-facing-api.md](references/customer-facing-api.md) before designing or changing its exception mapping.
17
+
18
+ Exercise representative domain errors, cancellation, timeouts and unexpected failures at the owning boundary. Verify the external response is sanitized and the internal error event is not duplicated.
@@ -13,14 +13,15 @@ For a fresh preflight, prefer one combined inspection such as `git status --shor
13
13
 
14
14
  Preserve unrelated user changes and stage explicit intended paths or hunks only. After staging, use one focused staged check that detects whitespace errors and confirms the staged scope, such as `git diff --cached --check --stat`. Expand to the full staged diff only when it has not already been reviewed or the staged scope is surprising.
15
15
 
16
- Branch names:
16
+ Follow the repository's branch and commit naming rules. If the team requires a Jira ID, reuse one from the current branch or user input and never invent one. Ask only if the requested operation requires an unavailable identifier.
17
17
 
18
- - `feature/<JIRA-ID>/<meaningful-name>`
19
- - `fix/<JIRA-ID>/<meaningful-name>`
18
+ ## Strict authorship policy
20
19
 
21
- Reuse a Jira ID from the current branch or user input. Never invent one; ask if the requested operation requires an unavailable ID.
22
-
23
- Commit messages begin with the Jira ID, for example `XDCI-12345 Add order webhook retry handling`. Do not add co-author, AI, or agent attribution.
20
+ - Never add `Co-authored-by:` trailers (case-insensitive), co-author metadata, or equivalent attribution to commits or pull requests. This applies to every coding agent, including GitHub Copilot, Codex, Claude, and Cursor.
21
+ - Never append AI/agent signatures, credits, or footers such as "Generated with Copilot" or "Assisted by Claude" to commit messages or pull request titles/descriptions.
22
+ - Do not supply attribution through `git commit --trailer`, commit-message templates, API fields, or another indirect mechanism. Do not change the configured Git author/committer identity or use `--author` to credit an agent.
23
+ - Before creating a commit or pull request, inspect the complete proposed message, including its body and trailers, and remove any automatically suggested attribution. Before pushing, inspect the new commits' complete messages with `git log <base>..HEAD --format=full` and verify the same policy.
24
+ - If a hook, tool, or host adds forbidden attribution, stop before publishing and report the blocker. Do not bypass hooks, change tool configuration, amend existing commits, or rewrite published history without explicit authorization.
24
25
 
25
26
  Before committing, confirm required validation and scan the intended changes for secrets/artifacts. Do not include unrelated changes. Do not change Git identity, credentials, credential helpers, or authentication configuration.
26
27
 
@@ -21,3 +21,5 @@ Do not add custom query/job retries merely because failures can be transient. Ad
21
21
  Before finalizing, inspect estimated/scanned bytes or repository query safeguards when available, and test mapping boundaries, nulls, pagination, cancellation, and date/time semantics relevant to the query.
22
22
 
23
23
  Read [references/query-safety.md](references/query-safety.md) for job, pagination, and date/time decision details.
24
+
25
+ Where supported by the installed client and repository, use query dry runs or maximum-bytes controls to bound cost. Preserve job identity when investigating ambiguous completion.
@@ -31,3 +31,5 @@ Assume messages can be delivered more than once. Make handlers idempotent where
31
31
  Test publish completion/failure, bounded producer flow, shutdown flushing, successful ack, retryable nack/redelivery, duplicate delivery, idempotency, cancellation, subscriber flow-control limits, and dead-letter/poison behavior as applicable.
32
32
 
33
33
  Read [references/client-patterns.md](references/client-patterns.md) when choosing client type, configuring a hosted subscriber, or tuning publisher/subscriber flow control and shutdown.
34
+
35
+ Exercise crash boundaries around durable work and acknowledgment, and verify graceful shutdown with outstanding messages. Use an emulator or isolated test environment where appropriate.
@@ -21,3 +21,5 @@ Model for document access patterns, not relational normalization. Choose collect
21
21
  Do not add custom retries merely because failures can be transient. Add them only when explicitly requested or required by existing architecture, and prefer client-supported behavior. Before retrying, account for transaction callback reruns, write idempotency, preconditions, duplicate side effects, timeout budget, bounded attempts, cancellation, and permanent error classification.
22
22
 
23
23
  Test serialization compatibility, absent/null fields, transaction reruns, concurrency preconditions, pagination, and cost-significant query behavior when applicable.
24
+
25
+ Test transaction callback reruns and cursor boundaries with the emulator or appropriate isolated environment when feasible. Verify server-side IAM and application authorization independently of document structure.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: http-client-integrations
3
+ description: Use when implementing or reviewing .NET outbound HTTP integrations, HttpClient lifetime, timeouts, response handling, or existing resilience policies.
4
+ ---
5
+
6
+ # Http Client Integrations
7
+
8
+ Inspect the existing typed or named clients, dependency injection, target framework, handlers, configuration, authentication and upstream contract before changing behavior.
9
+
10
+ - Reuse the repository client factory and intended handler lifetimes. Dispose owned response messages and streams; propagate cancellation through outbound I/O and bound response size where needed.
11
+ - Validate URI construction and redirects across trust boundaries; do not log credentials, sensitive bodies, or authorization headers. Map upstream failures to the owning application boundary without leaking internal details.
12
+ - Distinguish caller cancellation, timeout, transport failure, unsuccessful status, and invalid payload. Define total time budgets consistent with upstream deadlines.
13
+ - Do not introduce retries unless requested or required by existing architecture. Inspect framework and handler defaults: retrying unsafe methods or stacking policies can duplicate writes. If retries are required, establish idempotency, bounded attempts, cancellation, backoff and observability.
14
+ - Test serialization, auth, representative status codes, cancellation, timeout and disposal using the established test seam. Avoid testing only mocked implementation details.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: integration-testing-dotnet
3
+ description: Use when implementing or reviewing .NET integration tests across HTTP, persistence, messaging, or external services.
4
+ ---
5
+
6
+ # Integration Testing Dotnet
7
+
8
+ Follow the repository test framework and existing fixture conventions. Identify the boundary and behavior that must be verified; use unit tests for isolated logic and integration tests where configuration, serialization, persistence, or host wiring matters.
9
+
10
+ - For ASP.NET Core HTTP tests, use the established test host or WebApplicationFactory when appropriate. Exercise routing, authentication and resource authorization, validation, status codes, headers, serialization and sanitized failures over HTTP.
11
+ - Use an isolated database and the real provider when provider behavior matters; avoid assuming an in-memory substitute represents relational constraints, transactions or SQL translation. Apply the actual migration path where relevant.
12
+ - Use an existing emulator or isolated service for messaging and external dependencies when practical; otherwise substitute the boundary deliberately and state what is not covered. Never connect a test to production resources.
13
+ - Isolate test data and resource names; clean up owned resources. Control time and parallelism, bound waiting, and avoid tests that depend on execution order or arbitrary sleeps.
14
+ - Cover representative success and failure paths, cancellation and concurrency where material. Run the narrow affected suite and report unavailable dependencies or skipped checks.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: observability-dotnet
3
+ description: Use when designing or reviewing .NET metrics, distributed traces, OpenTelemetry propagation, sampling, redaction, or operational alerts.
4
+ ---
5
+
6
+ # Observability Dotnet
7
+
8
+ Inspect existing telemetry instrumentation, exporter configuration, service naming, sampling and retention conventions first. Identify the operational question and who will act on the signal.
9
+
10
+ - Propagate trace context across HTTP and messaging boundaries using established instrumentation. Use bounded, meaningful spans and avoid duplicating framework instrumentation.
11
+ - Define metrics for actionable throughput, failure, latency and saturation; avoid customer IDs, request IDs, URLs with unbounded values, and other high-cardinality metric labels.
12
+ - Never record secrets or raw sensitive payloads in logs, traces, metrics, baggage or exception attributes. Follow approved redaction and retention policies.
13
+ - Select sampling and alerts based on volume, severity and cost; ensure critical failure signals remain observable. Test propagation and sensitive-data exclusion where changed.
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: performance-diagnostics-dotnet
3
+ description: Use when investigating or improving measured .NET performance, allocations, garbage collection, thread-pool starvation, latency, or throughput.
4
+ ---
5
+
6
+ # Performance Diagnostics Dotnet
7
+
8
+ Establish the workload, baseline, target, environment and measurement method before changing code. Separate CPU, allocation/GC, contention, thread-pool, database and external dependency hypotheses using evidence.
9
+
10
+ Use existing profiling tools and representative workloads. Choose bounded diagnostic collection appropriate to the environment; production dump capture may include sensitive data and requires appropriate authorization. Compare like-for-like measurements and account for warmup, variability and collection overhead.
11
+
12
+ Change the smallest proven bottleneck while preserving behavior. Verify correctness and measure again. Avoid speculative micro-optimizations, premature pooling, or adding complexity unsupported by measured benefit. Report measurements, environment and residual uncertainty.
@@ -12,3 +12,5 @@ Unit tests and production hardening are optional for a POC. Prioritize executabl
12
12
  Label shortcuts and unknowns: security, resilience, error handling, scalability, observability, migration, compatibility, operations, and test gaps. Do not silently classify ordinary work as a POC to avoid tests.
13
13
 
14
14
  If the result is promoted to production, reassess architecture and contracts, remove shortcuts, add normal automated tests and validation, and review the result as production code rather than incrementally blessing the prototype.
15
+
16
+ Record hypothesis, setup, observed result and promotion blockers in a reproducible handoff. Reassess any shortcut before production adoption.
@@ -12,3 +12,5 @@ Form falsifiable hypotheses and request the smallest evidence needed: structured
12
12
  For high CPU, memory, thread-pool starvation, deadlock, or crash analysis, capture diagnostics with production-safe tooling and bounded duration/size. Account for collection overhead and retention/security rules. Never attach a debugger, restart, scale, change flags, clear queues/caches, or capture sensitive dumps without explicit authorization.
13
13
 
14
14
  Conclude with verified facts, root cause or ranked hypotheses, evidence gaps, safe mitigation/fix options, and a validation/monitoring plan. Keep production diagnosis separate from authorization to change production.
15
+
16
+ For performance incidents, first identify whether CPU, allocation/GC, thread-pool pressure, contention or downstream latency is dominant. Choose bounded counters, traces or dumps appropriate to the evidence and assess capture overhead and sensitive-data retention.
@@ -15,3 +15,5 @@ Prioritize containment, predictability, backward compatibility, observability, a
15
15
  6. Inspect the complete diff and report residual risk and any validation that production conditions prevented.
16
16
 
17
17
  Urgency changes breadth and speed, not safety. A temporary mitigation must be clearly identified, bounded, and not silently presented as a permanent design.
18
+
19
+ Record whether the change is a temporary mitigation or final fix, the rollout and recovery signals, rollback trigger, residual risk and follow-up owner.
@@ -22,3 +22,5 @@ Never log credentials, tokens, API keys, connection strings, authentication head
22
22
  Define one layer to own the exception event. Lower layers may add context by wrapping or enriching traces, but should not repeatedly log and rethrow the same failure. Include exceptions as exception arguments so stacks remain available internally. Preserve trace/correlation IDs across boundaries and prefer OpenTelemetry spans/metrics for high-volume timing or cardinality that does not belong in logs.
23
23
 
24
24
  Test/red-team log output when a change touches sensitive input or centralized failure handling. Verify useful fields exist and prohibited data does not.
25
+
26
+ Check trace propagation across HTTP and message boundaries, and assert sensitive values are absent from logs and telemetry in tests touching those paths.
@@ -14,3 +14,5 @@ Inspect the application's existing cache abstraction, Redis client registration,
14
14
  - Protect Redis transport with TLS and restrict access using the deployment's network and least-privilege authentication controls. Encryption in transit or at rest does not replace application-level protection of sensitive cached values. Do not log cache values, credentials, connection strings, or decrypted payloads.
15
15
  - Decide whether a Redis miss or outage should fall back to the source, fail closed, or surface an error based on the flow. Avoid a thundering herd on misses and keep any lock or refresh mechanism bounded. Add retries only when requested or required by existing architecture.
16
16
  - Test expiration, invalidation, tenant isolation, concurrent cache misses, serialization changes, and Redis failure behavior where relevant. For credential caching, verify plaintext secrecy, decrypt failures, and key rotation. Copy a valid ciphertext to another cache key, tenant/account, or credential purpose and verify decryption or use fails closed in each case.
17
+
18
+ When considering framework cache features such as HybridCache, check the target framework and installed versions, existing cache contracts, expiration and stampede behavior before adopting them.
@@ -20,3 +20,5 @@ Do not add custom retries merely because transient failures are possible. Add th
20
20
  Read only the matching provider reference: [PostgreSQL](references/postgresql.md) or [Oracle](references/oracle.md).
21
21
 
22
22
  For EF Core work, load `ef-core-safety` for ORM behavior. Load this skill and only the matching provider reference as well when the task depends on provider-specific SQL, type mapping, connection, transaction, or resilience semantics; do not load both for provider-agnostic EF Core changes.
23
+
24
+ Use provider-representative tests for transaction, null, precision, cancellation and pagination behavior where practical; explicitly record provider limitations if the test environment cannot reproduce them.
@@ -12,3 +12,5 @@ description: >
12
12
  Inspect existing policies, timeouts, cancellation, and failure semantics first. Retry only transient failures on operations safe to repeat, or operations with a reliable idempotency key. Bound attempts, total time, and concurrency; use backoff with jitter where appropriate. Honor server retry guidance when supported.
13
13
 
14
14
  Never retry validation failures or permanent authorization errors. Avoid layered retries that multiply calls and costs. Account for duplicate messages and ambiguous outcomes. Test the retry boundary with representative transient and permanent failures, and report the operational tradeoff.
15
+
16
+ Also review the overall deadline, concurrency limits and existing circuit-breaker or bulkhead behavior. Ensure layered policies do not multiply attempts. Configure unsafe-write retries only when the operation is demonstrably safe to repeat.
@@ -49,3 +49,5 @@ Never silently substitute a different operation. Ask before a correction changes
49
49
  ## Destructive-action safety
50
50
 
51
51
  For destructive or hard-to-recover actions, resolve and display exact targets first, prefer a reversible operation, and obtain approval when scope is not already explicit. Never use a home directory, repository root, filesystem root, or an unvalidated variable as a recursive deletion target.
52
+
53
+ For paths containing spaces, pass arguments separately where possible and verify the intended working directory before retrying. A status request or authorized action should not trigger unrelated environment changes.
@@ -14,3 +14,5 @@ Before editing shared code:
14
14
  5. Test the changed scenario and representative unaffected consumers, especially default behavior.
15
15
 
16
16
  Existing unusual or duplicated code is not permission to clean it up. If impact cannot be bounded with available evidence, state the uncertainty before making a high-blast-radius change.
17
+
18
+ For high-impact changes, record a compact matrix of consumer, current contract, intended change, unaffected scenario and verification evidence.
@@ -28,3 +28,5 @@ Choose the smallest matching workflow. Do not turn classification into a deliver
28
28
  Add `api-contract-safety`, `exception-handling`, `production-logging`, `ef-core-safety`, `distributed-workflows`, `dependency-management`, or `production-debugging` only when their subject is actually involved. Never preload unrelated cloud or database provider guidance. End code-changing work with `diff-review` and proportionate `targeted-validation`.
29
29
 
30
30
  For every category, preserve unrelated behavior, constrain the blast radius, and inspect shared dependencies. Task size changes investigation and validation depth, never safety standards.
31
+
32
+ For outbound HTTP integration, load `http-client-integrations`; for boundary tests load `integration-testing-dotnet`. Load `observability-dotnet`, `performance-diagnostics-dotnet`, `background-services-dotnet`, or `deployment-readiness-dotnet` only when the specific task involves those concerns.
@@ -7,7 +7,7 @@ description: Use when adding or improving focused .NET unit tests for changed bu
7
7
 
8
8
  Follow the test framework, assertion style, mocking library, naming, fixture, and data-builder conventions already present. Do not introduce a competing framework without necessity.
9
9
 
10
- Aim for roughly 90-100% meaningful coverage of new or materially changed testable production business logic when practical, not the legacy repository. Coverage is a signal: maximize useful behavioral confidence with maintainable tests and reasonable CI time, not raw test count or percentage.
10
+ Follow the repository or team coverage target for new or materially changed testable business logic when one exists. Coverage is a signal: maximize useful behavioral confidence with maintainable tests and reasonable CI time, not raw test count or percentage.
11
11
 
12
12
  Cover applicable happy paths, validation, boundaries, null/empty cases, important branches, error behavior, and customer/region/flow-specific conditions. When shared behavior changes, verify both changed and representative unchanged consumers.
13
13
 
@@ -20,3 +20,5 @@ Do not repeatedly test framework behavior, duplicate the same branch through imp
20
20
  Run the narrowest affected test first. Consider CI cost before adding slow combinations, large fixtures, or redundant integration coverage. Do not rewrite unrelated tests or mask a product defect by weakening assertions.
21
21
 
22
22
  For a clearly user- or repository-identified POC, tests are optional; validate feasibility instead. Restore normal test expectations when experimental code becomes production code.
23
+
24
+ Use established test seams for time, randomness, cancellation and concurrency. Exercise behavior at stable boundaries; use integration tests where provider or HTTP semantics matter.