Release 0.2.0-preview.3
Coordinated AppSurface release 0.2.0-preview.3, tagged on 2026-07-17.
Source of truth
This is the release note for AppSurface 0.2.0-preview.3 after 0.2.0-preview.2. It stays provisional until the next tag is cut.
What is taking shape
ForgeTrust.AppSurface.Durablenow separates passive adopter contracts from the publicForgeTrust.AppSurface.Durable.ProviderSPI, with versioned command fingerprints, validated opaque ids, immutable result boundaries, enforceable Work execution-identity transitions, bounded Schedule inputs, passive registration proof, and checked-in public-API baselines. Becausev1remains unpublished and has no persisted deployment, the one-time compatibility exception permits adding explicit canonical type tags now; after the first supported publication or any persisted deployment, every canonical-byte change is incompatible and requires a new schema id. Provider guidance also defines wake-only broker activation and leaves broker-native providers open until a concrete topology can preserve authoritative claims, fences, completion, and recovery. Both source-preview packages remain machine-held from publication until the PostgreSQL provider milestone supplies conformance and restore evidence.ForgeTrust.RazorWirenow owns a deterministic Turbo 8.0.12 default:<rw:scripts />emits an exact package-carried, same-origin runtime before RazorWire, while explicit custom and host-managed policies cover app-owned same-origin files or fully host-owned URL, integrity, CSP, and load-order requirements.ForgeTrust.RazorWireBehavior Kit now exposes root-scoped registrations for DOM enhancement and page-lifecycle registrations for logical browser visits, including PWA display-mode telemetry without fake body selectors or app-owned Turbo listeners.ForgeTrust.AppSurface.DeploymentandForgeTrust.AppSurface.Deployment.GcpCloudRunadd a provider-neutral deployment-intent boundary and a first Cloud Run migration-job compiler. The existing Aspire package annotates one resource graph and participates in Aspire's native publish pipeline; publishing remains tool-free and non-mutating, while verification is read-only and migration execution, state, apply, promotion, and rollback stay application-owned.ForgeTrust.AppSurface.Aspire.Testingadds deterministic typed construction of AppSurface profile graphs without invoking the asynchronous AppHost entry point. It preserves Aspire's configurable build, start, readiness, HTTP, and disposal workflow while rejecting unsupported CliFx-bound profile members and keeping test-only Aspire dependencies out of the runtime package. Publication remains blocked because pinned Aspire 13.4.4 leaks partial host state when host construction fails after creating its service provider.
Included in the next coordinated version
Release and docs surface
ForgeTrust.RazorWirereplaces its implicit CDN dependency with a packaged Turbo 8.0.12 UMD asset served through Razor Class Library static assets and embedded fallbacks.RazorWireOptions.Turbodefaults toBundled, supports a strictly validated same-originCustomPath, and offersHostManagedfor hosts that own cross-origin sourcing, integrity, CSP metadata, and parser-blocking order. Static CDN and hybrid exports materialize the bundled runtime instead of leaving a network dependency behind.ForgeTrust.AppSurface.Web.OpenApinow usesMicrosoft.AspNetCore.OpenApi10.0.9 and directly requiresMicrosoft.OpenApiin the range[2.7.5, 3.0.0), keeping .NET 10 consumers on the supported 2.x line above the range affected by GHSA-v5pm-xwqc-g5wc while preserving existing OpenAPI and Scalar APIs and endpoint behavior.appsurface coverage runcan now start long-running non-exclusive test projects earlier with--schedule longest-first. It reuses priortimings.jsondata when available, preserves integration and Playwright projects as exclusive barriers, supports explicit priority projects, fails invalid explicit timing or priority input before tests run, warns and preserves input order for unmeasured projects when inferred prior timings are missing or unusable, and keeps artifact names stable.appsurface coverage runnow supports repeatable--exclude-test-projectsegment globs for solution-discovered tests. Exclusions are normalized and case-insensitive, reject stale or malformed patterns before side effects, remain visible in list and dry-run output, preserve solution compilation, and are proven through the packaged CLI consumer with an excluded failing sentinel project.ForgeTrust.AppSurface.Webnamed canary evaluation is now available in preview: applications register typed, application-owned proof evaluators and explicitly map one fixed protected route family. The default adapter returns200only forpassand503for completed non-pass states; authenticated diagnostic consumers can opt into status-preservingAlwaysOk. Authorization remains host-owned and fail-closed, inputs and failures are redacted, reserved-route conflicts fail at startup, and triggering, retries, polling, aggregation, and/readybehavior remain outside this primitive.- AppSurface Docs Theme Contract v1 lets hosts configure
AppSurfaceDocs:Themewith dark-family presets (AppSurfaceDarkandGraphiteDark), accent/link color overrides, and density/chrome controls. The package validates enum values, CSS hex colors, null nested theme sections, and contrast-sensitive overrides at startup, emits resolved root attributes and CSS variables into rendered HTML, and freezes those variables into static exports and published archives instead of adding a dynamic themed CSS asset route. - AppSurface Docs now uses a package-specific absolute Razor layout and reasserts it for built-in Docs views, so a consuming application's generic
_ViewStartand_Layoutno longer strip the Docs theme, client configuration, or search scripts. Hosts can still deliberately replace the complete Docs shell by overriding the uniquely named layout path. - Documentation and release authoring guidance now require concept links instead of mention-only prose: start with adopter outcomes, explain internal feature labels in plain language, link named packages, concepts, workflows, diagnostics, guides, examples, and CLI commands to their canonical docs, and keep maintainer evidence after the adoption path.
- The repository coverage script now runs the same aggregate and pull-request patch thresholds as CI's coverage lane. CI supplies
HEAD^1for synthetic pull-request merge checkouts, while local runs compare againstorigin/mainby default and baseline jobs can omit patch thresholds explicitly. - AppSurface DevAuth now centralizes its environment activation policy. DevAuth remains Development-by-default, but
package consumers can explicitly add local/proof environment names through
AllowedEnvironmentNames; the marker self-suppresses outside allowed environments and mapped control/mutation endpoints stay fail-closed. ForgeTrust.AppSurface.Auth.AspNetCore.DevAuthcontrol pages now preserve an explicitly supplied safe localreturnUrlthrough every select-persona and clear-persona form, returning local proof workflows to the page under test. Missing or rejected targets remain omitted, while endpoint names, options, validation, cookies, loopback and same-origin guards, and local-redirect policy remain unchanged; no consumer migration is required.- Split stable and prerelease NuGet publish tag triggers so prerelease tags no longer start the stable publish workflow before the prerelease gate.
- AppSurface DevAuth marker overlays now start collapsed by default while keeping the active fake persona visible, and
AppSurfaceDevAuthMarkerOptions.StartExpandedlets local proof pages opt back into immediate persona controls. ForgeTrust.AppSurface.Auth.AspNetCore.DevAuthnow keeps the default marker as a fixed bottom-right overlay above 640 CSS pixels and places it in normal document flow at 640 CSS pixels or below. Hosts retain control of viewport metadata, render location, outer spacing, and custom styling; authentication behavior and the desktop overlay remain unchanged.- Add
ForgeTrust.AppSurface.Auth.Aspire.Keycloak, an AppHost-only real local OIDC proof package that builds on the official Aspire Keycloak hosting integration, generates deterministic realm/client/user import JSON, projects only safe OIDC settings into a pairedAuth.AspNetCore.Oidcweb proof, adds fixed-port/readiness diagnostics, and keeps Keycloak/Aspire hosting dependencies out of runtime web packages. ForgeTrust.RazorWiredocuments<rw:scripts behavior-kit="true" />, the queue-backedwindow.RazorWire.behaviorsstub, rootregister(...), page-lifecycleregisterLifecycle(...), stable diagnostics, and guidance for choosing built-in managers, root behaviors, lifecycle behaviors, islands, or app-owned JavaScript.appsurface pwa verifynow supports route-shaped readiness evidence for real app entry pages. Apps can verify--base-urlplus--entry-path, follow same-origin redirects that stay under the verified path base, assert manifeststart_url,scope,display, colors, and icon declarations, decode PNG icon dimensions, write schema v2 JSON evidence, and prove that the configured AppSurface service worker is not reachable when offline support is disabled.- AppSurface Web PWA diagnostics now expose the configured service-worker path separately from the active offline service-worker path, so verifier evidence can distinguish "offline disabled and no worker mapped" from "offline enabled with worker/fallback endpoints."
- AppSurface deployment documentation now covers the two-package Aspire adoption path, explicit resource-to-target assignment, closed non-secret GCP binding profiles, immutable image/source evidence, deterministic artifact ownership, shadow versus owned parity, single-writer cutover, compatibility, diagnostics, and the negative assurance that publish does not call GCP or change infrastructure.
ForgeTrust.AppSurface.WebPWA support now activates one generated service worker from independent offline or push options. Push-only apps get no cache or fetch interception; combined apps retain the narrow offline strategy. The package adds an inertwindow.AppSurface.Pwa.register()helper, a strict versioned notification/click adapter, custom-handler imports, PathBase-safe worker metadata, and value-free browser diagnostics without requesting permission, creating subscriptions, or owning delivery.ForgeTrust.AppSurface.WebPWA badging adds a default-off, PathBase-aware page helper and matching active-workerAppSurface.Pwa.badging.set(count)/.clear()adapter. Successful calls resolve toacceptedorunsupported; failures reject with sanitizedASPWAJS040–042errors. The rail reports explicit server-known posture without claiming browser support or icon visibility. It does not change the push payload, CLI schema, worker route, permission ownership, or existing disabled behavior.ForgeTrust.AppSurface.Web.Pushadds the optional safe rail on that worker: retained VAPID keys, required exact push-service origins, explicit protected intake mapping, direct-gesture browser subscription, one-attemptaes128gcm/vapiddelivery, safe classification, and complete-snapshot cleanup for only 404/410. Applications still own identity, tenants, preferences, persistence, recipients, timing, and retry policy; acceptance never claims delivery.
Migration watch
- Remove any app-authored duplicate Turbo tag when adopting the new bundled default. CSP policies can replace the former jsDelivr allowance with
'self'. Hosts that intentionally retain their own tag must setRazorWireOptions.Turbo.RuntimeModetoHostManaged, load Turbo before<rw:scripts />withoutasyncordefer, and treat versions other than 8.0.12 as host-tested compatibility choices. - Record-breaking or behavior-changing guidance here before it moves into the tagged release note.
Pwa.Enablednow controls install metadata only. Apps may activate the shared worker withPwa.Offline.EnabledorPwa.Push.Enabled; existingPwa.Offline.ServiceWorkerPathassignments remain compatible, while new code should usePwa.Worker.ServiceWorkerPath.- DevAuth hosts should include
<meta name="viewport" content="width=device-width, initial-scale=1">and render the default-styled marker after persistent application chrome and before main content. At 640 CSS pixels or below, the marker now occupies that host-owned location instead of the bottom-right viewport overlay; custom-skinned markers withIncludeDefaultStyles = falseremain fully host-owned. - Do not remove or move an already registered service-worker endpoint in one deployment. First ship unregister/replacement cleanup from the old path, let clients receive it, and only then stop mapping that path. See the PWA migration guidance.