Skip to content
Back to skills

Verify Ddd Tdd

ASecurity

Use after /implement-tdd, before the next batch: audits a .NET batch (correctness, reuse, simplification, cost, plan conformance, test policy, TDD evidence). Fast by default, full on request.

  • 7 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 19, 2026
testinggoexpressgitapi

Works with

  • api

Security analysis

A100/100

Scanned October 19, 2026

npx -y skills add pierrebelin/claude-code-toolkit --skill verify-ddd-tdd --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Verify Ddd Tdd?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Verify Ddd Tdd
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/pierrebelin-verify-ddd-tdd/badge)](https://www.skillsdirectory.com/skills/pierrebelin-verify-ddd-tdd)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: verify-ddd-tdd
description: "Use after /implement-tdd, before the next batch: audits a .NET batch (correctness, reuse, simplification, cost, plan conformance, test policy, TDD evidence). Fast by default, full on request."
context: fork
agent: cctoolkit:ddd-tdd-auditor
background: false
---

# DDD + TDD verification

Audit, never modify. Covers a batch implemented by `/implement-tdd`, never a feature without plan. Validations run the repo's configured commands (`commands.build`, `commands.test`), resolved as in `skills/implement-tdd/references/test-scope.md` § Runner.

One table (§2): code axes first — correctness, reuse, simplification, cost, placement, comments — judging delivered code as is; then the axes tying code to the sheet — test policy, plan traceability, scope. The plan is not the ultimate reference: it may change mid-batch, so a code/plan gap gets classified (§2).

$ARGUMENTS

## Modes

- **Fast**, default: global plan + batch sheet, DDD/APP/PERF coverage, applied ids, diff, modified files, targeted tests.
- **Full**, with `full` in argument: widens to touched boundaries, adds whole fast suites (§3.4). Never the whole `IntegrationTests` suite.
- **Resume**, with `resume`: re-audit after correction. Scope = previous verdict's deviation table + the correction's change set, both supplied by the caller — the change set read off the tree (`cctoolkit audit-round`), never the files the correction declared. Read only those files and their diff; re-judge only the axes and suites the deviations reach; nothing already verdicted is re-established. A changed file that is neither cited as a deviation's evidence nor the test of one is a **Scope** Major, unless the correction declared it as an extension whose reason a deviation's closure required. A gap the correction contested gets its answer (§ Contested findings).

Coverage: read the compact indexes `ddd-rules.md` + `architecture-rules.md` (under 6 kB), then the lines of the ids the sheet applies. `ddd-examples.md` only if an id stays ambiguous.

## Workflow

### 1. Establish the scope

1. Require `batch FX`. The caller supplies the sheet's FX section and the capture of `cctoolkit audit-capture`: status, `diff --check`, modified files, diff, `cctoolkit rules-coverage --untested` and `--ids <sheet>`, `cctoolkit access-cost --diff`, build / `ArchitectureTests` exit codes. Use it as is; read the plan or sheet yourself only if missing or contradicting the repo. No capture → produce status, check and diff yourself, one command.
2. No full coverage, or no **Design** section: still audit the code (§2), report the plan gap as **Major**, fix = update sheet. Every id is `applied` on a sheet `kit:applied-rules` row, or `N/A — reason` once on the global plan's `kit:na-rules` line. The capture's `not cited` line settles the mechanical half — an id listed there = **Blocking** unclassified id. Yours: whether a stated `N/A` reason holds. Never infer design from the implementation.
3. Walk the diff **hunk by hunk**, tie each to an RM/CU or sheet step; untied = **Scope** deviation. Read beyond a hunk only when the axis being judged needs it. Expected diff already committed → require an explicit base in argument.

### 2. Audit the delivered code

One table, one pass, over the batch diff. A green test proves nothing here. Ids cited = those of `ddd-rules.md` + `architecture-rules.md`: read the id line before invoking it.

| Axis | What counts as a deviation | Evidence required to report it |
|------|----------------------------|--------------------------------|
| Correctness | Untreated error path; absence or `null` unhandled; wrong comparison boundary; operation order leaving invalid intermediate state; swallowed exception; silent default masking failure; concurrent write on same aggregate, no concurrency handling. Command modifying or saving >1 aggregate outside DDD-08 exception stated with its consistency. Persistence-constraint violation not translated into domain exception (APP-03), or translated by generic filter (`Contains("duplicate")`) instead of one naming index — upstream uniqueness check = early failure, not deviation; missing translation = deviation. | Concrete breaking scenario, `inputs X → wrong behaviour Y`. No scenario → no report. |
| Reuse | Type, service, VO or method created while existing element covers need, or 80 % of it. Second type of existing shape: rename or extend existing, never duplicate. | Existing element as `path:line`. No named element → no report. |
| Simplification | Defensive branch on case an invariant of batch makes impossible — symmetrically, invariant announced in sheet removing no branch, loop, grouping or read is itself deviation. Indirection, wrapper or intermediate mapping with single caller. Dead code introduced or orphaned by batch; parameter never read; optional parameter or default no caller supplies; abstraction with no second implementer. Nullable collection in Domain/Application, or optional concept tested `is null` at every use instead of modelled (DDD-11). **Pre-existing** dead code = Minor: removing it lies outside batch scope, unless batch worsens it (§2 `Worsened`). | Line + concrete effect. No stylistic preference, no alternative-architecture suggestion, no proposed rewrite. |
| Cost | Capture's access-cost section lists the calls: judge from it, open a hunk only for an unclassified receiver or an `Include`. Flag on a line the batch added = deviation; on a pre-existing line = Minor, outside batch, unless batch worsens it (§2 `Worsened`). Repository call inside input-driven loop; unbounded read; `Include` of collection growing without limit; materialisation before filtering; one query per element (PERF-01). Bounded cost differing from sheet = `Plan` deviation, not code one. | idem |
| Placement | Business rule or validation carried by handler, repository, Infrastructure or WebAPI instead of aggregate concerned (DDD-02, APP-04) — handler orchestrates load, business call, save; never decides. Business operation in helper or static service receiving business object state; Domain Service neither stateless nor justified (DDD-09). Rule owned by external system (identity provider, external catalogue, organisation directory) replayed here, or share/transfer target validated by mere existence instead of the relationship authorising it. `Create()` and `Restore()` conflated, or repository not aggregate-centred (DDD-06, APP-03). Resource limit hand-rewritten in handler or carried by Domain instead of its owner (APP-05): WebAPI `RequestLimits`/rate limiting for transport, `PaginationBounds` at query creation, `ReadLimits` for read cap; unpaginated read with no cap. Exception: pre-check duplicating authority named elsewhere (persistence constraint, external system) is deviation only if **sole** owner of rule. | idem |
| Comments | Comment the code makes useless: paraphrase of the code, change narrative, ticket number, stale statement; XML `///` doc in a file that carries none. A comment giving a constraint, decision or workaround the code cannot carry is not a deviation. `pre-audit` lists added comments without failing: judge each from the capture's diff. | The line + what in the code already says it. |
| Test | A rule of the handler test policy broken (`test-scope.md` §5: aggregate tested directly, query or command asserted on anything else, interaction assertion); Verify snapshot of a contract test is not an interaction. Wrong or missing level (§1 of same file): diff hunk touching `src/{{PRODUCT}}.Infrastructure/` with no integration test and no waiver in sheet; contract test with no route changed. | Test as `path:line`, or uncovered Infrastructure hunk. |
| Plan | RM/CU with no code owner. Unit test without its `[Trait("RM", "{HandlerFolder}/{RM\|RL-xx}")]`, integration test proving a documented rule without it, trait citing rule absent from handler table, or a contract or E2E test carrying one. Id missing from coverage; `N/A` without reason; id applied with no owner. TDD evidence: a cycle of the capture's `TDD cycles` section without an observed RED (exit ≠ 0) before its GREEN, or a sheet without `## Cycles` whose `TDD:` ticks claim what nothing observed — **except** declarative artifacts listed in `common-rules.md` §4.5, written by orchestrator with no red before them (assumed, not deviation, as long as they carry no branch, validation or mapping decision), and methods a RED listed as unreachable. A `stubs with logic` line of the capture is a stub the RED check saw carrying a branch: code written before its test unless the line is pure declaration — judge it, Blocking when it is. A decision the run took without the user is listed by the caller for the user to validate (`TO-VALIDATE.md`): never a deviation for being absent from the sheet. | RM/CU or id, and where evidence is missing. |
| Scope | Diff hunk with no RM/CU nor sheet step carrying it. Refactor, renaming, reformatting, reorganisation of working code batch had no reason to touch. Adjacent bug fixed outside batch RM/CU. Unrequested removal of pre-existing dead code or comment outside touched lines. Flexibility, configurability or abstraction with no expressed need. | Hunk as `path:line` + missing RM/CU or sheet step. Line required by delivered behaviour — propagated signature, DI registration, newly necessary `using` — is traced: not deviation. |

Locating the existing element behind a `Reuse` or `Placement` deviation: `graphify explain|affected "X"` first, `grep -rn` scoped to the layer folder otherwise.

**Bug class** — a Correctness, Cost or Placement deviation is a pattern, not a line. Before reporting it, `git grep -n` that pattern over the files the batch changed: every instance goes in the same gap, `Evidence` listing each `path:line`, `Closure` covering them all. Fixed one instance at a time, the class comes back each round.

**`Worsened`** — pre-existing defect the batch makes measurably worse, judged as if batch introduced it: severity of its axis, `Gap` cell prefixed `(worsened)`. Worse means one more of the same thing: one more repository call in an already looping path, one more branch in an already defensive chain, one more copy of an already duplicated block, one more caller of a pre-existing unbounded read. Evidence: pre-existing state (context line of hunk, or `path:line` at base) **and** batch line adding to it. Untouched pre-existing defect, or one batch merely sits next to, stays Minor. Fix expected: only what batch added, never pre-existing part — outside scope.

No evidence → finding not reported. Symmetrically, missing evidence never a favourable assumption: cite file and line where deviation observed, or say point could not be verified.

Don't propose adding a comment, XML doc, anticipatory abstraction or isolated aggregate test: they are deviations, not fixes.

Classify every code/plan divergence before reporting it, one explicit line:

- **Faulty code** — plan still right, implementation departs. Fix: code.
- **Stale plan** — implementation better, or decision settled mid-batch. Fix: sheet, plus source spec if RM/CU moves. Severity **Minor** — the code is the reference, the sheet a plan; **Major** only when an RM/CU moves and the spec must follow.
- **Unsettleable divergence** — both readings hold. Report both, arbitration to user. Never decide in plan's place.

RM/CU with no code owner stays blocking in all three cases: hole, not divergence. Traceability reads both ways: RM → code, code → RM.

### 3. Run the minimal validations

Runner, filters, suite scope, integration filter → `skills/implement-tdd/references/test-scope.md`. Test volume is an audit decision: never re-run what `/implement-tdd` or the capture already ran — read its exit code, run only what is missing or was scoped too narrowly.

1. Build + `ArchitectureTests`: exit codes from the capture. What `ArchitectureTests` locks is not re-argued; what it breaks is blocking.
2. Tests named in the sheet: targeted filter first.
3. Suites the diff makes mandatory, whole or filtered per §2 of that file.
4. `full`: adds `UnitTests` + `ContractTests` in full.

No green without exit code `0`. Distinguish not run, skipped, failed. The `Validations` line carries each command's **scope**: a filter without scope reads as a full suite.

## Severities

- **Blocking** — any of the four rules of `test-scope.md` §5, RM/CU with no code owner, unclassified id, rule applied with no owner, red `ArchitectureTests`, diff touching `src/{{PRODUCT}}.Infrastructure/` with no integration test and no written waiver, cycle without observed RED (or TDD evidence ticked without observation on a sheet without `## Cycles`), any Correctness deviation carrying breaking scenario.
- **Major** — missed reuse of named existing element, unbounded cost, business rule outside its aggregate, resource limit outside its owner (APP-05: WebAPI `RequestLimits`, `PaginationBounds`, `ReadLimits`), comment in production, stale plan moving an RM/CU, hunk outside batch scope.
- **Minor** — simplification with no functional consequence, pre-existing dead code or cost reported (observation, not request to fix), stale plan with no RM/CU moving. Pre-existing defect worsened by batch is never Minor by origin: severity of its axis.

Verdict `GAPS` as soon as Blocking or Major exists. Minors listed under `VALID` verdict without calling it into question.

## Verdict

Verdict block alone, no preamble, no recap of plan, files or logs; on failure ≤6 useful lines of the command output. Ceiling **1.5 kB for `VALID`, 3 kB for `GAPS`** — the calling session carries it every later turn. Headings, severities and axis labels are frozen literals (`learn-candidates.py` parses them). End with one of these two formats, verbatim:

```markdown
## Verdict — VALID

| RM/CU or rule | Code evidence | Test evidence |
|---------------|---------------|---------------|
| RM-01 / DDD-02 / APP-01 | `path:line` | `Should...` |

Code — minors (do not block the next batch):
| Axis | Finding | Evidence |
|------|---------|----------|
| Simplification | Defensive branch on a case excluded by the invariant | `path:line` |

Scope: `[n]` hunks, all traced to an RM/CU or step — otherwise list the untraced hunks
Assumptions: `Hn` — `[assumption]`, to be validated by `[who]` — or "none"
Reported without fixing: `[pre-existing dead code or adjacent bug]` — `path:line`

Validations: `[command]` — exit 0, scope `[filter or "whole suite"]`, `[n]` tests
Not run: `[suite]` — `[reason]`
```

```markdown
## Verdict — GAPS

| Severity | Axis | Gap | Evidence | Closure | Expected fix |
|----------|------|-----|----------|---------|--------------|
| Blocking | Correctness | Unhandled absence: `inputs X → wrong behaviour Y` | `path:line` | `inputs X` → `outcome Z`, a test proving it | Handle the missing case in the aggregate |
| Blocking | Test | Spy in a handler test | `path:line` | No interaction assertion left in the test | Assert the result or SavedEvents depending on the handler type |
| Major | Reuse | Second type of the same shape as the existing one | `path:line` | One type of that shape | Rename and extend `path:line` |
| Major | Cost | (worsened) Second repository call in a pre-existing loop | `path:line` | The batch adds no call inside the loop | Remove the call the batch added |
| Major | Plan | Stale plan: an RM moves, the sheet and the spec still state the old one | `path:line` | Sheet and spec state the delivered RM | Update the sheet, and the spec if an RM moves |
| Major | Scope | Hunk with no RM/CU nor owning step | `path:line` | Every hunk traced | Revert the hunk, or tie it to a step of the sheet |

Validations: `[command]` — exit N, scope `[filter or "whole suite"]` / not run
```

`Closure` = the observable state that closes the gap, checkable by reading the code or running a test; `Expected fix` is one way to reach it, never an order.

## Contested findings

The correction may contest a gap instead of applying it, only by naming a concrete harm its closure would do: a behaviour it breaks, an invariant it violates, a cost it adds. "Complex", "out of scope", "not needed" open no contest: the gap is applied and the objection recorded. The resume audit answers each contest once, never by repeating the gap:

- **Accept** — the harm holds and outweighs the gap: the finding closes, the trade-off goes to the user's review.
- **Counter** — another closure reaches the gap without the harm: state it; the next round applies it.
- **Refute** — the harm does not hold: why, with evidence `path:line`; the next round applies the gap.
- **Escalate** — both readings hold and the choice is the user's: it goes to the user's review, nothing waits on it.

Fix nothing here; fixing belongs to `/implement-tdd`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.