Skip to content

refactor(api): split the endpoint groups out of Program.cs - #1257

Merged
mforce merged 6 commits into
mainfrom
refactor/1215-program-cs
Oct 12, 2026
Merged

mforce merged 6 commits into
mainfrom
refactor/1215-program-cs

Conversation

@mforce

@mforce mforce commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Part of #1215

Moves the /api/v1 endpoint-group registration out of Program.cs into MapCluckworkEndpointGroups in src/Cluckwork.Api/Endpoints/CluckworkEndpointGroups.cs. Program.cs calls it from the same position. Program.cs goes from 630 to 478 lines and leaves the FileSizeLimitTests legacy list. Nothing else changes behavior.

What moved and what stayed

Moved, verbatim and re-indented by eight spaces: the 20 MapGroup(...).Map*Endpoints() chains, the OAuth/MCP block that maps only when an issuer is configured, and the client-errors group (base lines 361–494).

Stayed in Program.cs:

  • the healthcheck early return and the ProcessRoles computation
  • service registration, boot guards, CLI dispatch and the one-shot assert
  • the whole middleware pipeline
  • every direct route handler: /error, /api/{**rest}, /health/{**rest} and the SPA fallback

Endpoint-group order relative to the middleware and to the routes after it is unchanged. Moving the endpoint groups was the only cut that keeps registration order and moves nothing an in-test guard reads. tools/oauth/mutation-check.sh is the one reader that had to follow.

The class lives in Cluckwork.Api.Endpoints, not Hosting. Hosting is outside the adapter-reach roots. Under Hosting, a handler later added inside this method could take AppDbContext or reach a new module and still pass the reach guard. The same line in Program.cs fails it. Under Endpoints the guard walks the method. Its reach is empty (WebApplication and CluckworkIdentityRegistration are Platform), so the ledger and the coupling matrix are unchanged. Regenerating the matrix produced no diff.

Readers of Program.cs

