Skip to content

Contracts completion: web-contracts-tests (083) + server-side CreateRole with backend validation (079)#270

Merged
StevenTCramer merged 2 commits into
masterfrom
dev
Jul 2, 2026
Merged

Contracts completion: web-contracts-tests (083) + server-side CreateRole with backend validation (079)#270
StevenTCramer merged 2 commits into
masterfrom
dev

Conversation

@StevenTCramer

Copy link
Copy Markdown
Contributor

Summary

The final two contracts-arc tasks, sequenced tests-first deliberately.

083 — web-contracts-tests (Decision 3 build-out)

Host-free Fixie+Shouldly project referencing web-contracts only, so serialization is checkable in the contract-first window (before any server exists). 7 tests targeting shapes where serialization can actually diverge:

  • ctor+Guard Responses bind camelCase JSON to constructor parameters — and Guard invariants run during deserialization (Guid.Empty roleId throws rather than materializing an invalid Response)
  • ListResponse<RoleDto> envelope; source-generated [ApiRoute] route property; SharedProblemDetails extension-data losslessness (validation errors + traceId both directions)
  • Trivial POCO round-trips deliberately skipped (documented). dev test discovers the project via the tests/ glob automatically.

079 — server-side CreateRole + backend validation

Completes the RoleForm round-trip that previously 405'd:

  • CreateRoleEndpoint (BaseEndpoint MVC shim, per web-server slice convention) + handler (deliberate, documented in-memory stub)
  • Backend validation with zero new code: FluentValidationBehavior runs the contract's composed Validator (shared RoleDetailsValidator + AuthApiRequestValidator) server-side; integration tests prove both 400 rejection paths by property name
  • Prerequisite: BaseEndpoint/BaseFastEndpoint TResponse : BaseResponse constraint loosened to class (Decision 5 made ctor+Guard Responses first-class)
  • All roles route warts fixed: {RoleId:guid} everywhere, plural resource routes, removed stray Guid Guid property and RPC-style api/DeleteRole + hand-declared int RoleId. The 083 tests caught the generated-property type change — tests-first sequencing working as intended.

Verification

dev build 0/0 · web-server integration 18 passed (was 11) · contracts round-trips 7/7 · analyzer 21/21 · sourcegen 14/14

Board

083, 079 done. New task 085: collected analyzer/source-gen inference-removal candidates (endpoint↔contract verb agreement, missing-endpoint detection, canonical JsonSerializerOptions, generated mock-factory registry, Aspire resource names).

🤖 Generated with Claude Code

StevenTCramer and others added 2 commits July 2, 2026 18:21
…(Decision 3 build-out)

Dedicated Fixie+Shouldly project referencing web-contracts ONLY, so contract
serialization is checkable in the contract-first window (before any server
exists — the BFF workflow the skill teaches). dev test discovers it via the
tests/ glob automatically.

7 tests targeting shapes where serialization can actually diverge (per the
resolved RFC Decision 3 prioritization; trivial POCO round-trips deliberately
skipped and the skip documented):
- ctor+Guard Responses: camelCase JSON binds to constructor parameters, and
  Guard invariants run DURING deserialization (Guid.Empty roleId throws
  rather than materializing an invalid Response)
- GetRoles.Response: ListResponse<RoleDto> envelope (base get-only props via
  derived ctor)
- GetRole.Query: source-generated [ApiRoute] route property round-trips
- SharedProblemDetails: validation errors + traceId survive the Extensions
  extension-data catch-all in both directions

Inference-removal candidate (standing directive): canonical
JsonSerializerOptions now exists in three places by convention (web-spa
program.cs, web-spa-integration-tests, this project) — hoist one declaration
into foundation-contracts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…all roles route warts

Completes the RoleForm round-trip: POST api/Roles now has a real endpoint
(BaseEndpoint MVC shim, mirroring the web-server slice pattern) and handler
(deliberate in-memory stub, documented). Backend validation costs zero new
code: FluentValidationBehavior runs the contract's composed Validator
(shared RoleDetailsValidator + AuthApiRequestValidator) server-side.

Prerequisite fix: BaseEndpoint/BaseFastEndpoint constrained
TResponse : BaseResponse, which would force Responses back into the shape
RFC Decision 5 rejected -> loosened to class (Send uses no BaseResponse
member; both bases kept aligned).

Roles route warts fixed (unblocks 078 Edit/View):
- get-role:   {RoleId:min(1)}       -> {RoleId:guid}
- update-role: api/Role/{RoleId:int} -> api/Roles/{RoleId:guid}; removed
  stray `Guid Guid` property
- delete-role: RPC-style api/DeleteRole -> api/Roles/{RoleId:guid}; removed
  hand-declared `required int RoleId` (generator emits it from the route)
The 083 serialization tests caught the generated-property type change
(RoleId int -> Guid) exactly as the tests-first sequencing intended.

Integration tests (web-server, real host): 200 + non-empty RoleId on valid
command; 400 problem-details naming the property for empty Name and empty
UserId. Suite 11 -> 18 passed. dev build 0/0; contracts 7/7; analyzer 21/21;
sourcegen 14/14.

New task 085: collected analyzer/source-gen inference-removal candidates
(endpoint<->contract verb agreement, missing-endpoint detection, canonical
JsonSerializerOptions, generated mock-factory registry, Aspire resource
names, base-endpoint alignment).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@StevenTCramer StevenTCramer merged commit f3b5734 into master Jul 2, 2026
1 check passed
@StevenTCramer StevenTCramer deleted the dev branch July 2, 2026 11:36
@StevenTCramer StevenTCramer restored the dev branch July 2, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant