Cephalon REST Endpoint Authoring Strategy
Decision baseline date: April 14, 2026
Related issues: ENG-058-T55 / GitHub issue #313, ENG-058-T56 / GitHub issue #314, ENG-058-T57 / GitHub issue #318, ENG-058-T58 / GitHub issue #320, ENG-058-T61 / GitHub issue #324, ENG-058-T62 / GitHub issue #325, ENG-058-T63 / GitHub issue #326, ENG-058-T64 / GitHub issue #327, ENG-058-T65 / GitHub issue #329, ENG-058-T66 / GitHub issue #331, ENG-058-T67 / GitHub issue #332, ENG-058-T68 / GitHub issue #333, ENG-058-T69 / GitHub issue #334, ENG-058-T70 / GitHub issue #335, ENG-058-T71 / GitHub issue #336, ENG-058-T72 / GitHub issue #337, ENG-058-T73 / GitHub issue #338, ENG-058-T74 / GitHub issue #339, ENG-058-T75 / GitHub issue #340, ENG-058-T76 / GitHub issue #341, ENG-058-T77 / GitHub issue #342, ENG-058-T78 / GitHub issue #343, ENG-058-T79 / GitHub issue #344, ENG-058-T80 / GitHub issue #345, ENG-058-T81 / GitHub issue #346, ENG-058-T82 / GitHub issue #347, ENG-058-T83 / GitHub issue #348, ENG-058-T84 / GitHub issue #349, ENG-058-T85 / GitHub issue #350, ENG-058-T86 / GitHub issue #351, ENG-058-T87 / GitHub issue #352, ENG-058-T88 / GitHub issue #353, ENG-058-T89 / GitHub issue #354, ENG-058-T90 / GitHub issue #355, ENG-058-T91 / GitHub issue #356, ENG-058-T92 / GitHub issue #357, ENG-058-T93 / GitHub issue #358, ENG-058-T94 / GitHub issue #359, ENG-058-T95 / GitHub issue #360, ENG-058-T96 / GitHub issue #361, ENG-058-T97 / GitHub issue #362, ENG-058-T98 / GitHub issue #363, ENG-058-T99 / GitHub issue #364, ENG-058-T100 / GitHub issue #365, ENG-058-T101 / GitHub issue #366, ENG-058-T102 / GitHub issue #368, ENG-058-T103 / GitHub issue #369, ENG-058-T104 / GitHub issue #370, ENG-058-T105 / GitHub issue #371, ENG-058-T106 / GitHub issue #372, ENG-058-T107 / GitHub issue #373, ENG-058-T108 / GitHub issue #374, ENG-058-T109 / GitHub issue #375, ENG-058-T110 / GitHub issue #376, ENG-058-T111 / GitHub issue #377, ENG-058-T112 / GitHub issue #378, ENG-058-T113 / GitHub issue #379, ENG-058-T114 / GitHub issue #380, ENG-058-T115 / GitHub issue #381, ENG-058-T116 / GitHub issue #382, ENG-058-T117 / GitHub issue #383, ENG-058-T118 / GitHub issue #384, ENG-058-T119 / GitHub issue #385, ENG-058-T120 / GitHub issue #386, ENG-058-T121 / GitHub issue #387, ENG-058-T122 / GitHub issue #388, ENG-058-T123 / GitHub issue #389, ENG-058-T124 / GitHub issue #390, ENG-058-T125 / GitHub issue #391, ENG-058-T126 / GitHub issue #392, ENG-058-T127 / GitHub issue #393, ENG-058-T128 / GitHub issue #394, ENG-058-T129 / GitHub issue #395, ENG-058-T130 / GitHub issue #396, ENG-058-T131 / GitHub issue #397, ENG-058-T132 / GitHub issue #398, ENG-058-T133 / GitHub issue #399, ENG-058-T134 / GitHub issue #400
Cross-references: docs/components/behaviors-http.md, docs/module-authoring.md, docs/architecture.md, docs/architecture-review-2026-04.md, docs/project-memory.md
Purpose
Section titled “Purpose”This document captures the recommended long-term model for REST endpoint authoring in Cephalon.
It exists because Cephalon now has a correct explicit public REST path through
RestBehaviorModuleBase.ConfigureRestBehaviors(...), but the next design question is not whether
that path works. The next question is how to reduce ceremony for developers without undoing the
architectural gains that came from making public REST module-owned.
The target outcome is:
- low-code authoring for simple projects
- deterministic ownership for serious systems
- clean separation between behavior logic and public HTTP concerns
- clear override rules
- a path to evolve authoring models without rewriting existing behavior code
Ground truth from the current repo
Section titled “Ground truth from the current repo”The current shipped model is already opinionated:
- public REST is module-owned
- behavior topology is for pattern plus non-REST transports
http.restis intentionally rejected in behavior transport allowlists and topologyRestBehaviorModuleBaseis the canonical authoring path for behavior-backed public RESTBehaviorModuleBaseis the canonical path for behavior ownership without public RESTEngine:Behaviors:AutoRegisteris an opt-in fallback, not the default behavior-ownership model- the current module-owned REST DSL now compiles into one normalized internal projection contract before ASP.NET Core materializes route groups and endpoints
- host governance is still shorthand-first by default; explicit module-DSL route groups only
participate when the owning group explicitly allows host governance and the matching host rule
deliberately targets authoring style
behavior-module-dsl - route groups can now also stamp an additive original-projection governance scope for selector targeting and runtime truth, but that scope does not opt explicit module DSL into host governance by itself
That means Cephalon should not go back to a model where [AppBehavior] silently publishes a public
REST boundary by default.
If Cephalon adds a lower-ceremony REST path later, it should still require explicit REST opt-in
metadata such as a projection profile or generated module contract. [AppBehavior] plus
auto-registration alone must never be enough to publish a public REST surface.
The three proposed modes
Section titled “The three proposed modes”Mode 1: explicit module-owned REST DSL
Section titled “Mode 1: explicit module-owned REST DSL”Example:
public override void ConfigureRestBehaviors(IRestBehaviorModuleBuilder behaviors){ var group = behaviors.Group("/showcase/cart"); group.MapGet<GetCartBehavior>("/{cartId}"); group.MapPost<AddToCartBehavior>("/{cartId}/items"); group.MapDelete<RemoveFromCartBehavior>("/{cartId}/items/{productId}"); group.MapPost<CheckoutCartBehavior>("/{cartId}/checkout");}Assessment:
- strongest for deterministic ownership
- strongest for bounded-context clarity
- strongest for operator truth and future introspection
- easy to understand in large systems
- slightly more ceremony than a behavior-only authoring flow
Decision:
- keep this as the canonical Cephalon public REST path
- do not demote it to legacy or escape-hatch status
- keep explicit module DSL authoritative by default, but allow a route group to opt into host-level publication governance explicitly when a host needs to suppress or rewrite that authored boundary without changing the owning module model
Mode 2: behavior-only REST shorthand
Section titled “Mode 2: behavior-only REST shorthand”Example intent:
[AppBehavior("cart.xgetx")][BehaviorAllowedPatterns("cqrs")][BehaviorAllowedTransports("http.rest")]public sealed class XxxxBehavior : IAppBehavior<XxInput, XxOutput>Assessment:
- good for low-code DX
- bad if implemented as direct behavior-owned REST activation
- conflicts with the current module-owned public-boundary model
- weakens ownership, route governance, and explicit public-surface review
- risks accidental route publication from auto-registered behaviors
Decision:
- reject direct behavior-owned REST activation as the long-term model
- accept the underlying DX goal, but satisfy it through a lower-level projection system instead
Mode 3: explicit module mapping overrides behavior shorthand
Section titled “Mode 3: explicit module mapping overrides behavior shorthand”Assessment:
- this direction is correct
- explicit public-boundary declarations must beat implicit or convention-based projections
Decision:
- keep this rule
- strengthen it into a formal precedence model
Additional mode Cephalon should add
Section titled “Additional mode Cephalon should add”The repo needs one more mode beyond the three above.
Mode 4: normalized REST projection descriptors
Section titled “Mode 4: normalized REST projection descriptors”Cephalon should introduce one normalized descriptor layer for public REST projections.
That layer should be the internal source of truth for:
- HTTP method
- route pattern
- route group or public boundary
- input binding plan
- OpenAPI tag and candidate document version
- authorization or capability hooks that belong to the REST projection
Different authoring styles should compile into the same normalized projection model:
- explicit module DSL
- behavior-authored HTTP profile metadata
- configuration-driven projection overrides
- generated or convention-based module projections
This is the missing abstraction that lets Cephalon support low-code authoring without leaking REST
concerns directly into IAppBehavior<TIn, TOut>.
Status update:
- Step 1 of this direction is now shipped internally through the current
RestBehaviorModuleBaseDSL, which compiles into a normalized projection contract plus a dedicated materializer - Step 2 of this direction is now shipped through
IRestEndpointRuntimeCatalog,/engine/rest-endpoints,/engine/rest-endpoints/{restEndpointId},snapshot.RestEndpoints, and fail-fast collision validation on the resolved publicHTTP method + route pattern - Step 3 is now shipped through
BehaviorRestProfileAttribute,BehaviorRestMethod,BehaviorRestProfileDescriptor, source-generatedGetRestProfiles()hints, andABT0015throughABT0027, while still keeping those behavior-authored REST profiles metadata-only rather than publishing public REST directly from behaviors - Step 4 is now partially shipped through
IRestBehaviorEndpointGroupBuilder.MapProfile<TBehavior>(), which consumes those generated hints through the same explicit module-owned DSL, prefers source-generatedGetRestProfiles()material, falls back only to the explicitly targeted behavior type when generated hints are unavailable, and keeps runtime publication on the existingmodule-dslpath with additiveauthoringStyle = behavior-module-profilemetadata - the next high-value follow-through was tightening the normalized projection model with explicit binding descriptors before any broader convention-backed shorthand publication was considered
- that explicit-binding slice is now shipped through
ENG-058-T63: profile metadata can carry explicit route/query/header/body binding descriptors, module-ownedMapProfile<TBehavior>()consumes them through the same normalized projection pipeline, request composition now treats those descriptors as overrides instead of an exclusive mode, and the runtime catalog initially surfaced the resolved plan through additivebindingDescriptorsmetadata - the next hardening slice is now also shipped through
ENG-058-T64:Cephalon.Behaviors.SourceGenrejects invalid explicit binding metadata at build time throughABT0019throughABT0025, generatedGetRestProfiles()output no longer depends on hard-coded enum ordinals, andBehaviorRestProfileResolvernow fails fast when an explicit route binding names a placeholder that the declared profile route pattern does not contain - the next contract-hardening follow-through is now also shipped through
ENG-058-T141andENG-058-T142:BehaviorRestBindingSourceplusBehaviorRestMethodnow carry stable wire-name vocabularies, andCephalon.Behaviors.SourceGennow validates both profile methods and explicit binding metadata against those canonical wire-name contracts while still emitting resolved enum member names into generatedGetRestProfiles()output - the next runtime-guidance parity follow-through is now also shipped through
ENG-058-T143: runtime attribute-fallback, explicit binding-plan normalization, and last-mile profile-method conversion now echo those same canonicalget/post/put/patch/deleteandroute/query/header/bodywire names in their exception guidance, so operator and developer troubleshooting no longer diverges from the JSON/source-generation contract - the next method-guidance completion follow-through is now also shipped through
ENG-058-T144: non-body method body-binding rejections and unsupported REST method parser failures now also echo the canonicalget/post/put/patch/deletevocabulary, so the remaining runtime method-validation paths no longer drift back to enum/member-name wording - the next profile-route authoring-safety follow-through is now also shipped through
ENG-058-T117:Cephalon.Behaviors.SourceGennow rejects malformedBehaviorRestProfileAttribute.RelativePatternplaceholder syntax earlier throughABT0026, andBehaviorRestProfileResolvernow also parses the declared route pattern even when no explicit bindings are present so direct attribute fallback or stale generated hints still fail fast before shorthand publication can materialize an invalid route shape - the next explicit-binding authoring-parity follow-through is now also shipped through
ENG-058-T119: metadata-only REST profiles can now declareBehaviorRestProfile(PreserveImplicitQueryFallback = true)when they already carry explicit bindings, so profile authors can keep explicit route aliases or other explicit bindings without losing the remaining implicit query-fallback surface; later host governance can now also opt an explicit-binding shorthand candidate into that same preserved source query surface throughRestApi:Overrides:*:PreserveImplicitQueryFallbackwhen the module did not declare it up front, whileCephalon.Behaviors.SourceGenstill rejects missing-binding cases throughABT0027andBehaviorRestProfileResolverre-checks the same rule during runtime fallback - the next runtime-contract follow-through is now shipped through
ENG-058-T65: the engine-owned transport contract now publishes explicit binding plans throughRestEndpointRuntimeDescriptor.BindingDescriptors,RestEndpointBindingDescriptor, andRestEndpointBindingSource, while the ASP.NET Core host no longer duplicates that plan insidemetadata.bindingDescriptors - the next precedence-visibility follow-through is now shipped through
ENG-058-T66: the runtime now exposesIRestEndpointCandidateRuntimeCatalog,GET /engine/rest-endpoint-candidates,GET /engine/rest-endpoint-candidates/{candidateId}, andsnapshot.RestEndpointCandidates, so operators can see both published and suppressed module-owned REST candidates, while explicit module DSL mappings now suppress lower-precedence profile shorthand for the same behavior by default and surface the winning candidate id plus suppression reason explicitly - the next original-versus-effective shorthand visibility follow-through is now shipped through
ENG-058-T78: the runtime now also exposesRestEndpointCandidateProjectionDescriptorplusRestEndpointCandidateRuntimeDescriptor.OriginalProjectionso operators can compare the original shorthand route, method, version, route-group prefix, relative pattern, and binding plan against the final effectiveProjectedEndpointshape without inferring that source truth back out of the mapped endpoint - the next shorthand binding-governance follow-through is now shipped through
ENG-058-T79:Cephalon.Abstractionsnow also exposes typedRestEndpointOverrideBindingModethrough the override runtime contract,RestApi:Overridescan now declare wire-name-onlyBindingMode = merge-explicitwhen a host wants to upsert only selected explicit bindings by property name instead of restating the whole explicit plan, the existingreplace-explicitbehavior remains the default whenBindingModeis omitted, and the runtime now keeps that merge-versus-replace governance truth visible through/engine/rest-endpoint-overridesplussnapshot.RestEndpointOverrides;bindingMode = unspecifiedis preserved there only when aClearBindingsrule omitted an explicit mode, while other omitted modes still normalize toreplace-explicitormerge-explicit, and host config still accepts only those two explicit wire names - the next grouped publication-visibility follow-through is now shipped through
ENG-058-T80:Cephalon.Abstractionsnow also exposesIRestEndpointPublicationGroupRuntimeCatalogplusRestEndpointPublicationGroupDescriptor,Cephalon.AspNetCorenow publishes/engine/rest-endpoint-publication-groups,/engine/rest-endpoint-publication-groups/{behaviorId}, andsnapshot.RestEndpointPublicationGroups, and the host now groups the existing candidate-level truth per behavior so operators can inspect published candidates, precedence-suppressed candidates, governance-suppressed candidates, the winning precedence rank when one exists, and the ordered candidate set without manually joining several runtime surfaces - the next publication-group source-competition visibility follow-through is now shipped through
ENG-058-T121:Cephalon.Abstractionsnow also exposesRestEndpointPublicationGroupAuthoringStyleDescriptor, andRestEndpointPublicationGroupDescriptor.AuthoringStyleSummariesnow derives a first-class per-style summary directly from the grouped candidate truth so/engine/rest-endpoint-publication-groupsandsnapshot.RestEndpointPublicationGroupsalso show which authoring styles participated, which remained published, and which were precedence-suppressed or governance-suppressed without re-partitioning the ordered candidate set manually - the next publication-group authoring-policy contract follow-through is now shipped through
ENG-058-T122:Cephalon.Abstractionsnow also exposesRestEndpointPublicationGroupAuthoringPolicyDescriptor,RestEndpointPublicationGroupDescriptor.AuthoringPolicynow carries the effective default- versus-configured authoring-policy intent for each grouped behavior answer, andRestApi:AuthoringPolicies:{behaviorId}now bindsAllowMultiplePublishedCandidatesplus preferred/allowed/disallowed authoring-style intent so/engine/rest-endpoint-publication-groupsandsnapshot.RestEndpointPublicationGroupscan round-trip that policy truth - the next bounded authoring-policy enforcement follow-through is now shipped through
ENG-058-T123:Cephalon.Behaviors.Httpnow honorsRestApi:AuthoringPolicies:{behaviorId}:AllowMultiplePublishedCandidatesduring candidate resolution so lower-precedence shorthand candidates can remain published when governance does not suppress them, while route-collision validation still stays authoritative and effective endpoint names are now disambiguated deterministically by authoring style, route shape, and candidate identity when co-published shorthand candidates would otherwise reuse the same endpoint name - the next shorthand authoring-policy truth follow-through is now shipped through
ENG-058-T124:PreferredAuthoringStyle,AllowedAuthoringStyles, andDisallowedAuthoringStylesnow also enforce shorthand publication policy forbehavior-module-profileandbehavior-module-generatedcandidates, while explicit module DSL publication remains authoritative; grouped publication and candidate runtime truth now keep authoring-policy suppression distinct from config-governance suppression and candidate-precedence suppression through dedicated suppression kinds, policy-suppressed candidate buckets, and startup diagnostics/logging - the next authoring-policy runtime-contract conformance follow-through is now shipped through
ENG-058-T145:/engine/rest-endpoint-candidates,/engine/rest-endpoint-candidates/{candidateId}, andsnapshot.RestEndpointCandidatesnow have targeted hosting/runtime coverage that locksSuppressedByAuthoringPolicyKindonto the canonicaldisallowed-authoring-style,not-allowed-authoring-style, andpreferred-authoring-style-selectedwire names instead of leaving operator JSON truth implicit in enum serialization behavior alone - the next publication-group authoring-policy suppression-breakdown follow-through is now shipped
through
ENG-058-T146: grouped publication answers now also expose typedAuthoringPolicySuppressionSummariesat both the behavior-group level and inside eachAuthoringStyleSummariesentry, so/engine/rest-endpoint-publication-groups,/engine/rest-endpoint-publication-groups/{behaviorId}, andsnapshot.RestEndpointPublicationGroupscan distinguishdisallowed-authoring-style,not-allowed-authoring-style, andpreferred-authoring-style-selectedsuppression outcomes without forcing operators to re-join the candidate catalog manually - the next rule-centric authoring-policy runtime-answer follow-through is now shipped through
ENG-058-T152,ENG-058-T153, andENG-058-T154:Cephalon.Abstractionsnow also exposesIRestEndpointAuthoringPolicyRuntimeCatalog,RestEndpointAuthoringPolicyDescriptor,RestEndpointAuthoringPolicyAuthoringStyleDescriptor, andRestEndpointAuthoringPolicySuppressionSummaryDescriptor;Cephalon.AspNetCorenow publishes/engine/rest-endpoint-authoring-policies,/engine/rest-endpoint-authoring-policies/{behaviorId}, andsnapshot.RestEndpointAuthoringPolicies; and that top-level behavior answer keeps explicit default-versus-configured policy intent, explicitly configured-but-unmatched policies, separate retained-versus-published-versus-precedence/governance-suppressed buckets, and per-styleAuthoringStyleSummariesvisible without reopening grouped publication answers, while also keeping host-governance eligibility and skipped-rule ids visible there when explicit ownership kept later host governance out of scope - the next publication-group host-governance rule-summary follow-through is now shipped through
ENG-058-T147: grouped publication answers now also expose typedGovernanceSuppressionSummariesandGovernanceOverrideSummariesat both the behavior-group level and inside eachAuthoringStyleSummariesentry, so/engine/rest-endpoint-publication-groups,/engine/rest-endpoint-publication-groups/{behaviorId}, andsnapshot.RestEndpointPublicationGroupscan show matched-versus-suppressed host suppression outcomes plus matched/selected/applied override outcomes, including no-op winning overrides whose applied bucket remains empty, without re-reading/engine/rest-endpoint-candidates - the next low-code inline module-owned authoring follow-through is now shipped through
ENG-058-T81:Cephalon.Behaviors.Httpnow exposesRestBehaviorEngineBuilderExtensions.AddRestBehaviorModule<TMarker>(), which lets a host register a real module-owned REST surface without a dedicatedRestBehaviorModuleBasesubclass, still drives the same normalized projection/materialization/candidate/governance pipeline as the class-based DSL, usesTMarkerboth as the reusable helper’s distinct module type identity and as the source assembly marker forMapGeneratedProfiles(...), and still never publishes public REST from[AppBehavior]alone - the next low-code generated module-path follow-through is now shipped through
ENG-058-T84:IRestBehaviorModuleBuilder.GroupFromBehaviorIdPrefix(...)now derives a deterministic route group such as/showcase/cartfromshowcase.cart, andRestBehaviorEngineBuilderExtensions.AddGeneratedRestBehaviorModule<TMarker>()now wraps that same derivation for the common inline generated-profile case so the engine no longer requires authors to repeat both the route path and the behavior-id prefix manually while still using the same module-owned projection/materialization/candidate/governance pipeline and still never publishing public REST from[AppBehavior]alone - the next low-ceremony inline descriptor follow-through is now shipped through
ENG-058-T157:Cephalon.Behaviors.Httpnow also exposesmoduleId/displayName/descriptionconvenience overloads forAddRestBehaviorModule<TMarker>(),AddGeneratedRestBehaviorModule<TMarker>(configureGroup?), andAddGeneratedRestBehaviorModule<TMarker>(behaviorIdPrefix, configureGroup?)so hosts can keep the inline module-owned path terse without manually constructingModuleDescriptor; those overloads delegate to the same descriptor-based helpers, preserve the same marker-based module identity plus source-assembly semantics, keep the normalized projection/materialization/candidate/governance pipeline unchanged, and still keep the explicitbehaviorIdPrefixescape hatch when inline module identity and generated ownership should differ - the next inline grouped-generated follow-through is now also shipped through
ENG-058-T167:Cephalon.Behaviors.Httpnow also exposesAddGeneratedRestBehaviorModuleGroups<TMarker>()so hosts can keep theMapGeneratedProfileGroups(...)path low-code without a dedicated module class; the helper still materializes a real module, reuses the same marker-based module-identity plus source-assembly semantics as the existing inline helpers, lets the common overload derive the grouped generated root prefix from the inline module id while the explicitbehaviorIdPrefixandModuleDescriptoroverloads remain the escape hatches, and now reuses the same fail-fast dot-separated prefix validation regardless of which grouped-generated helper path is used - the next grouped-generated per-derived-group configuration follow-through is now also shipped
through
ENG-058-T173:Cephalon.Behaviors.Httpnow also exposes derived-prefix-awareMapGeneratedProfileGroups(...)andAddGeneratedRestBehaviorModuleGroups<TMarker>()overloads so one owning module or inline helper can branch on each derived generated behavior-id prefix before mapping profiles, keeping per-branch API version, tag, and governance-scope conventions low-code while preserving the same grouped generated ownership, candidate, publication-group, governance, and runtime-catalog path - the next stable shorthand candidate-id governance follow-through is now shipped through
ENG-058-T85: shorthand candidate ids now resolve from the original shorthand projection before host-level overrides are applied,RestApi:SuppressionsandRestApi:Overridesnow also accept exactCandidateIds, runtime suppression/override catalogs plus the snapshot now surface those configured candidate ids directly, and selector specificity now prefers candidate-targeted rules before broader behavior/module selector matches whileProjectedEndpointcontinues to answer the final effective mapped route shape - the next shorthand projected-endpoint metadata alignment follow-through is now shipped through
ENG-058-T86: shorthand candidates now project the same endpoint name, summary, and description metadata that the final behavior-backed runtime endpoint exposes, using the same operation-name/documentation conventions during candidate resolution so/engine/rest-endpoint-candidatesand/engine/rest-endpointsstay aligned for operator-facing metadata truth - the next shorthand governance-match visibility follow-through is now shipped through
ENG-058-T87: shorthand candidates now also keep the full ordered suppression-rule and override-rule match sets visible throughMatchedSuppressionIdsandMatchedOverrideIdsbeforeSuppressedBySuppressionIdorAppliedOverrideIdidentifies the selected winner, so overlapping host governance stays operator-visible without changing the existing specificity model - the next bounded shorthand route-group-prefix override follow-through is now shipped through
ENG-058-T82: the typed override/runtime contracts plus ASP.NET Core config binding now support shorthand-onlyRouteGroupPrefix, that remap must stay beneath the active REST root, cannot declare route placeholders, cannot silently change effective API-version truth, and now causes the ASP.NET Core materializer to split effective shorthand route groups when only some candidates in one authored group are remapped so actual HTTP routes, runtime catalogs, and snapshots all report the same published answer - the next shorthand explicit-binding withdrawal follow-through is now shipped through
ENG-058-T83: the typed override/runtime contracts plus ASP.NET Core config binding now also supportRemovedBindingProperties,merge-explicitnow covers both property-by-property explicit binding upserts and explicit-binding withdrawals, removal-only rules normalize to merge mode automatically,replace-explicitcannot pair with removals, a merge rule cannot both remove and override the same property, removal targets must already exist in the source shorthand explicit binding plan, and/engine/rest-endpoint-overridesplussnapshot.RestEndpointOverridesnow keep both the typed binding mode and removed-property list visible - the next shorthand explicit-binding reset follow-through is now shipped through
ENG-058-T110: the typed override/runtime contracts plus ASP.NET Core config binding now also support shorthand-onlyClearBindings, that reset can discard the source explicit binding plan so request composition returns to the implicit route/query/body baseline, it cannot pair withBindings,RemovedBindingProperties, or an explicitBindingMode, and it fails fast when the effective route would only remain satisfiable through removed explicit route-binding aliases; equivalent reorder-only override plans now also stay visible as matches while preserving source explicit binding order and leavingAppliedOverrideId = nullwhen the normalized binding set does not change - the next low-code generated module-owned shorthand is now shipped through
ENG-058-T67:IRestBehaviorEndpointGroupBuilder.MapGeneratedProfiles()andMapGeneratedProfiles(string behaviorIdPrefix)let an owning module opt into profile-backed generated publication for one owned route group, prefer source-generatedGetRestProfiles()plusGetRestProfileBehaviorTypes()hints, fall back only to a bounded scan of the explicit owning module assembly when generated type hints are unavailable, and keep runtime publication on the same normalized projection and candidate-catalog path withmetadata.authoringStyle = behavior-module-generated - the next explicit module-DSL host-governance boundary follow-through is now shipped through
ENG-058-T128:IRestBehaviorEndpointGroupBuilder.AllowHostGovernance()now lets an explicit module-owned route group opt into ASP.NET CoreRestApi:SuppressionsandRestApi:Overrideswithout changing its authoring style,RestEndpointCandidateProjectionDescriptorplus publishedOriginalProjectionnow keep that opt-in visible throughAllowsHostGovernance, shorthand candidates still participate by default, and host rules still leave explicit module DSL out of scope unless they explicitly target authoring stylebehavior-module-dsl - the next explicit module-DSL governance-visibility follow-through is now shipped through
ENG-058-T129: when host suppression or override rules target that same explicit module-DSL surface before the route group opts in, runtime candidates plus published behavior-backed endpoints now keep the ordered skipped rule ids visible throughSkippedSuppressionIdsandSkippedOverrideIdswhileMatched*stays empty, so operators can distinguish governance-ineligible explicit ownership from a simple selector miss - the next explicit module-DSL grouped-governance visibility follow-through is now shipped through
ENG-058-T130:/engine/rest-endpoint-publication-groupsplussnapshot.RestEndpointPublicationGroupsnow also keep groupedHostGovernanceEligibleCandidateIds,HostGovernanceIneligibleCandidateIds,SkippedSuppressionIds, andSkippedOverrideIdsvisible at both the top-level behavior group and per-authoring-style summary, so operators can inspect grouped publication truth without drilling into each candidate first - the next explicit module-DSL grouped skipped-governance follow-through is now shipped through
ENG-058-T148: those same grouped publication answers now also keep per-rule skipped suppression/override candidate buckets visible throughSkippedSuppressionSummariesandSkippedOverrideSummariesat both the top-level behavior group and per-authoring-style summary, so operators can see which ineligible candidates each skipped host rule targeted without re-reading/engine/rest-endpoint-candidates - the next explicit module-DSL diagnostics follow-through is now shipped through
ENG-058-T131:/engine/diagnosticsplus information-level startup logging now also emitRestEndpointGovernanceSkippedevent5206when host suppression or override rules target an explicit module-DSL candidate that did not opt into host governance, so skipped-rule visibility stays aligned across candidate, endpoint, grouped-publication, and diagnostics surfaces - the first host-governance slice is now shipped through
ENG-058-T68: ASP.NET Core hosts can suppress descriptor-backed shorthand candidates throughRestApi:Suppressions, the runtime now exposes those configured rules throughIRestEndpointSuppressionRuntimeCatalog,/engine/rest-endpoint-suppressions, andsnapshot.RestEndpointSuppressions, and suppressed candidates now distinguish governance suppression throughRestEndpointCandidateRuntimeDescriptor.SuppressedBySuppressionIdwhileRestEndpointCandidateRuntimeDescriptor.MatchedSuppressionIdskeeps every matching rule visible in specificity order - the first constrained shorthand-override slices are now shipped through
ENG-058-T69,ENG-058-T70,ENG-058-T71,ENG-058-T72,ENG-058-T73,ENG-058-T74,ENG-058-T75,ENG-058-T76,ENG-058-T82, andENG-058-T83: ASP.NET Core hosts can retarget descriptor-backed shorthand candidates throughRestApi:Overrideswhen they need a different effectiveApiVersionMajor,OpenApiDocumentName, HTTPMethod, bounded publishedRouteGroupPrefix, constrained relativePattern, and/or explicit binding plan; later follow-through also layers capability, endpoint-metadata, and tag/document governance on the same contract. The runtime now exposes those configured rules throughIRestEndpointOverrideRuntimeCatalog,/engine/rest-endpoint-overrides, andsnapshot.RestEndpointOverrides; candidates now surface the governing rule throughRestEndpointCandidateRuntimeDescriptor.AppliedOverrideIdwhen the winning rule materially changes the effective answer, and now also surface the selected winning no-op rule throughRestEndpointCandidateRuntimeDescriptor.SelectedOverrideIdplusRestEndpointCandidateRuntimeDescriptor.OverrideSelectionBasiswhileRestEndpointCandidateRuntimeDescriptor.MatchedOverrideIdskeeps every matching rule visible in specificity order, and published candidate registration now reconciles capability-only no-op matches against the actual mapped endpoint so no-op clears or same-key capability rewrites leaveAppliedOverrideId = nullwhileSelectedOverrideId,OverrideSelectionBasis, andMatchedOverrideIdsstill show which rule won, why it beat the runner-up, and which rules matched. The next declared-versus-effective override-dimension visibility follow-through is now shipped throughENG-058-T132: the typed override contract now exposesRestEndpointOverrideActionKindplusRestEndpointOverrideDescriptor.ActionKinds, while shorthand candidates and published endpoints now exposeSelectedOverrideActionKindsandAppliedOverrideActionKindsso the runtime can say which override dimensions the winning rule declared versus which ones materially changed the effective published answer; no-op winners keep the selected action kinds visible while leaving applied action kinds empty. The next diagnostics-story follow-through is now shipped throughENG-058-T133andENG-058-T134: startup diagnostics event5200now also echoes the decisive suppression selection-basis wire name, while events5202and5203now also echo the decisive override selection-basis wire name plus the selected and applied override action-kind wire names, so the operator log story matches the runtime catalog story without requiring a manual diff against the final route shape. The normalized materializer now maps the same effective projection shape that the runtime catalogs report; explicit binding-plan overrides now default to replacing the shorthand candidate’s explicit descriptors, but can also merge explicit binding upserts and withdrawals by property name throughBindingMode = merge-explicitplusRemovedBindingPropertieswhile still leaving unbound route placeholders and remaining request-body fields available for deterministic fallback, or clear the explicit plan entirely through shorthand-onlyClearBindingswhen the effective route still binds truthfully through the implicit baseline; placeholder renames can now also apply when the effective explicit route-binding plan covers the renamed placeholder set exactly; placeholder removals can now also apply when the original projection already exposes explicit route-binding coverage for the original placeholder set and the effective explicit binding plan keeps every affected original route-bound property explicitly bound; placeholder additions can now also apply when the effective explicit route-binding plan covers the full final placeholder set and every newly route-bound property was either already explicitly bound in the original projection, forPOST/PUT/PATCHalready part of the original deterministic remaining-body fallback surface, or for shorthand candidates with no explicit binding plan already part of the original implicit query-fallback surface, or for explicit shorthand profiles that intentionally preserve source implicit query fallback when the newly route-bound property still belongs to that remaining source query surface; and invalid effective method-plus-binding plans, rename attempts that still rely on inference, removal attempts that rely on inferred original route coverage or drop explicit binding coverage, or addition attempts that would promote any other implicit property into the public route now fail fast - the selector-expansion follow-through is now shipped through
ENG-058-T77,ENG-058-T109,ENG-058-T118,ENG-058-T156, andENG-058-T164: bothRestApi:SuppressionsandRestApi:Overridescan refine exactBehaviors/Modulestargeting withApiVersionMajors,Methods,RelativePatterns,RouteGroupPrefixes,OpenApiDocumentNames,TagNames,EndpointNames,BehaviorIdPrefixes, andBindingFallbackModes; those selectors match the original shorthand candidate shape before override actions are applied, withEndpointNamestargetingProjectedEndpoint.OriginalEndpointNameandBehaviorIdPrefixestargeting the original dot-separated behavior-id hierarchy, suppression now preserves that same original-shape contract even when an override later rewrites the final published endpoint, rule specificity now also considers populated selector dimensions plus narrower selector sets and narrower behavior-subtree scope, and the runtime suppression/override catalogs now expose the selector arrays directly - broader configuration-driven projection overrides that promote implicit properties into route placeholders beyond that constrained body-fallback-plus-bounded-query-fallback-plus-preserved- explicit-query-fallback path, or rewrite binding shape beyond that constrained explicit-binding upsert-plus-withdraw model, remain later work
Recommended long-term engine model
Section titled “Recommended long-term engine model”Cephalon should use a four-layer model.
Layer 1: behavior core
Section titled “Layer 1: behavior core”IAppBehavior<TIn, TOut> stays transport-neutral.
It should continue to describe:
- behavior identity
- input/output contract
- pattern defaults
- non-REST transport defaults
- generic route-shaped API surface for non-REST HTTP adapters
It should not become the primary place for public REST route ownership.
Layer 2: optional behavior-authored HTTP profile defaults
Section titled “Layer 2: optional behavior-authored HTTP profile defaults”If Cephalon adds shorthand REST metadata, it should live in an HTTP or REST companion abstraction,
not in Cephalon.Abstractions.Behaviors.
Good candidates:
- a dedicated attribute in an HTTP-facing package
- a static
ConfigureHttp(...)-style profile method in an HTTP-facing interface - a source-generator-readable profile contract that emits descriptor data at build time
This layer may declare defaults such as:
- preferred HTTP method
- preferred relative route
- preferred parameter-source hints
- preferred candidate API version
But this layer should still be metadata only. It should not directly publish public REST routes by itself.
Layer 3: module-owned public REST projection
Section titled “Layer 3: module-owned public REST projection”RestBehaviorModuleBase remains the default public-boundary owner.
For serious systems, this remains the recommended path because it makes the bounded context, route shape, and public contract explicit in one place.
For lower-ceremony systems, Cephalon now also ships generated and inline module paths that still materialize into module-owned projections at runtime, so authors can reduce ceremony without moving the public REST boundary out of this layer.
Current shipped follow-through:
RestBehaviorModuleBaseremains the class-based path for dedicated module typescephalon-rest-behavior-modulenow gives teams an adoption-readydotnet newstarter for that same class-based path, keeping module ownership, localized sample behavior wiring, and package- manifest output aligned without forcing authors to start from the genericIRestModulepath and migrate later- the shipped
cephalon-monolith,cephalon-slice, andcephalon-microservicestarters, plus the matching blueprint samples, now also begin their public REST starter modules onRestBehaviorModuleBase.ConfigureRestBehaviors(...).MapProfile<TBehavior>()wheneverRestApiis enabled, keeping app-level adoption aligned with the same settled module-owned boundary AddRestBehaviorModule<TMarker>()is now the lowest-ceremony explicit module-registration path for straightforward hosts: themoduleId/displayName/descriptionconvenience overload covers the common path, while theModuleDescriptoroverload remains available for richer inline metadata, but both still land on this same layer instead of inventing a new publication sourceGroupFromBehaviorIdPrefix(...),AddGeneratedRestBehaviorModule<TMarker>(), andAddGeneratedRestBehaviorModuleGroups<TMarker>()now cover the common generated-profile cases where one route group or one grouped generated subtree should derive from a stable generated root prefix, while the explicitbehaviorIdPrefixandModuleDescriptoroverloads remain available when inline module identity, generated ownership, or inline metadata should differ, again without inventing a new publication source; the grouped-generated module and inline-helper paths now also expose derived-prefix-aware callbacks so each derived branch can stamp its own API version, tag, or governance scope without abandoning grouped generated shorthand
Layer 4: host- or app-level projection overrides
Section titled “Layer 4: host- or app-level projection overrides”Cephalon should support configuration-driven projection overrides, but not by silently rewriting every explicit module DSL route by default.
The safe long-term rule is:
- explicit manual module mapping remains authoritative by default
- descriptor-backed convention or generated projections may be overridden from configuration
- explicit code must opt in if it wants host configuration to replace route shape or binding rules
That preserves deterministic ownership and avoids operator-side route surprises.
Current shipped baseline:
RestApi:SuppressionsandRestApi:Overridesare the first ASP.NET Core host-governance surfaces- they apply only to descriptor-backed shorthand candidates such as
MapProfile<TBehavior>()andMapGeneratedProfiles(...), including grouped generated shorthand fromMapGeneratedProfileGroups(...) - suppression runs before precedence resolution rather than silently rewriting candidates
- override currently supports
ApiVersionMajor,OpenApiDocumentName,Method, bounded publishedRouteGroupPrefix, relativePattern,RequiredCapabilityKey,ClearRequiredCapability,EndpointName,Summary,Description,TagName,ClearEndpointName,ClearSummary,ClearDescription, explicitBindings,RemovedBindingProperties, shorthand binding resets throughClearBindings, and typedBindingMode - both rule families fail fast when a rule omits every primary selector:
CandidateIds,Behaviors,BehaviorIdPrefixes,Modules, andHostGovernanceScopes - override rules also fail fast when they omit all override actions, use a non-positive
ApiVersionMajor, declare an unsupported HTTP method, declare an invalid relative route pattern, or declare an invalidRouteGroupPrefix - both rule families can target exact
Behaviors, subtreeBehaviorIdPrefixes, andModules, then refine that targeting withApiVersionMajors,Methods,RelativePatterns,RouteGroupPrefixes,OpenApiDocumentNames,TagNames,EndpointNames, andBindingFallbackModes, and those selector refiners match the original shorthand candidate shape before override actions are applied - when more than one rule matches, the host prefers the more specific rule deterministically by populated target dimensions first, then by exact behavior-targeted scope, narrower behavior-subtree scope, narrower authoring-style scope, fewer total selector values, and finally stable rule-id ordering
- neither surface overrides explicit module DSL or manual module-owned REST endpoints
- shorthand groups that declare
.ApiVersion(...)explicitly stay authoritative over host version rewrites, while shorthand method and constrained pattern overrides can still apply to those same groups - the current override slice can rewrite the effective API major version, OpenAPI document name,
HTTP method, bounded published route-group prefix, constrained relative route pattern, required
capability boundary, shorthand endpoint metadata, shorthand tag, and/or explicit binding plan
while keeping the
/api/v{major}route segment, published group boundary, OpenAPI document name, mapped endpoint, endpoint-group metadata, and runtime catalogs aligned to the same effective projection;ApiVersionMajoronly re-derives the document name when the authored shorthand group did not pin one explicitly RouteGroupPrefixrewrites stay beneath the active REST root, cannot declare placeholders, cannot silently change effective API-version truth, and now make ASP.NET Core split effective shorthand groups when only some candidates in one authored group are remapped, moved to another document, or retaggedOpenApi:EnabledVersionsand legacy document config still decide which documents are actually published- pattern rewrites preserve the placeholder set by default and can now also rename placeholders when the effective explicit route-binding plan covers the renamed placeholder set exactly
- placeholder removals can now also apply when the original projection already exposes explicit route-binding coverage for the original placeholder set and the effective explicit binding plan keeps every affected original route-bound property explicitly bound
- placeholder additions can now also apply when the effective explicit route-binding plan covers
the full final placeholder set and every newly route-bound property was either already explicitly
bound in the original projection, for
POST/PUT/PATCHalready part of the original deterministic remaining-body fallback surface, or for shorthand candidates with no explicit binding plan already part of the original implicit query-fallback surface, or for explicit shorthand candidates whose remaining source query surface was intentionally preserved either by the source profile or by a winning host override that setsPreserveImplicitQueryFallback = true BindingMode = merge-explicitcan now upsert changed explicit bindings and withdraw selected original explicit bindings throughRemovedBindingProperties, while failing fast if a removal targets a property the source shorthand never bound explicitly or if one merge rule both removes and overrides the same property- on non-body-capable methods, merge-mode withdrawals now also fail fast when they would stop
explicitly binding a source query-bound property unless that property still belongs to a source
profile that intentionally declared
BehaviorRestProfile(PreserveImplicitQueryFallback = true), a winning host override that intentionally setsPreserveImplicitQueryFallback = true, or the host intentionally resets the whole authored plan throughClearBindings = true ClearBindings = truecan now discard the source shorthand explicit binding plan entirely and return the candidate to the implicit request-binding baseline, while failing fast if the effective route would only stay valid through explicit placeholder aliases that the clear removed- broader implicit-property promotion beyond that constrained body-fallback-plus-bounded-query- fallback-plus-source-or-host-preserved-explicit-query-fallback path plus broader input-binding rewrites beyond the current replace-plus-merge-explicit upsert-plus-withdraw model remain later work
Precedence and suppression rules
Section titled “Precedence and suppression rules”Cephalon should formalize the following precedence order.
Ownership precedence
Section titled “Ownership precedence”- explicit
MapAdditionalEndpoints(...)manual routes - explicit
RestBehaviorModuleBase.ConfigureRestBehaviors(...)DSL routes such asMapGet/MapPost/... - explicit profile-consumption shorthand through
MapProfile<TBehavior>() - explicit generated module shorthand through
MapGeneratedProfiles(...) - pure convention defaults derived from behavior id and input shape
The shipped runtime-catalog baseline now covers both the explicit module DSL and explicit manual module-owned REST paths. That means precedence affects publication, but the winning manual or DSL route still flows through the same operator-facing catalog and duplicate-route guard once ASP.NET Core materializes the final endpoints.
The shipped precedence-visibility baseline now also makes that suppression decision observable for
module-owned normalized behavior projections. Within that behavior-projection path, the explicit
module DSL wins over both MapProfile<TBehavior>() and MapGeneratedProfiles(...), and
MapProfile<TBehavior>() in turn wins over generated shorthand for the same behavior. The runtime
keeps all three candidates visible through the candidate catalog instead of hiding the winning
decision as silent startup behavior.
Suppression rule
Section titled “Suppression rule”If any higher-precedence layer maps a behavior into public REST, lower-precedence public REST projections for that behavior should be suppressed automatically unless the higher-precedence layer explicitly opts into multiple projections.
The current shipped place for that intent is
RestApi:AuthoringPolicies:{behaviorId}:AllowMultiplePublishedCandidates, surfaced back out
through RestEndpointPublicationGroupDescriptor.AuthoringPolicy. When that flag is omitted or
false, the default single-winner precedence answer still applies. When it is true,
lower-precedence shorthand candidates can remain published side by side as long as governance does
not suppress them and the final HTTP method + route pattern answers still stay distinct; if
co-published candidates would otherwise reuse the same effective endpoint name, the resolver now
disambiguates that endpoint name deterministically while preserving OriginalEndpointName as the
source shorthand lineage.
That means:
- explicit module mapping should suppress implicit behavior-only REST projection for the same behavior
- Cephalon should not run both side by side by default
- Cephalon may run more than one shorthand candidate side by side only when the grouped behavior explicitly opts into that outcome and the final mapped public surface remains deterministic
Registration precedence
Section titled “Registration precedence”- explicit module-owned behavior registration
- fluent explicit registration
- auto-registration / assembly scanning
This already matches the shipped model and should stay stable.
Route-collision and runtime-catalog direction
Section titled “Route-collision and runtime-catalog direction”The current repo already prevents duplicate behavior ownership across modules, and it now also has a first-class runtime contract for resolved public REST truth plus fail-fast route-collision validation.
That shipped baseline matters because future generated, shorthand, or convention-backed REST projections now have one operator-facing surface and one collision-policy pipeline to extend instead of inventing their own route publication rules.
Recommended runtime surface:
IRestEndpointRuntimeCatalog/engine/rest-endpoints/engine/rest-endpoints/{restEndpointId}snapshot.RestEndpointsIRestEndpointCandidateRuntimeCatalog/engine/rest-endpoint-candidates/engine/rest-endpoint-candidates/{candidateId}snapshot.RestEndpointCandidatesIRestEndpointPublicationGroupRuntimeCatalog/engine/rest-endpoint-publication-groups/engine/rest-endpoint-publication-groups/{behaviorId}snapshot.RestEndpointPublicationGroups- fail-fast startup validation on duplicate resolved public
HTTP method + route pattern
The shipped baseline now answers at least:
- source kind such as
manualormodule-dsl - module id when a real module owns the projection
- behavior id when the endpoint dispatches through
BehaviorDispatcher - HTTP method
- final route pattern
- candidate OpenAPI document or API version
- first-class published-endpoint
RouteGroupPrefix,RelativePattern,AuthoringStyle, nullableBehaviorType, nullableSourceId, and nullableCandidateId, while additive metadata remains compatibility-only - for shorthand candidate entries, both the original source projection and the final effective mapped endpoint shape
That answer now covers both projection-backed module DSL routes and explicit manual module-owned
REST routes published through IRestModule, legacy IEndpointModule, or
RestBehaviorModuleBase.MapAdditionalEndpoints(...).
The same shipped baseline now also answers precedence visibility for module-owned shorthand projections:
- published versus suppressed candidate status
- candidate authoring style and precedence rank
- the winning candidate id when suppression occurs
- an operator-facing suppression reason
- the projected endpoint shape each candidate would publish if it won
- the full ordered suppression-rule and override-rule match sets when overlapping governance rules target the same shorthand candidate
- the grouped published-versus-suppressed answer per behavior, including published candidate ids, precedence-suppressed candidate ids, governance-suppressed candidate ids, the winning precedence rank when one exists, and the ordered candidate set
Broader generated or convention-backed low-code projections should extend that same candidate surface plus grouped publication answer instead of inventing a second precedence-answer model.
This keeps shorthand authoring compatible with Cephalon’s broader requirement that runtime policy, composition, and public surface decisions stay introspectable.
Input binding direction
Section titled “Input binding direction”The current REST helper composes route values, query-string values, and JSON bodies into one JSON payload by name.
That is a reasonable baseline, but it is too implicit for the long-term engine contract because collisions can be surprising and the source of each input field is not explicit enough.
The long-term projection model now has a first shipped explicit-binding baseline through repeated
BehaviorRestBindingAttribute declarations on a behavior profile. That baseline feeds
BehaviorRestProfileDescriptor.Bindings, source-generated GetRestProfiles() hints, explicit
module-owned MapProfile<TBehavior>() consumption, and the engine-owned
RestEndpointRuntimeDescriptor.BindingDescriptors runtime contract.
The current binding-descriptor baseline supports:
- route
- query
- header
- body
Current rule:
- explicit binding metadata beats inference
- explicit bindings currently require object inputs; scalar inputs still use the existing scalar REST binder path
- route placeholders can still infer unbound route-bound properties when names match
- explicit route bindings must name placeholders that actually exist in the declared
BehaviorRestProfileAttributepattern - for
GETandDELETE, explicit body bindings are rejected - for
POST,PUT, andPATCH, explicit route/query/header/body bindings resolve first, and the JSON body can still fill remaining unbound object properties - body values that target a property already reserved by an explicit non-body binding fail fast instead of silently overwriting the explicit source
- build-time diagnostics now reject invalid binding sources, missing or duplicate input-property
targets, scalar-input binding misuse, body bindings on non-body verbs, and route-placeholder
mismatches before
GetRestProfiles()is generated - shorthand REST publication still requires an explicit HTTP method selection and does not infer a public verb only from behavior-id naming conventions
- the shipped constrained host-level binding override baseline now supports both full explicit-plan
replacement and typed
merge-explicitproperty-by-property binding patches plus withdrawals, still leaves unbound route placeholders and remaining request-body fields available for deterministic fallback, and still fails fast when the effective method-plus-binding plan is invalid - merge-mode withdrawals must not silently demote a source explicit query binding on
non-body-capable methods; that rewrite is valid only when the source explicit profile preserved
the remaining implicit query surface intentionally or the host resets the authored plan through
ClearBindings - runtime fallback truth is intentionally split between authored and effective answers:
OriginalProjection.BindingFallbackModestays source-projection truth, whileProjectedEndpoint.BindingFallbackModemay surfacePreserveSourceImplicitFallbackonly when an override legitimately re-exposes preserved remaining query surface - broader configuration-driven binding overrides beyond that explicit-binding upsert-plus-withdraw model remain later work
OpenAPI version direction
Section titled “OpenAPI version direction”Cephalon should keep two concerns separate.
Concern 1: endpoint candidate version
Section titled “Concern 1: endpoint candidate version”The REST projection selects the candidate API version or document membership for an endpoint.
That can come from:
- explicit module
.ApiVersion(...) - future behavior-authored HTTP profile defaults
- configuration-driven projection overrides
Concern 2: host published documents
Section titled “Concern 2: host published documents”The host still decides which documents are published through:
OpenApi:EnabledVersionsOpenApi:DefaultVersion- legacy
OpenApi:Documents/OpenApi:DefaultDocument
That allow-list remains authoritative and must stay separate from endpoint authoring metadata.
The shipped configuration-driven override surface is still intentionally narrow: RestApi:Overrides
can target the original shorthand candidate shape through exact Behaviors, subtree
BehaviorIdPrefixes, ApiVersionMajors, Methods, RelativePatterns, RouteGroupPrefixes,
OpenApiDocumentNames, TagNames, EndpointNames, and BindingFallbackModes, then change the
effective shorthand candidate ApiVersionMajor,
OpenApiDocumentName, HTTP Method, bounded published RouteGroupPrefix, relative Pattern,
RequiredCapabilityKey, ClearRequiredCapability, EndpointName, Summary, Description,
TagName, ClearEndpointName, ClearSummary, ClearDescription, and/or explicit Bindings
plus RemovedBindingProperties, and can now also reset the authored explicit binding plan through
shorthand-only ClearBindings, but the current route-pattern slice
is still constrained enough to keep binding semantics truthful and ApiVersionMajor only
re-derives the effective document name when the authored shorthand group did not pin one
explicitly through .WithOpenApiDocumentName(...). Cephalon therefore keeps the
route-version segment and document name
together for version rewrites, allows route-pattern rewrites when they preserve the same
placeholder set or when the effective explicit route-binding plan covers a renamed placeholder set
exactly, lets binding overrides either replace the shorthand candidate’s explicit binding plan or
merge explicit binding upserts and withdrawals into it by property name while preserving
deterministic fallback for unbound route placeholders and remaining request-body fields, now also
lets hosts clear that explicit plan entirely when the effective route can still bind truthfully
through the implicit baseline, allows
route-pattern rewrites that remove placeholders when the original projection already
exposes explicit route-binding coverage for the original placeholder set and the effective explicit
binding plan keeps every affected original route-bound property explicitly bound, allows
route-pattern rewrites that add placeholders when the effective explicit route-binding plan covers
the full final placeholder set and every newly route-bound property was either already explicitly
bound in the original projection, for POST/PUT/PATCH already part of the original
deterministic remaining-body fallback surface, or for shorthand candidates with no explicit
binding plan already part of the original implicit query-fallback surface, or for explicit
shorthand profiles that intentionally preserve source implicit query fallback when the newly
route-bound property still belongs to that remaining source query surface, allows
RouteGroupPrefix rewrites only when the published group stays beneath the active REST root,
contains no placeholders, and does not silently change effective API-version truth, now makes
ASP.NET Core materialize split effective route groups when one authored shorthand group fans out
to more than one published group, rejects any one rule that tries to both set and clear the same
endpoint-metadata field, and does not yet support route rewrites that promote other
implicit properties into placeholders outside the shipped body-fallback, no-explicit-plan
query-fallback, and source-or-host-preserved-explicit-query-fallback slices or broader
host-level binding rewrites beyond the current replace-plus-merge-explicit upsert-plus-withdraw
model that would silently change how one shorthand endpoint reads its input.
Within that bounded capability-governance slice, ClearRequiredCapability = true is the explicit
host answer for removing an inherited shorthand capability boundary. It is mutually exclusive with
RequiredCapabilityKey, remains visible through /engine/rest-endpoint-overrides, and must drive
the same null effective capability boundary across the shorthand candidate projection, the
materialized ASP.NET Core endpoint metadata, /engine/rest-endpoints, and snapshot.RestEndpoints
rather than leaving the earlier shorthand guard in place invisibly.
If the same behavior needs multiple public API versions simultaneously, model that as multiple explicit projections or versioned modules. Do not hide multi-version public contracts behind one implicit behavior-level flag until behavior identity and versioned transport-surface semantics are reworked deliberately.
Why this model is better than direct REST on IAppBehavior
Section titled “Why this model is better than direct REST on IAppBehavior”It preserves the current architectural wins:
- public REST remains a public-boundary concern
- behavior logic stays portable across REST, GraphQL, JSON-RPC, SSE, WebSocket, gRPC, and messaging
- non-REST route-shaped adapters keep using
BehaviorApiSurfaceDescriptor - low-code authoring can exist without making every behavior an accidental public API
- future source generation can emit descriptor data and binder plans without runtime reflection
It also gives Cephalon a better portability story:
- teams can keep behavior code stable
- teams can switch route shape, grouping, or public-boundary layout through descriptor-backed authoring instead of editing handler logic
- future architecture or app-shape changes can happen at the projection layer rather than inside behavior implementations
Recommended migration path
Section titled “Recommended migration path”Cephalon should implement this in five steps.
Step 1: normalize the public REST projection contract
Section titled “Step 1: normalize the public REST projection contract”Add a normalized descriptor model and make the current module DSL compile into it internally.
Status:
- shipped through
ENG-058-T56; the current module DSL now compiles into a normalized internal projection model before route materialization
Step 2: add resolved REST endpoint catalog and collision validation
Section titled “Step 2: add resolved REST endpoint catalog and collision validation”Add a runtime catalog and fail-fast duplicate-route validation over the normalized projection model so future shorthand or generated projections cannot create silent public-route ambiguity.
Status:
- shipped through
ENG-058-T57plusENG-058-T58;Cephalon.Abstractionsnow exposesIRestEndpointRuntimeCatalog,IRestEndpointRuntimeRegistry, andRestEndpointRuntimeDescriptor,Cephalon.AspNetCorenow publishes/engine/rest-endpoints,/engine/rest-endpoints/{restEndpointId}, andsnapshot.RestEndpoints, the public REST host now fails fast when two resolved public REST endpoints collide on the sameHTTP method + route pattern, and that runtime answer now covers both projection-backed module DSL routes and explicit manual module-owned REST routes
Step 3: add build-time diagnostics and source-generated profile support
Section titled “Step 3: add build-time diagnostics and source-generated profile support”If behavior-authored HTTP profiles are added, validate them at build time and emit normalized descriptor data alongside existing behavior registration hints.
Status:
- shipped through
ENG-058-T61;Cephalon.Behaviors.Httpnow exposes the metadata-onlyBehaviorRestProfileAttribute,BehaviorRestMethod, andBehaviorRestProfileDescriptorcontract, whileCephalon.Behaviors.SourceGennow validates that profile metadata at build time and emits source-generatedGetRestProfiles()hints without activating public REST routes from[AppBehavior]
Step 4: ship explicit module-owned profile shorthand, then generated module projections
Section titled “Step 4: ship explicit module-owned profile shorthand, then generated module projections”Status:
- partially shipped through
ENG-058-T62;IRestBehaviorEndpointGroupBuilder.MapProfile<TBehavior>()now lets an owning module consumeBehaviorRestProfileAttributehints without restating the HTTP method or relative pattern in module code, while still keeping public REST explicit and module-owned - now shipped through
ENG-058-T67;IRestBehaviorEndpointGroupBuilder.MapGeneratedProfiles()andMapGeneratedProfiles(string behaviorIdPrefix)let an owning module publish all matching profile-backed behaviors beneath one owned route group without restating each behavior individually, while still keeping public REST explicit, module-owned, and visible through the same normalized projection plus candidate-catalog runtime surfaces - now also shipped through
ENG-058-T163;IRestBehaviorModuleBuilder.MapGeneratedProfileGroups(...)lets an owning module fan one generated behavior-id root prefix out into several derived owned route groups, applies optional shared group-level conventions before publication, and still keeps generated publication on the same normalized projection, candidate-catalog, publication-group, and runtime-catalog path instead of inventing a new generated publication source - now also shipped through
ENG-058-T173; those same grouped generated dedicated-module and inline-helper paths can now also configure each derived group with awareness of its exact generated behavior-id prefix, so one owner can stamp different API versions, tags, or governance scopes per branch without falling back to manual derived-group enumeration or leaving the same normalized grouped-generated runtime path
Follow-through later:
- keep any further low-code shorthand additions on that same module-owned generated path only when selector provenance and grouped runtime truth remain readable, then evaluate broader convention- backed projection only if it still preserves the same public-boundary model and operator truth
Step 5: add explicit input-binding descriptors, then controlled configuration overrides
Section titled “Step 5: add explicit input-binding descriptors, then controlled configuration overrides”Finish the model by making binding plans explicit first, then evaluate whether descriptor-backed routes should opt into configuration override behavior where that flexibility is worth the complexity.
Status:
- the explicit input-binding descriptor slice is now shipped through
ENG-058-T63 - the first compile-time and runtime hardening follow-through is now shipped through
ENG-058-T64, so invalid binding metadata is rejected at build time and runtime fallback still re-checks route-placeholder truth before endpoint materialization - suppression visibility plus explicit-DSL-over-profile precedence is now shipped through
ENG-058-T66 - generated module shorthand plus explicit
DSL > MapProfile<TBehavior>() > generated shorthandprecedence is now shipped throughENG-058-T67, where generated shorthand now includes bothMapGeneratedProfiles(...)andMapGeneratedProfileGroups(...) - the first controlled-governance follow-through is now shipped through
ENG-058-T68, so ASP.NET Core hosts can suppress descriptor-backed shorthand candidates throughRestApi:Suppressionswhile the runtime keeps both the configured suppression-rule catalog and the candidate-levelSuppressedBySuppressionIdplusMatchedSuppressionIdstruth visible - the next controlled-governance follow-through is now shipped through
ENG-058-T69,ENG-058-T70,ENG-058-T71,ENG-058-T72,ENG-058-T73,ENG-058-T74,ENG-058-T75,ENG-058-T82,ENG-058-T97,ENG-058-T98,ENG-058-T99,ENG-058-T105,ENG-058-T107, andENG-058-T108, so ASP.NET Core hosts can retarget descriptor-backed shorthand candidates throughRestApi:Overrideswhen they need a different effectiveApiVersionMajor,OpenApiDocumentName, HTTPMethod, bounded publishedRouteGroupPrefix, constrained relativePattern, required capability boundary, endpoint metadata, tag, or explicit binding plan, while the runtime keeps both the configured override-rule catalog and the candidate-levelAppliedOverrideId,SelectedOverrideId, andMatchedOverrideIdstruth visible - the next governance-overlap visibility follow-through is now shipped through
ENG-058-T87, so overlapping shorthand suppression/override matches now stay visible in runtime truth through the orderedMatchedSuppressionIdsandMatchedOverrideIdslists before one rule wins by the existing specificity model - the candidate-runtime status contract now also uses stable
published/suppressedwire names throughRestEndpointCandidateStatus, so/engine/rest-endpoint-candidates,/engine/rest-endpoint-candidates/{candidateId}, andsnapshot.RestEndpointCandidatesno longer rely on raw enum-number serialization for operator-facing publication state - the next selector-targeting follow-through is now shipped through
ENG-058-T77,ENG-058-T109,ENG-058-T118, andENG-058-T120, so bothRestApi:SuppressionsandRestApi:Overridescan refine that same descriptor-backed shorthand scope withApiVersionMajors,Methods,RelativePatterns,RouteGroupPrefixes,OpenApiDocumentNames,TagNames,BindingFallbackModes, and exact original explicitTargetBindingsselector sets while the runtime keeps both the configured rule catalogs and the original-shape targeting truth visible - the next constrained shorthand REST implicit query-fallback route promotion is now shipped
through
ENG-058-T88, so shorthand candidates with no explicit binding plan can promote placeholders from the original implicit query-fallback surface while explicit-binding candidates stay on the stricter explicit-binding path unless a later preserved-explicit follow-through deliberately keeps source query fallback available - the next partial-explicit-override follow-through is now shipped through
ENG-058-T89, so when a shorthand candidate originally had no explicit binding plan, hosts can add partial explicit bindings without losing the remaining implicit query-fallback surface for unbound properties, and runtime truth now keeps that preserved mode visible throughmetadata.bindingFallbackMode = preserve-source-implicit-fallback - the next typed binding-fallback runtime-contract follow-through is now shipped through
ENG-058-T90, so that preserved shorthand fallback answer no longer lives only in additive metadata:Cephalon.Abstractionsnow exposesRestEndpointBindingFallbackModeplus typedBindingFallbackModeproperties on bothRestEndpointCandidateProjectionDescriptorandRestEndpointRuntimeDescriptor, runtime JSON now serializes that typed answer directly on the original shorthand projection and the effective published endpoint, andmetadata.bindingFallbackMode = preserve-source-implicit-fallbackremains compatibility-only metadata - the next explicit-profile authoring parity follow-through is now shipped through
ENG-058-T119, so explicit metadata-only REST profiles can now preserve that same source implicit query fallback intentionally by settingBehaviorRestProfile(PreserveImplicitQueryFallback = true)when at least one explicit binding is present; build-timeABT0027and runtime profile normalization now both fail fast when that flag is declared without explicit bindings - the next merge-withdrawal safeguard follow-through is now also shipped through
ENG-058-T162, so merge-mode shorthand binding removals on non-body-capable methods now fail fast when they would stop explicitly binding a source query-bound property unless the source profile intentionally preserved implicit query fallback or the host intentionally resets the full explicit plan throughClearBindings, and runtime truth now keeps authored-source versus effective fallback answers separate when that preserved query surface is newly re-exposed by the winning override - the next explicit-binding remaining-body-fallback truth follow-through is now shipped through
ENG-058-T114, so body-capable shorthand candidates with explicit bindings now also publish typedBindingFallbackMode = PreserveRemainingBodyFallbackwhen unbound properties still remain on the deterministic request-body surface, and compatibilitymetadata.bindingFallbackMode = preserve-remaining-body-fallbackremains additive-only metadata - the next published-endpoint provenance follow-through is now shipped through
ENG-058-T91, so the final/engine/rest-endpointssurface no longer needs route-text guessing to reconnect with the shorthand-candidate story:RestEndpointRuntimeDescriptornow exposes typed nullableCandidateId, behavior-backed published endpoints now point back to the original candidate id even when host overrides rewrite the final route shape, and manual endpoints staynull - the next published-endpoint authorship follow-through is now shipped through
ENG-058-T92, so published endpoints no longer needmetadata.authoringStyleas the canonical origin answer:RestEndpointRuntimeDescriptornow exposes first-classAuthoringStyle, runtime JSON now serializes that property directly on/engine/rest-endpointsplussnapshot.RestEndpoints, and additivemetadata.authoringStyleremains compatibility-only metadata - the next published route-boundary follow-through is now shipped through
ENG-058-T93, so published endpoints no longer needmetadata.routeGroupPrefixormetadata.relativePatternas the canonical grouped-route answer:RestEndpointRuntimeDescriptornow exposes first-classRouteGroupPrefixandRelativePattern, runtime JSON now serializes those properties directly on/engine/rest-endpointsplussnapshot.RestEndpoints, and additivemetadata.routeGroupPrefixplusmetadata.relativePatternremain compatibility-only metadata - the next published behavior-implementation follow-through is now shipped through
ENG-058-T94, so published endpoints no longer needmetadata.behaviorTypeas the canonical behavior-backed implementation answer:RestEndpointRuntimeDescriptornow exposes first-class nullableBehaviorType, runtime JSON now serializes that property directly on/engine/rest-endpointsplussnapshot.RestEndpoints, manual non-behavior endpoints staynull, and additivemetadata.behaviorTyperemains compatibility-only metadata - the next published source-identity follow-through is now shipped through
ENG-058-T95, so published endpoints no longer needmetadata.sourceIdas the canonical source-identity answer:RestEndpointRuntimeDescriptornow exposes first-class nullableSourceId, runtime JSON now serializes that property directly on/engine/rest-endpointsplussnapshot.RestEndpoints, and additivemetadata.sourceIdremains compatibility-only metadata - the next route-boundary materialization follow-through is now shipped through
ENG-058-T96, so shorthand ASP.NET Core materialization now readsProjectedEndpoint.RouteGroupPrefixdirectly when it publishes effective route groups instead of parsingmetadata.routeGroupPrefix, and additivemetadata.routeGroupPrefixnow stays compatibility-only even for internal route mapping - the next shorthand endpoint-metadata governance follow-through is now shipped through
ENG-058-T97, soRestApi:Overridescan now also rewrite shorthandEndpointName,Summary, andDescription, those effective metadata values now flow through shorthand candidate truth, actual ASP.NET Core endpoint metadata,/engine/rest-endpoints, andsnapshot.RestEndpoints, and metadata-only no-op rules do not pretend they changed the effective published answer - the next shorthand capability-boundary governance follow-through is now shipped through
ENG-058-T98, soRestApi:Overridescan now also rewrite shorthandRequiredCapabilityKey, that effective value now flows through shorthand candidate truth, actual ASP.NET Core endpoint metadata,/engine/rest-endpoints, andsnapshot.RestEndpoints, andRequireCapability(...)now treats the last declared capability boundary as authoritative so a later host override can supersede an earlier shorthandconfigureEndpointguard instead of stacking both boundaries - the next shorthand capability-boundary clear follow-through is now shipped through
ENG-058-T99, soRestApi:Overridescan now also declareClearRequiredCapability = truefor descriptor-backed shorthand candidates, that action stays visible through/engine/rest-endpoint-overridesplussnapshot.RestEndpointOverrides, shorthand candidate projections plus actual ASP.NET Core endpoint metadata plus/engine/rest-endpointsnow all agree onRequiredCapabilityKey = nullwhen that clear wins, and hosts now fail fast if one override rule tries to both setRequiredCapabilityKeyand clear it in the same action - the next published capability-provenance follow-through is now shipped through
ENG-058-T100, soRestEndpointRuntimeDescriptornow also exposes nullableOriginalRequiredCapabilityKeyplusAppliedOverrideId, shorthand materialization captures the source capability boundary before later host capability overrides run,/engine/rest-endpointsplussnapshot.RestEndpointsnow show both the original and effective capability answers directly, and capability-only no-op clear rules no longer claim an endpoint-level applied override when the published capability answer stays unchanged - the next shorthand feature-boundary governance follow-through is now also shipped through
ENG-058-T174, soRestApi:Overridescan now also rewrite shorthandRequiredFeatureFlagIdsor clear them throughClearRequiredFeatureFlags, that effective ordered feature answer now flows through shorthand candidate truth, actual ASP.NET Core endpoint metadata,/engine/rest-endpoints, andsnapshot.RestEndpoints,RequireFeatureFlag(...),RequireFeatureFlags(...), andClearRequiredFeatureFlags()now all treat the last declared feature registration as authoritative so later host governance can replace or intentionally remove an earlier shorthand feature boundary, and published endpoints now also expose orderedOriginalRequiredFeatureFlagIdsso runtime truth can distinguish “never had a feature gate” from “host cleared or rewrote the source feature gate” - the next published override-match visibility follow-through is now shipped through
ENG-058-T102, soRestEndpointRuntimeDescriptornow also exposes orderedMatchedOverrideIds, shorthand materialization carries that same ordered match set onto the final published endpoint surface,/engine/rest-endpointsplussnapshot.RestEndpointsno longer need a candidate join to explain which shorthand override rules matched a live published endpoint, and capability-only no-op matches now keepMatchedOverrideIdsvisible there even whenAppliedOverrideIdstaysnull - the next published original-shorthand-visibility follow-through is now shipped through
ENG-058-T103, soRestEndpointRuntimeDescriptornow also exposes nullableOriginalProjection, shorthand materialization carries the pre-override shorthand method, route, document-version, and binding-plan truth onto the final published endpoint surface, and/engine/rest-endpointsplussnapshot.RestEndpointscan now compare original-versus-effective publication directly without joining back to the candidate catalog while manual and behavior-helper endpoints staynull - the next published original-shorthand endpoint-metadata follow-through is now shipped through
ENG-058-T104, soRestEndpointRuntimeDescriptornow also exposes nullableOriginalEndpointName,OriginalSummary, andOriginalDescription, shorthand materialization carries that pre-override endpoint-metadata truth onto the final published endpoint surface, and/engine/rest-endpointsplussnapshot.RestEndpointscan now compare original-versus-effective endpoint metadata directly while manual and behavior-helper endpoints keep that trionull - the next shorthand endpoint-metadata clear-governance follow-through is now shipped through
ENG-058-T105, soRestEndpointOverrideDescriptorplusRestEndpointOverrideOptionsnow also exposeClearEndpointName,ClearSummary, andClearDescription, hosts now fail fast when one rule tries to both set and clear the same endpoint-metadata field, shorthand candidate projections plus actual ASP.NET Core endpoint metadata plus/engine/rest-endpointsnow all agree onnullwhen an endpoint-metadata clear wins, and the original shorthand endpoint- metadata lineage still stays visible throughOriginalEndpointName,OriginalSummary, andOriginalDescription - the next shorthand metadata-and-document truthfulness follow-through is now shipped through
ENG-058-T106,ENG-058-T107,ENG-058-T108,ENG-058-T109,ENG-058-T110,ENG-058-T111,ENG-058-T112,ENG-058-T113,ENG-058-T114,ENG-058-T115, andENG-058-T116: same-value endpoint-metadata, tag, and document-name rewrites plus reorder-only equivalent binding-set rewrites now keepMatchedOverrideIdsvisible while leavingAppliedOverrideId = null, tag rewrites preserveOriginalProjection.TagNamewhile splitting effective materialized groups, document-name governance now addsOpenApiDocumentNameplus.WithOpenApiDocumentName(...), explicit.ApiVersion(...)precedence remains authoritative for version selection even when later host governance rewrites the effective published document name, and selector targeting can now distinguish candidates by original shorthand document name plus primary tag name without depending on rewritten routes, whileClearBindingsnow resets shorthand explicit binding plans back to the implicit route/query/body baseline, keeps that reset truthful through the override, candidate, endpoint, and snapshot catalogs, fails fast when the effective route would only remain satisfiable through removed explicit placeholder aliases, and keeps source explicit binding order authoritative when a matched override only restates the same normalized binding set in another order; that same semantic binding-set comparison now also drives projection reuse and post-materialization structural override reconciliation so future shorthand paths cannot regress into order-sensitive endpoint provenance, whileCephalon.Behaviors.Httpnow also publishes stable startup diagnostics for suppression, precedence suppression, applied overrides, no-op override matches, and preserved binding fallback through/engine/diagnosticssourceCephalon.Behaviors.Httpand information-level logs that reconcile published answers against post-materialization truth whenever the runtime candidate registry is active, while explicit body-capable shorthand binding plans that still preserve deterministic remaining request-body fallback now also keep that typedBindingFallbackMode = PreserveRemainingBodyFallbackanswer aligned acrossOriginalProjection,ProjectedEndpoint,/engine/rest-endpoints, andsnapshot.RestEndpoints,ENG-058-T115now keeps event5204RestEndpointBindingFallbackPreservedaligned with that same broader runtime truth so startup logging emits whichever typed fallback mode was preserved, including bothPreserveSourceImplicitFallbackandPreserveRemainingBodyFallback,ENG-058-T135now also keeps that startup log payload on the same stablepreserve-source-implicit-fallback/preserve-remaining-body-fallbackwire names the runtime contract and compatibility metadata already use, andENG-058-T116now centralizes the stable compatibility wire names behindRestEndpointBindingFallbackModeExtensions.GetWireName()/TryParseWireName(...)so ASP.NET Core metadata plus tests no longer maintain independent hardcoded fallback-mode strings - the next binding-fallback selector-targeting follow-through is now shipped through
ENG-058-T118, so bothRestApi:SuppressionsandRestApi:Overridescan now refine original- shape shorthand governance withBindingFallbackModes, the runtime suppression/override catalogs now publish those configured selectors directly, specificity now counts that extra dimension consistently, and hosts can target the original shorthand fallback identity through the stable wire namespreserve-source-implicit-fallbackandpreserve-remaining-body-fallbackwithout depending on later rewritten published shape;ENG-058-T136now also makes those stable wire names the only accepted host-config input forBindingFallbackModes, so runtime truth, diagnostics, and config no longer mix PascalCase enum aliases into the operator contract - the next original-binding-plan selector-targeting follow-through is now shipped through
ENG-058-T120, so bothRestApi:SuppressionsandRestApi:Overridescan now refine original- shape shorthand governance with exactTargetBindingsselector sets, the runtime suppression/override catalogs now publish those configured selectors directly, specificity now counts that extra dimension consistently, and hosts can target route-only versus richer explicit- binding shorthand candidates by their authored binding plan without depending on later rewritten published shape - the next original-endpoint-name selector-targeting follow-through is now shipped through
ENG-058-T156, so bothRestApi:SuppressionsandRestApi:Overridescan now refine original- shape shorthand governance with exactEndpointNamesselector sets, the runtime suppression/override catalogs now publish those configured selectors directly, specificity now counts that extra dimension consistently, and hosts can target the authored shorthand endpoint name throughProjectedEndpoint.OriginalEndpointNamewithout depending on later rewritten published shape - the next route-group governance-scope selector follow-through is now shipped through
ENG-058-T158, so route groups can now publish one stableHostGovernanceScopethroughWithHostGovernanceScope(...)andOriginalProjection.HostGovernanceScope, bothRestApi:SuppressionsandRestApi:Overridescan targetHostGovernanceScopesdirectly, specificity now counts that extra original-shape dimension consistently, and explicit module-DSL routes can carry a scope without entering host governance unlessAllowHostGovernance()still opts them in separately - the next scope-first governance-config follow-through is now shipped through
ENG-058-T159, soHostGovernanceScopesnow also counts as a rule’s primary selector besideCandidateIds,Behaviors, andModules; scope-only suppression and override rules no longer fail fast just because they omit behavior or module ids, while empty-selector rules still do - the next scope-first runtime-parity follow-through is now shipped through
ENG-058-T160, so scope-onlyHostGovernanceScopesrules are now explicitly proven through the suppression, override, publication-group, authoring-policy, and snapshot answers without falling back to behavior-id selectors, and ASP.NET Core materialization now only stampsRestEndpointAppliedOverrideMetadatawhen the selected rule’s own capability or endpoint- metadata action family materially changed the published answer, so capability-only no-op matches remain selected-only instead of surfacing false applied provenance - the next explicit preserved-query-fallback route-promotion follow-through is now shipped
through
ENG-058-T161, so shorthand profiles that already declare explicit bindings and intentionally preserve source implicit query fallback can now promote that remaining query surface into added route placeholders through host overrides, while candidate and published runtime truth now clearBindingFallbackModeonce the effective binding plan fully consumes that preserved fallback surface - the next explicit-query withdrawal guardrail follow-through is now also shipped through
ENG-058-T162, so merge-mode shorthand binding removals on non-body-capable methods now fail fast when they would stop explicitly binding a source query-bound property unless the source profile intentionally declaredBehaviorRestProfile(PreserveImplicitQueryFallback = true), the winning host override intentionally setPreserveImplicitQueryFallback = true, or the host intentionally resets the plan throughClearBindings; when preserved fallback remains valid after the rewrite, runtime truth also stays honest by allowingOriginalProjection.BindingFallbackModeto remainnullwhileProjectedEndpoint.BindingFallbackModebecomesPreserveSourceImplicitFallback - the next generated profile-group shorthand follow-through is now also shipped through
ENG-058-T163, so oneIRestBehaviorModuleBuilder.MapGeneratedProfileGroups(...)call can derive several owned route groups from one generated root prefix, apply one shared group-level convention callback to each derived group, and still keepbehavior-module-generatedauthoring style, source-module ownership, publication-group answers, and candidate/runtime truth on the same normalized module-owned path - the next behavior-subtree governance follow-through is now also shipped through
ENG-058-T164, soRestApi:SuppressionsandRestApi:Overridescan target one generated or profiled shorthand subtree throughBehaviorIdPrefixes, exact behavior-id rules still beat those broader subtree matches, longer prefixes now beat shorter prefixes throughnarrower-behavior-scope, and the suppression/override runtime catalogs plussnapshotkeep the configured prefix arrays and decisive selection-basis truth visible directly - the next grouped-operator parity follow-through is now also shipped through
ENG-058-T165, so that same exact-versus-prefix subtree governance story is now explicitly proven through/engine/rest-endpoint-publication-groups,/engine/rest-endpoint-authoring-policies, and the matchingsnapshotanswers, including per-authoring-style grouped summaries where broader prefix rules stay visible as matched-only outcomes beside narrower exact winners - the next skipped-governance parity follow-through is now also shipped through
ENG-058-T166, so prefix-targeted suppression and override rules that hit explicit module-DSL behavior ids withoutAllowHostGovernance()now remain visible as skipped outcomes through/engine/rest-endpoint-publication-groups,/engine/rest-endpoint-authoring-policies, the direct grouped/operator runtime catalogs, andsnapshotinstead of disappearing as if selector targeting failed - the next inline grouped-generated helper follow-through is now also shipped through
ENG-058-T167, so hosts can keep that sameMapGeneratedProfileGroups(...)ownership and runtime story on the low-code inline module path throughAddGeneratedRestBehaviorModuleGroups<TMarker>(), while the grouped generated root-prefix validation now fails fast consistently for both dedicated-module and inline-helper entry points - the next grouped-generated per-derived-group configuration follow-through is now also shipped
through
ENG-058-T173, so both the dedicated-module and inline-helper grouped generated paths can now configure each derived group with awareness of its exact generated behavior-id prefix before profiles are mapped, keeping per-branch API-version, tag, and governance-scope conventions on the same generated authoring-style and runtime-truth path - the next metadata-authoring parity follow-through is now also shipped through
ENG-058-T119, so that samepreserve-source-implicit-fallbackstory is no longer limited to no-explicit-plan shorthand candidates plus later host overrides; explicit metadata-only profiles can now opt into it directly throughBehaviorRestProfile(PreserveImplicitQueryFallback = true)when they also declare explicit bindings, and both build-timeABT0027plus runtime profile normalization keep invalid no-binding cases from leaking into shorthand publication - controlled configuration overrides that promote implicit properties into route placeholders
beyond the shipped constrained remaining-body-fallback-plus-bounded-query-fallback-plus-
source-or-host-preserved-explicit-query-fallback path, or rewrite input binding beyond
constrained explicit-binding replacement, remain later work now that the current override
baseline covers original-shape candidate ids plus selector targeting across exact behavior ids,
behavior-subtree prefixes, version, method, route-group prefix, document name, tag name, binding
fallback, exact original explicit binding plans, capability, bindings, clear-bindings resets,
PreserveImplicitQueryFallback, placeholder reshaping, and bounded fallback promotion
What should be stored as project memory
Section titled “What should be stored as project memory”The following points are durable enough to keep outside thread-local context.
- public REST stays module-owned even if Cephalon later adds shorthand REST authoring
- future shorthand REST authoring should be metadata or projection driven, not direct behavior-owned route activation
- explicit module-owned REST mappings suppress lower-precedence implicit or convention projections for the same behavior by default
- low-code REST authoring should stay opt-in, should prefer source-generated descriptor material first, and should allow only bounded owner-assembly fallback when a module explicitly opts into generated publication
[AppBehavior]plus auto-registration alone must still not publish a public REST boundary- host governance can now target that same shorthand ownership model by exact behavior id or by
subtree
BehaviorIdPrefixes, so one rule can govern one generated grouped branch without enumerating every exact candidate id while the owning module still owns the public REST boundary - overlapping behavior-targeted host rules now resolve exact behavior ids before broader subtree
prefixes, then prefer longer subtree prefixes through
narrower-behavior-scope, and the runtime suppression/override catalogs plussnapshotkeep that decisive basis operator-visible - the shipped public REST baseline now exposes resolved route truth through
IRestEndpointRuntimeCatalog,/engine/rest-endpoints,/engine/rest-endpoints/{restEndpointId}, andsnapshot.RestEndpoints - the shipped precedence-visibility baseline now also exposes candidate publication truth through
IRestEndpointCandidateRuntimeCatalog,/engine/rest-endpoint-candidates,/engine/rest-endpoint-candidates/{candidateId}, andsnapshot.RestEndpointCandidates - the shipped precedence-visibility baseline now also exposes grouped publication truth through
IRestEndpointPublicationGroupRuntimeCatalog,/engine/rest-endpoint-publication-groups,/engine/rest-endpoint-publication-groups/{behaviorId}, andsnapshot.RestEndpointPublicationGroups - those grouped publication entries now also expose
AuthoringStyleSummaries, derived from the same candidate set, so operators can inspect per-style participation, candidate ids, precedence ranks, published candidates, and suppression buckets without manually splitting the ordered behavior-level candidate set - those grouped publication entries now also expose
AuthoringPolicyas typedRestEndpointPublicationGroupAuthoringPolicyDescriptordata, so operators can distinguish the implicit default single-winner boundary from an explicitRestApi:AuthoringPolicies:{behaviorId}configuration and see preferred/allowed/disallowed authoring-style policy plus authoring-policy-suppressed candidate outcomes without inferring either answer from roadmap text alone - those grouped publication entries now also expose typed
AuthoringPolicySuppressionSummariesat both the grouped behavior level and inside eachAuthoringStyleSummariesentry, so operators can read the per-kinddisallowed-authoring-style,not-allowed-authoring-style, andpreferred-authoring-style-selectedsuppression breakdown directly from publication-group and snapshot payloads instead of reconstructing that answer candidate by candidate - the shipped REST authoring-policy runtime baseline now also exposes
IRestEndpointAuthoringPolicyRuntimeCatalog,/engine/rest-endpoint-authoring-policies,/engine/rest-endpoint-authoring-policies/{behaviorId}, andsnapshot.RestEndpointAuthoringPolicies, so one behavior-level policy answer can keep explicit default-versus-configured policy intent, explicitly configured-but-unmatched policies, and separateCandidateIds,RetainedCandidateIds,PublishedCandidateIds,PrecedenceSuppressedCandidateIds,GovernanceSuppressedCandidateIds, and groupedSuppressionSummariesvisible without reopening grouped publication answers - that same rule-centric authoring-policy answer now also exposes typed
AuthoringStyleSummariesentries throughRestEndpointAuthoringPolicyAuthoringStyleDescriptor, so operators can inspect per-styleCandidateIds,RetainedCandidateIds,PublishedCandidateIds,PrecedenceSuppressedCandidateIds,GovernanceSuppressedCandidateIds,SuppressedCandidateIds, and grouped suppression summaries without falling back to publication-group-only answers - that same rule-centric authoring-policy answer now also keeps
HostGovernanceEligibleCandidateIds,HostGovernanceIneligibleCandidateIds,SkippedSuppressionIds, andSkippedOverrideIdsvisible at both the behavior level and inside each authoring-style summary, so operators can confirm when explicit ownership stayed outside host governance without reopening publication-group-only answers - that same rule-centric authoring-policy answer now also exposes typed
GovernanceSuppressionSummaries,GovernanceOverrideSummaries,SkippedSuppressionSummaries, andSkippedOverrideSummariesat both the behavior level and inside eachAuthoringStyleSummariesentry, using the genericRestEndpointGovernance*SummaryDescriptorcontracts so operators can inspect matched-versus-suppressed, selected-versus-applied, and skipped-rule candidate mappings without reopening grouped publication answers - those grouped publication entries now also expose typed
GovernanceSuppressionSummariesandGovernanceOverrideSummariesat both the grouped behavior level and inside eachAuthoringStyleSummariesentry, so publication-group and snapshot payloads can answer which host rules matched, which candidates they actually suppressed, and which candidates they only selected versus materially changed without re-reading the candidate catalog - those same grouped governance summaries now also expose typed selection-basis and override-action buckets, so grouped publication answers can say why a winning host rule beat the runner-up and which override dimensions only stayed declared versus materially applied without reopening the candidate catalog
- those candidate entries now keep the original shorthand source shape visible through
RestEndpointCandidateRuntimeDescriptor.OriginalProjectionwhileProjectedEndpointcontinues to answer the final effective mapped route, version, method, binding, endpoint-name, summary, and description shape and now also keeps original shorthand endpoint metadata visible throughProjectedEndpoint.OriginalEndpointName,ProjectedEndpoint.OriginalSummary, andProjectedEndpoint.OriginalDescription - those candidate entries now also keep overlapping host-governance matches visible through
RestEndpointCandidateRuntimeDescriptor.MatchedSuppressionIdsandRestEndpointCandidateRuntimeDescriptor.MatchedOverrideIdsbefore one winning rule is selected - those grouped publication entries now keep the behavior-level published-versus-suppressed story visible through published candidate ids, precedence-suppressed candidate ids, governance-suppressed candidate ids, the winning precedence rank when one exists, and the ordered candidate set
- the shipped governance baseline now also exposes configured suppression-rule truth through
IRestEndpointSuppressionRuntimeCatalog,/engine/rest-endpoint-suppressions,/engine/rest-endpoint-suppressions/{suppressionId}, andsnapshot.RestEndpointSuppressions - the shipped governance baseline now also exposes configured override-rule truth through
IRestEndpointOverrideRuntimeCatalog,/engine/rest-endpoint-overrides,/engine/rest-endpoint-overrides/{overrideId}, andsnapshot.RestEndpointOverrides - those same rule catalogs now also derive rule-centric runtime-effect buckets directly from
candidate truth: suppression descriptors surface
MatchedCandidateIds,SuppressedCandidateIds,SkippedCandidateIds,SelectionBases, and groupedSelectionBasisSummaries, while override descriptors surfaceMatchedCandidateIds,SelectedCandidateIds,AppliedCandidateIds,SkippedCandidateIds,SelectionBases, groupedSelectionBasisSummaries,SelectedActionKinds, groupedSelectedActionKindSummaries,AppliedActionKinds, and groupedAppliedActionKindSummaries, so operators can answer per-rule runtime effect and per-bucket provenance without reopening/engine/rest-endpoint-candidatesor/engine/rest-endpoint-publication-groups - the shipped
RestApi:Suppressionsbaseline is intentionally limited to suppression of descriptor-backed shorthand candidates, and the shippedRestApi:Overridesbaseline is intentionally limited to shorthandApiVersionMajor,OpenApiDocumentName,Method, boundedRouteGroupPrefix, constrained relativePattern,RequiredCapabilityKey,ClearRequiredCapability,EndpointName,Summary,Description,TagName,ClearEndpointName,ClearSummary,ClearDescription, constrained explicitBindingsrewrites with either default full replacement or typedmerge-explicitproperty upserts plusRemovedBindingProperties, and shorthand-onlyClearBindingsresets back to the implicit request-binding baseline; neither surface rewrites explicit module DSL or manual routes - both rule families can now target exact original-shape shorthand candidates through
CandidateIds, can also refineBehaviors/Modulestargeting withApiVersionMajors,Methods,RelativePatterns,RouteGroupPrefixes,OpenApiDocumentNames,TagNames,EndpointNames,HostGovernanceScopes, andBindingFallbackModes, and all of those selectors match the original shorthand candidate identity before override actions are applied so suppression and override decisions do not depend on already-rewritten final route shape;EndpointNamestargetsProjectedEndpoint.OriginalEndpointName,HostGovernanceScopestargetsOriginalProjection.HostGovernanceScope, andBindingFallbackModesuses the stable wire namespreserve-source-implicit-fallbackandpreserve-remaining-body-fallback /engine/rest-endpoint-candidatesnow publishes that same original-shape candidate identity throughRestEndpointCandidateRuntimeDescriptor.Id, whileProjectedEndpoint.Idremains the effective mapped endpoint identity after override actions are applied- shorthand candidate projected endpoints now also keep endpoint names plus summary/description metadata aligned with the final behavior-backed runtime endpoint conventions, including XML- derived summaries/descriptions when those docs exist and module-description fallback when they do not
- when REST governance rewrites or clears shorthand
EndpointName,Summary, orDescription, the same effective answer must driveProjectedEndpoint, actual ASP.NET Core endpoint metadata,/engine/rest-endpoints, andsnapshot.RestEndpoints; metadata-only no-op matches should not pretend they changed the published answer, andOriginalEndpointName,OriginalSummary, andOriginalDescriptionshould remain available so operators can still see the source shorthand metadata after a clear wins - when REST governance rewrites shorthand
TagName, the same effective answer must driveProjectedEndpoint.Tags, actual ASP.NET Core endpoint tag metadata,/engine/rest-endpoints, andsnapshot.RestEndpointswhileOriginalProjection.TagNamecontinues to preserve the source shorthand tag lineage, and same-value tag rewrites should keepMatchedOverrideIdsvisible while leavingAppliedOverrideId = null - when REST governance rewrites shorthand
OpenApiDocumentName, the same effective answer must driveProjectedEndpoint.OpenApiDocumentName, actual ASP.NET Core endpoint-group metadata,/engine/rest-endpoints, andsnapshot.RestEndpointswhileOriginalProjection.OpenApiDocumentNamecontinues to preserve the source shorthand document lineage, and same-value document rewrites should keepMatchedOverrideIdsvisible while leavingAppliedOverrideId = null - when REST governance clears shorthand explicit bindings through
ClearBindings, the same effective answer must driveProjectedEndpoint.BindingDescriptors, actual ASP.NET Core request composition,/engine/rest-endpoints, andsnapshot.RestEndpoints, and that clear must fail fast when the effective route would only remain valid through explicit placeholder aliases that the source shorthand binding plan had been supplying - when published candidate or endpoint runtime truth is reconciled after ASP.NET Core
materialization, metadata-only same-value rewrites, same-value document rewrites, same-value tag
rewrites, and metadata-clear matches against source metadata the module already set or cleared should keep
MatchedOverrideIdsvisible while leavingAppliedOverrideId = null; those no-op wins should still surface the winning rule throughSelectedOverrideIdplus the decisive specificity answer throughOverrideSelectionBasis - when REST governance rewrites shorthand
RequiredCapabilityKeyor clears it throughClearRequiredCapability, the same effective answer must driveProjectedEndpoint.RequiredCapabilityKey, actual ASP.NET Core endpoint metadata,/engine/rest-endpoints, andsnapshot.RestEndpoints;RequireCapability(...)andClearRequiredCapability()now both follow last-declaration-wins so a host can intentionally replace or remove an earlier shorthand capability boundary without leaving stacked or hidden guards behind - when published endpoint runtime truth needs to explain shorthand capability governance,
/engine/rest-endpointsandsnapshot.RestEndpointsnow also exposeOriginalRequiredCapabilityKey,AppliedOverrideId,SelectedOverrideId, andOverrideSelectionBasis, so the final published surface can distinguish “no capability boundary ever existed” from “a source capability boundary was cleared or rewritten” without forcing operators to reconstruct that answer only from candidate joins; the endpoint-levelAppliedOverrideIdshould remainnullfor capability-only no-op matches whose effective published capability answer does not change, whileSelectedOverrideIdplusOverrideSelectionBasisstill answer which rule won and why - when REST governance rewrites shorthand
RequiredFeatureFlagIdsor clears them throughClearRequiredFeatureFlags, the same effective ordered answer must driveProjectedEndpoint.RequiredFeatureFlagIds, actual ASP.NET Core endpoint metadata,/engine/rest-endpoints, andsnapshot.RestEndpoints;RequireFeatureFlag(...),RequireFeatureFlags(...), andClearRequiredFeatureFlags()now all follow last-declaration-wins so a host can intentionally replace or remove an earlier shorthand feature boundary without leaving stacked or hidden gates behind - when published endpoint runtime truth needs to explain shorthand feature governance,
/engine/rest-endpointsandsnapshot.RestEndpointsnow also expose orderedOriginalRequiredFeatureFlagIds,AppliedOverrideId,SelectedOverrideId, andOverrideSelectionBasis, so the final published surface can distinguish “no feature boundary ever existed” from “a source feature boundary was cleared or rewritten” without forcing operators to reconstruct that answer only from candidate joins; the endpoint-levelAppliedOverrideIdshould remainnullfor feature-only no-op matches whose effective published feature answer does not change, whileSelectedOverrideIdplusOverrideSelectionBasisstill answer which rule won and why - when ASP.NET Core materialization reconciles selected override truth against the actual endpoint metadata it published, applied endpoint-level provenance should only be emitted when the winning rule changed the published surface inside the same action family it targeted; capability-only no-op matches should not start looking applied just because runtime documentation metadata was normalized, and metadata-only no-op matches should not start looking applied just because capability metadata was inspected
- when published endpoint runtime truth needs to explain shorthand governance overlap directly,
/engine/rest-endpointsandsnapshot.RestEndpointsshould also expose the orderedMatchedOverrideIdsset from the originating shorthand candidate so operators can see matched override rules, including capability-only and feature-only no-op matches, without joining back to/engine/rest-endpoint-candidates - within that constrained pattern slice, placeholder-preserving rewrites stay the default and
placeholder renames now also work when the effective explicit route-binding plan covers the
renamed placeholder set exactly, placeholder removals now also work when the original
projection already exposes explicit route-binding coverage for the original placeholder set and
the effective explicit binding plan keeps every affected original route-bound property
explicitly bound, placeholder additions now also work when the effective explicit route-binding
plan covers the full final placeholder set and every newly route-bound property was either
already explicitly bound in the original projection, for
POST/PUT/PATCHalready part of the original deterministic remaining-body fallback surface, or for shorthand candidates with no explicit binding plan already part of the original implicit query-fallback surface, boundedRouteGroupPrefixrewrites now also stay below the active REST root with no placeholders and no silent API-version drift, ASP.NET Core now materializes split effective groups when only some shorthand candidates in one authored group are remapped, moved to another document, or retagged so route mapping, endpoint-group metadata, endpoint tag metadata, and runtime catalogs stay aligned, no-explicit-plan shorthand candidates now also preserve their remaining implicit query-fallback surface when hosts add only partial explicit bindings, typedBindingFallbackModevalues backed byRestEndpointBindingFallbackModenow keep that preserved mode visible on both candidate and published endpoint runtime surfaces, additivemetadata.bindingFallbackMode = preserve-source-implicit-fallbackandmetadata.bindingFallbackMode = preserve-remaining-body-fallbackremain compatibility-only metadata, explicit metadata-only profiles can now also opt into that same source implicit query-fallback answer from the start throughBehaviorRestProfile(PreserveImplicitQueryFallback = true)when they already declare at least one explicit binding, those explicit shorthand profiles can now also promote that remaining preserved query surface into added route placeholders through host overrides, and candidate plus published runtime truth now clearBindingFallbackModeonce the effective binding plan fully consumes that preserved surface; broader implicit-property promotion beyond the shipped body- fallback, no-explicit-plan query-fallback, and source-or-host-preserved-explicit-query-fallback slices remains later work - future shorthand or convention REST publication must compose through the shared projection, runtime-catalog, and collision-validation pipeline instead of bypassing it
- future agentic, AI, or multi-platform expansion should not outrun core engine contract quality, performance, security, and maintainability
Complete REST baseline
Section titled “Complete REST baseline”For Cephalon, the engine-first REST baseline is now considered complete enough to ship when the following remain true together:
- authoring stays module-owned: public REST comes from
RestBehaviorModuleBase,MapProfile<TBehavior>(), generated shorthand throughMapGeneratedProfiles(...)orMapGeneratedProfileGroups(...), or the explicit inline module helpers, never from[AppBehavior]alone - low-ceremony authoring stays explicit and readable: inline helpers, route-group conventions,
WithHostGovernanceScope(...), andAllowHostGovernance()can reduce host code, but they still materialize the same normalized candidate/projection/publication pipeline - runtime truth stays unified:
OriginalProjection,ProjectedEndpoint, candidate ids, publication groups, authoring-policy answers, suppression catalogs, override catalogs, andsnapshotall describe the same winning-versus-skipped governance story without hidden host-only state - merge-mode shorthand binding withdrawals stay safe: on non-body-capable methods a host cannot
silently stop explicitly binding a source query-bound property unless the source profile
deliberately preserved that remaining implicit query surface or the host intentionally resets the
authored explicit plan through
ClearBindings - operator surfaces stay first-class:
/engine/rest-endpoints,/engine/rest-endpoint-candidates,/engine/rest-endpoint-publication-groups,/engine/rest-endpoint-authoring-policies,/engine/rest-endpoint-suppressions,/engine/rest-endpoint-overrides, andsnapshotmust be enough to explain what published, what stayed suppressed, which rules matched, which rules were skipped, and why - BFF documentation materialization stays derived from runtime truth:
/engine/backend-for-frontend/rest-documents, scope-specific filtered OpenAPI routes, and scope-aware Scalar pages must stay projections over the shared binding catalog plus published REST endpoint catalog instead of inventing a separate documentation registry - authored-versus-effective fallback truth stays explicit:
OriginalProjection.BindingFallbackModeremains the source projection answer, whileProjectedEndpoint.BindingFallbackModeand the final published endpoint may surface preserved fallback only when an override legitimately re-exposes that remaining source-owned query surface - host governance stays explicit and bounded: shorthand candidates remain the default governance
target, explicit module-DSL routes only participate when the owning group opts in, and selectors
such as
EndpointNames,HostGovernanceScopes, andTargetBindingskeep matching the original authored candidate identity rather than a later rewritten route shape - applied provenance stays truthful: matched and selected rule ids can stay visible for no-op
winners, but
AppliedOverrideIdand endpoint-level applied-override metadata should only appear when the published route, document, tag, capability, metadata, or binding answer materially changed - later follow-through stays additive: broader convention-backed publication, broader implicit- property promotion, or richer binding evolution should only land through this same normalized projection/runtime-catalog/materialization pipeline instead of inventing a parallel REST model
Current closeout posture
Section titled “Current closeout posture”The core engine-first REST authoring model is now shipped. Recommended posture for new work:
- start new behavior-backed public modules from
dotnet new cephalon-rest-behavior-modulewhen a dedicated package should own both behavior registration and public REST projection from day one - treat the shipped
cephalon-monolith,cephalon-slice, andcephalon-microservicestarters plus the matching blueprint samples as the app-level adoption baseline: whenRestApiis enabled, their public starter modules now begin onRestBehaviorModuleBase.ConfigureRestBehaviors(...).MapProfile<TBehavior>()rather than the genericIRestModulepath - keep
RestBehaviorModuleBaseorAddRestBehaviorModule<TMarker>()as the canonical public- boundary entry points, because they stay explicit about ownership, route groups, and published REST truth - use
MapGeneratedProfiles(...)orMapGeneratedProfileGroups(...)only when generated-profile shorthand materially reduces repetition, but keep those paths on the same module-owned projection, runtime-catalog, and governance pipeline - treat
RestApi:AuthoringPolicies,RestApi:Suppressions, andRestApi:Overridesas additive host governance over shorthand by default; explicit module-DSL routes should only participate when the owning group opts in throughAllowHostGovernance() - evaluate any future convention-backed publication source only if it preserves module ownership, deterministic precedence, and the existing candidate/publication-group/runtime-catalog/operator story instead of inventing a parallel REST model
- treat the shipped backend-for-frontend REST document catalog plus filtered OpenAPI/Scalar surfaces as the frontend-facing documentation baseline; future non-REST or low-code materialization should extend the same runtime catalogs instead of bypassing them