Reader What it reads Result
CredentialEpochMiddlewareOrderTests the UseAuthentication … IdempotencyMiddleware sequence and UseExceptionHandler(, by path not moved; green
AdapterReach top-level walk Map* route calls in Program.cs top-level statements the four handlers stay with the same keys; MapGroup is not a route call
AdapterReach type walk methods in adapter-root namespaces now also walks MapCluckworkEndpointGroups; empty reach, no ledger row
ModuleLedger, SeamSurface, AdapterTier, NamespaceFolderAgreement the whole src/ tree green; Api.* is the Platform hub, and MapMcp is still in Hosting/CluckworkMcp.cs
tools/oauth/mutation-check.sh three mutants anchored on the moved text repointed: new file key ENDPOINT_GROUPS, anchors re-indented; each matches once
#271 AddSingleton/AddHostedService census call sites under src/ none in the moved block; count and files unchanged
docs/architecture.md, decisions 806 and 846 prose about Program.cs still accurate

Proof of a pure move

  • Base Program.cs lines 361–494 equal the new method body byte for byte after removing the eight-space indent (134 lines).
  • The rest of Program.cs is byte-identical to base, apart from the usings and the one call line. The diff removes 20 usings, which only the moved block needed, and adds using Cluckwork.Api.Endpoints;.

Route parity

A temporary WebApplicationFactory test dumped EndpointDataSource in enumeration order on base and head. It recorded pattern, HTTP methods, order, names, handler signatures and metadata: authorization policies, anonymous access, rate limits, body caps and tags. It ran in four cases:

OAuth issuer SPA shell Endpoints Singleton/hosted descriptors Base vs head
absent absent 118 219 identical
absent present 118 219 identical
present absent 123 688 identical
present present 123 688 identical

The comparison ignores only ParameterInfo.MetadataToken values, which are row ids in the assembly metadata table and shift when a method is added.

Checks

  • dotnet build Cluckwork.slnx: 0 warnings, 0 errors (IDE0005 enforced).
  • Application.Tests filtered to FileSizeLimit, AdapterReach, AdapterTier, ModuleLedger, CouplingMatrix, SeamSurface and NamespaceFolderAgreement: 237/237.
  • Integration tests (Docker) filtered to CredentialEpochMiddlewareOrder, ProcessRoleGuard, ProcessRoleRegistry, McpRouteParity, McpEndpoint, OAuthFailClosed, ClientErrorReport and ResponseCacheControl: 212/212.
  • Adapter-reach gap closed. A probe MapGet with AppDbContext and ICommerceModule parameters inside the new method turns AdapterReachRealTreeTests red for both the forbidden persistence type and the undeclared Commerce reach. With the probe removed, the test is green again.
  • tools/oauth/mutation-check.sh with MUTANT_FILTER on the three repointed mutants: all 3 killed (farm-apps-not-owner-only, mcp-mapped-without-issuer, customers-route-admin-only). Baseline and restore runs were both 509/509 green.

Merged with main at 56f90ac

The merge brought in #1256 and #1258 through #1266. One conflict, in FileSizeLimitTests.cs: I took main's Legacy list and removed only the Program.cs row, leaving web/src/styles.css. Main's one Program.cs change (UseTrustedForwardedHeaders, #1260) sits in the pipeline that stays in Program.cs and merged cleanly. tools/oauth/mutation-check.sh merged cleanly and still points its three mutants at CluckworkEndpointGroups.cs. The merge needed no change to module-ledger.json, the adapter rows or the coupling matrix.

Repointed citations (commit 45cbc59):

Where Old New
tools/verify/features/products.md:120 src/Cluckwork.Api/Program.cs:556,574 src/Cluckwork.Api/Program.cs:404,422 (the two "Concurrency conflict" titles in /error)
src/Cluckwork.Api/Modules/Insights/Export/ExportEndpoints.cs:11 group policy in Program.cs group policy in CluckworkEndpointGroups.cs

Plans, designs and decision-record narratives keep their old citations as history.

Checks on the merged head:

  • dotnet build Cluckwork.slnx: 0 warnings, 0 errors.
  • Application.Tests filtered to FileSizeLimit, ModuleLedger, AdapterReach, AdapterTier, TenantBypass, AuditVocabulary, CouplingMatrix, SeamSurface, ProcessRole, OneShotVerb, CliDispatcher and NamespaceFolderAgreement: 306/306.
  • Integration tests, same filter as above: 212/212.
  • The adapter-reach probe inside MapCluckworkEndpointGroups is still red for both the forbidden AppDbContext and the undeclared Commerce reach, and green again once removed.

Move the /api/v1 MapGroup chains, the OAuth/MCP conditional mapping and
the client-errors group verbatim into Hosting/CluckworkEndpointGroups.cs,
called from the same position in Program.cs. Program.cs drops to 477
lines and leaves the FileSizeLimitTests legacy list. The three OAuth
mutation-check mutants that anchored on the moved text now target the
new file.

Part of #1215
Cluckwork.Api.Hosting is outside AdapterReach's roots, so a direct route
handler added inside MapCluckworkEndpointGroups escaped the persistence
ban and the module-reach ledger that the same line in Program.cs meets.
Move the class to Cluckwork.Api.Endpoints, an adapter root, and repoint
the mutation-check path.

Part of #1215
@mforce mforce added this to the Platform hardening milestone Oct 12, 2026
# Conflicts:
#	tests/Cluckwork.Application.Tests/Architecture/FileSizeLimitTests.cs
The /error ProblemDetails titles moved up to Program.cs:404,422, and the
/export group policy now sits in CluckworkEndpointGroups.cs.

Part of #1215
# Conflicts:
#	tests/Cluckwork.Application.Tests/Architecture/FileSizeLimitTests.cs
@mforce
mforce merged commit 497e29e into main Oct 12, 2026
21 checks passed
@mforce
mforce deleted the refactor/1215-program-cs branch October 12, 2026 17:41
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