Signal-native page migrations + framework + async-job contract#5307
Draft
norman-abramovitz wants to merge 301 commits intodevelopfrom
Draft
Signal-native page migrations + framework + async-job contract#5307norman-abramovitz wants to merge 301 commits intodevelopfrom
norman-abramovitz wants to merge 301 commits intodevelopfrom
Conversation
…atched - StOrg/StApp/StSpace gain cnsiGuid: string as a typed field matching the Stratos contract direction (Track 2 V3 migration). - EndpointDataService and OrgDataService inject cnsiGuid into every resource from HTTP responses (Jetstream doesn't emit it yet). - Shim dispatches build entity dictionaries keyed by cnsiGuid:guid composite, fixing the under-duplicate-URL collision that 2401443 worked around. Apps are now dispatched through the shim (they were deliberately excluded under bare-guid keys because of the shared 'applicationWall' pagination slot — composite keys resolve that). - Specs updated: shim spec asserts composite keys and apps-through-shim; endpoint-data.service spec fixtures include cnsiGuid.
Per-entity byte count + entityType + cnsiGuid go to StratosDiagnostics on every dispatch. Gives a first pass at effectiveness data: which entities are biggest, which CFs contribute most to store weight. entity-key-collision-avoided counter is deferred to Phase 10's marquee integration test which exercises the N=3-4 duplicate-URL scenario needed to trip it.
load() and loadDetails() increment service-call-count per invocation. Cache-hit fires when a warm signal (recentApps populated or orgs populated respectively) lets the call skip re-fetch work; cache-miss fires otherwise. The registry wires diagnostics through to each instance; the diagnostics param is optional on the service so tests that construct without it stay working.
Plugin registered via plugin-config.yaml; extra_plugins.go regenerates at build time from that source. Handler is admin-gated and only active when DIAGNOSTICS_ENABLED env var is set — disabled responses return 404 (not 403) so production scanners can't detect feature availability. SnapshotEnvelope mirrors the frontend's shape so one tooling consumer reads both surfaces uniformly.
Middleware infrastructure: WrapClient(*http.Client, *Buffer) returns a shallow copy whose RoundTripper tallies every request into the buffer. Path GUIDs collapse to /:guid so aggregated counters don't fragment into per-GUID noise. Wiring into portalProxy.GetHttpClient is intentionally NOT in this commit — that touches every CF call path and is best validated against adepttech, not in unit tests. Phase 13 (deploy + validate) will opt the CF HTTP client into the wrap when DIAGNOSTICS_ENABLED.
Phase 0.5's mock_server_test.go fixture alignment (cnsis columns include meta_data AnyArg, /v3/info probe handler) incidentally made this test pass. The TODO skip was stale — removing it recovers the coverage that was dropped when the earlier cnsi_test.go fixtures broke.
Composite entity keys eliminate the cross-endpoint GUID collision that 2401443 worked around; the auto-scope + banner + refetch plumbing is no longer necessary. Deleted: - ApplicationWallComponent.countDuplicateUrlEndpoints + banner HTML - CfAppConfigService.pickInitialCfGuid (restore "null when multiple CFs" default — the All view is now meaningful under composite keys) - Post-ResetPagination re-dispatch in createCfOrSpaceMultipleFilterFn - setMultiFilter-on-cf-change branch in list-pagination-controller All associated specs deleted. Gate passes — test suite is the acceptance proof that the underlying fix works.
Phase 9 deleted the banner along with the auto-scope workaround, but the shared-URL fact itself is useful operator context — it signals "you have N endpoints registered against the same foundation, probably under different auth contexts." Composite keys make that situation work correctly; the banner just surfaces the situation. Wording updated to drop the "scoped to one connection's view" claim (no longer true) and replace with "shown together — use the CF filter to view a single endpoint."
Phase 5.2 added apps dispatch to the shim, reasoning that composite keys made it safe. That's wrong: composite keys protect the entity dictionary (still has all N × apps entries per CF) but the shared 'applicationWall' pagination key is still last-write-wins. Each CF's shim.write() overwrote the shared page with its own 52 IDs / totalResults=52, so the app wall rendered 52 (not 104) apps and — when the page's composite IDs didn't resolve under the app-wall's native fetch expectation — sometimes 0. Yesterday's working shape (00a702a) explicitly did NOT dispatch apps through the shim for exactly this reason. Phase 9 correctly deleted the 2401443 workaround, but Phase 5.2's apps-through-shim addition was a *new* break, not an undo of anything. Restoring the orgs+spaces-only shape. App wall's native fetch path handles multi-endpoint aggregation correctly (and it relies on the composite entity dictionary Phase 3 provides for cross-endpoint isolation). Also in this commit: - manifest.yml: DIAGNOSTICS_ENABLED=true so the admin-gated diagnostics endpoint serves data on adepttech (test environment; prod default off). - stratos-diagnostics.service: window.stratosDiagnostics now binds when isDevMode() OR localStorage.stratos.diagnostics === 'on'. Lets us inspect counts + samples from DevTools on adepttech prod builds without needing a dev build. - Integration test: softened the collision-counter assertion to a "detection code runs without error" shape — the dispatch-spy harness can't observe real store state after mocked dispatches, so the counter will stay 0 in this test. Counter semantics are verified unit-side and will be re-verified live via window.stratosDiagnostics.
SEMVER_VERSION and GO_LDFLAGS were := (immediate) — captured package.json at Make parse time. Chaining `make bump dev build release deploy cf` let bump edit package.json at recipe time, but the already-captured parse-time values flowed into stamp.frontend and the Go binary. Result: build-info.ts stamped the pre-bump version even though package.json had been updated. Changed both to = (lazy). Preserves the interface distinction — VERSION is user-settable input, SEMVER_VERSION is the derived internal canonical — while letting consumers re-evaluate at recipe execution time. Informational derivatives (SEMVER_MAJOR/MINOR/PATCH/PRERELEASE) stay := since they're only used by `dump version` which is a snapshot anyway.
Phase 9 deleted pickInitialCfGuid thinking it was purely a collision workaround. It wasn't — it was also the only thing that gave CfAppsDataSource a concrete endpointGuid to pass to GetAllApplications. Without it, cfGuid=null on initial load and the backend fetch never fires (GetAllApplications requires a specific endpointGuid; there's no "all CFs" backend path). The app wall renders empty until the user manually triggers a re-fetch via the in-app refresh button. Restore a minimal version: pick the first connected CF as the initial filter. Collision protection is no longer part of this function's responsibility — composite keys (Phase 3) handle that. Users switch between endpoints via the CF filter dropdown. Note: apps are still slow to load because there's no shim pre-populate for the applicationWall pagination key (Phase 5.2's apps-through-shim was the wrong solution — it had last-write-wins overwrite semantics on the shared key). Proper fix is a per-CF shim dispatch + aggregating selector; deferred as a follow-up.
Add middleware.GzipWithConfig to the /pp API group with a skipper that bypasses WebSocket upgrades (log-stream, firehose, cfapppush, cfappssh) and MinLength=1024 to skip compression on small polling responses where the CPU cost would outweigh the byte savings. Add wireSizeMiddleware that buffers JSON responses and emits the X-Stratos-Wire-Sizes header with raw_total / keys / values / structural / resources byte breakdown. Active only when DIAGNOSTICS_ENABLED. Feeds empirical measurement for whether further format optimisation beyond gzip would help. Track 2 page 1 — work unit 0 of the applications-wall migration. See stratos KS docs/2026-04-20-track2-page1-appwall-plan.md.
Introduce the shared Go types for the Stratos-shape paging contract: Href object-wrapper, PaginationMeta envelope with camelCase keys and null-on-terminal link semantics, generic StratosPagedResponse[T] top- level envelope, and StratosMeta / StratosError for the tristate / multi-error _meta block. BuildPaginationMeta constructs relative-path links from the incoming request's own URL, preserving all non-page query params. No hardcoded route templates; proxy-stripped prefixes just work. Track 2 page 1 — work unit 1. No handler wiring or consumer yet; that lands in WU 3.
Add memory (*int, MB), diskQuota (*int, MB), and orgGuid (*string) to the Go StApp struct with json:",omitempty" tags; mirror with optional memory, diskQuota on the TS StApp interface and move orgGuid from required to optional. Pointer / optional shapes are the tristate-discipline hint: absent on the wire when the handler couldn't compose the field (e.g., /v3/processes fetch failed), listed in _meta.unavailable for the affected rows. Existing frontend consumers of StApp never read orgGuid (verified via grep), so the required-to-optional change is safe. Memory and diskQuota are new; no consumers yet — those land in WU 5 when the app wall migrates to the primitive. Track 2 page 1 — work unit 2. Handler wiring in WU 3.
Add ?return=summary branch to getNativeApps: parses Stratos-shape paging (page, per_page), sort (order_by + direction, translated to CAPI's minus-prefix form), and filter passthrough for every non- reserved query param. Emits the StratosPagedResponse[StApp] envelope with BuildPaginationMeta-built pagination links. Uses existing toStApp so memory, diskQuota, and orgGuid are still absent from rows — those land in WU 3b (/v3/processes composition) and WU 3c (space-to-org resolution). Backwards-compat paths (counts, recent, no-param) are untouched and still return the legacy StAppsResponse shape; existing FWT-934 home-page card and any other no-param consumers keep working. Track 2 page 1 — work unit 3a.
getNativeAppsSummary now fans out to /v3/processes?app_guids=...& types=web after the app list comes back. The web Process per app supplies memory_in_mb, disk_in_mb, and instances — populated into the StApp.Memory, StApp.DiskQuota, and StApp.Instances fields. When the processes fetch fails, the handler still returns HTTP 200 with the app-level fields intact. Each row carries a _meta.unavail- able list noting the composition-dependent fields that couldn't be populated; the envelope carries a _meta.errors entry with scope "envelope", code PROCESSES_FETCH_FAILED, and the affected GUIDs + field names. HTTP status reflects transport success; the payload itself remains valid — the design distinction locked in Group 4. Empty app list short-circuits the processes fetch. Also: - StApp gains _meta (*StratosMeta) for row-level tristate - TS side adds matching StratosMeta / StratosError interfaces Track 2 page 1 — work unit 3b. orgGuid composition in WU 3c.
Extend getNativeAppsSummary to batch-fetch the /v3/spaces referenced by each app in the current page, then read relationships.organization to populate StApp.OrgGUID. Unique space GUIDs dedupe across apps so the lookup is one call per page regardless of app count. Failure isolation: processes and spaces fetches are independent. Either can fail without affecting the other or the app-level fields. Each failure adds its own envelope _meta.errors entry (with its own Affected field list) and each affected row gets those fields added to its _meta.unavailable. Multi-error design (Group 4 decision) surfaces all failures together. The fw-capi library's ListResponse[T] doesn't expose CAPI's included array, so ?include=space is skipped in favour of the separate batched /v3/spaces fetch. If a future capi library version exposes Included, this can collapse to one round-trip. Track 2 page 1 — work unit 3c. Derived-field sort fallback in WU 3d.
CAPI V3's /v3/apps natively sorts on name, state, created_at, and updated_at only — memory / diskQuota / instances live on processes and aren't sortable server-side. For sort requests on those derived fields, getNativeAppsSummary switches to a fetch-all + compose + in-memory-sort + paginate path. - isDerivedSortField dispatches; field name + direction returned without a minus-prefix helper for the sort routine - fetchAllAppsWithFilters paginates /v3/apps across all CAPI pages with the request's filter set preserved, ignoring order_by + page - sortStAppsByDerivedField sorts the composed slice stably; nil- valued rows (composition failure on that row) always sort to the end regardless of direction — unavailable data doesn't rank ahead of known data - Page slice cut from the sorted in-memory set Per-request buffer is bounded to one CF's matching app set — no cross-CF buffering. Cross-CF merge is the frontend primitive's concern in WU 4. Track 2 page 1 — work unit 3d. WU 3 complete.
The bufferingResponseWriter embedded http.ResponseWriter without overriding WriteHeader, so when a handler called ctx.JSON() the status + headers flushed to the underlying writer before the middleware's post-handler phase could set X-Stratos-Wire-Sizes. Unit tests didn't catch this because they called handlers directly without the middleware chain. Override WriteHeader to capture the status code without forwarding; add flushStatus() helper; call flushStatus() before writing the buffered body or at overflow points. The final Header().Set() calls in the middleware now land before the status line hits the wire. Also add a WebSocket-upgrade skipper matching the gzip middleware so log-stream / firehose / cfapppush / cfappssh don't have their writers wrapped (hijack requires the raw writer). Add five integration tests exercising the middleware in an Echo chain (what the unit tests missed): header emitted on JSON responses, absent when diagnostics off, non-JSON passes through, status code preserved through buffering, WebSocket upgrade skipped. Track 2 page 1 — WU 0 bug fix.
Capture elapsed server-side time from middleware entry to just before flush; emit as an additional field in X-Stratos-Wire-Sizes. Lets the eventual format-optimisation revisit (MessagePack vs columnar tier vs stay-with-gzip) measure CPU cost alongside the byte savings — bytes saved only matter if CPU time doesn't eat the savings. Example header post-change: X-Stratos-Wire-Sizes: raw_total=1910; keys=551; values=1221; structural=138; resources=5; duration_ms=45 Duration covers handler execution + JSON marshal + our tokenise step + any sub-fetch composition. It is end-to-end server time, not network transfer. Client-side parse time stays a DevTools concern. Track 2 page 1 — WU 0 extension.
Issue #2925 (historical P1): gzip on CF passthrough responses corrupted Content-Type for Firefox. WU 0 re-enabled gzip on the full /pp group, which potentially revives the regression on /pp/v1/proxy/... paths. Add a shared Skipper predicate (ppMiddlewareSkipper) used by both gzip and wire-size middleware that bypasses: - WebSocket upgrades (already skipped; consolidated into the shared helper) - /pp/v1/proxy/* paths (new — fixes potential #2925 revival) Passthrough paths aren't Stratos-shape so aren't the target of wire-size instrumentation either; skipping also removes the memory-pressure concern of buffering 200 KB+ CF proxy responses before flushing. Stratos-shape native endpoints (/pp/v1/cf/apps/{cnsi} and sibling routes) keep gzip + wire-size — unchanged behavior. Track 2 page 1 — WU 0 refinement.
uaaScopes and selectedScope are plain fields read by step 2's template; the component runs OnPush. The async submit() awaits a store.select before assigning them, and the assignments alone don't trigger CD — step 2 could render with an empty scope dropdown until something else marks the view dirty. Inject ChangeDetectorRef and call markForCheck() at the end of submit.
Two signal-shape services that wrap the auth ngrx slice and a
localStorage-backed home prefs store. SessionService exposes
sessionData() / config() as signals for any page reading session
config. DashboardPreferencesService owns home-page prefs
(homeShowAllEndpoints, homeLayout) under stratos-home-prefs-{user},
hydrating from localStorage when the username becomes known.
Also exports SessionDataConfig from @stratosui/store so consumers
can type the config signal.
Removes the ngrx Store dependency from the home page and rewires the internal data flow to signals + computed + effect. - Router redirect: store.dispatch(new RouterNav) becomes inject(Router).navigate. Drops the RouterNav action wrapper. - Endpoint bootstrap kick removed. auth.effects already dispatches GetAllEndpoints on every session verify, so the home-side dispatch was redundant. - Session config (homeViewShowFavoritesOnly, endpointCardConcurrency) reads via SessionService instead of store.select(s => s.auth). - Home prefs (homeShowAllEndpoints, homeLayout) read and write via DashboardPreferencesService instead of selectDashboardState + SetDashboardStateValueAction / SetHomeCardLayoutAction. The dashboard ngrx slice keys for these become dead. - Internals: combineLatest / switchMap / pipe chain replaced with computed() signals and a single side-effect effect for show-mode persistence + noneAvailableMsg refresh. allFavorites, connectedEndpoints, haveRegistered, disablePersistenceFeatures bridged via toSignal at the boundary. Template @async pipes replaced with signal calls. allEndpointIds$ stays Observable because PageHeaderComponent still consumes it that way. Existing dashboard ngrx slice persists for other consumers (sidebar prefs, gravatar, timeoutSession, etc.). Users with prior homeShowAllEndpoints / homeLayout in the DASHBOARD localStorage blob see those values orphaned once - new prefs key takes over. Spec: adds redirect + dispatch-guard tests for the home component; adds full coverage for the two new services.
Drains capi.Stacks().List pages, maps each capi.Stack to a Stratos-shape StStack DTO. Three TDD tests cover happy path, empty result (resources:[] not null), and pagination drain.
Replaces CfStacksDataSource + CfStacksListConfigService + the legacy CfStacksCardComponent with a per-CNSI CfStacksSignalConfigService, CnsiStacksSource, and a SignalListComponent-driven page. Loads through the native v3 handler and drops the ngrx pagination plumbing.
Drains capi.Buildpacks().List pages, maps each capi.Buildpack to a Stratos-shape StBuildpack DTO. Coerces nullable Filename/Stack to empty strings so the wire shape stays flat. Three TDD tests cover happy path (READY + AWAITING_UPLOAD rows), empty result (resources:[] not null), and pagination drain.
Replaces CfBuildpacksDataSource + CfBuildpacksListConfigService + the legacy CfBuildpackCardComponent with a per-CNSI CfBuildpacksSignalConfigService, CnsiBuildpacksSource, and a SignalListComponent-driven page. Adds Position/Stack/Filename/Enabled/ Locked columns and drops the ngrx pagination plumbing.
Drains capi.SecurityGroups().List pages, maps each capi.SecurityGroup to a Stratos-shape StSecurityGroup DTO. Reduces the rule array and running/staging space relationships to counts so the list shape stays flat; the future detail screen will own the full rule table. Three TDD tests cover happy path (mixed globally-enabled + space binds), empty result, and pagination drain.
…ty_groups Replaces CfSecurityGroupsDataSource + CfSecurityGroupsListConfigService + the legacy CfSecurityGroupsCardComponent with a per-CNSI CfSecurityGroupsSignalConfigService, CnsiSecurityGroupsSource, and a SignalListComponent-driven page. Adds Rules / Global Running / Global Staging / Running Spaces / Staging Spaces columns and drops the ngrx pagination plumbing.
Drains capi.FeatureFlags().List pages, maps each capi.FeatureFlag to a Stratos-shape StFeatureFlag DTO. Unlike most resources, feature flags have no GUID — name is the identity — and no created_at; only updated_at is tracked, and it is nullable along with custom_error_message. Both nullables are coerced to empty strings server-side. Three TDD tests cover happy path (enabled + disabled with error message), empty result, and pagination drain.
…flags Replaces CfFeatureFlagsDataSource + CfFeatureFlagsListConfigService + the legacy table-cell-feature-flag-state and -description cell components with a per-CNSI CfFeatureFlagsSignalConfigService, CnsiFeatureFlagsSource, and a SignalListComponent-driven page. Columns: Name / Enabled / Custom Error Message / Updated. Drops the ngrx pagination plumbing.
Drains capi.OrganizationQuotas().List and capi.SpaceQuotas().List
respectively, mapping each capi quota onto a flat StOrgQuota or
StSpaceQuota DTO. v3 nests limits under Apps/Services/Routes/Domains
with nullable *int values; the handlers flatten that to top-level int
fields and coerce nil → -1 ("Unlimited") so the wire shape stays flat
ints and the frontend renders without null-guarding every cell.
Six TDD tests across the two suites cover happy path with mixed
limited/unlimited rows, empty result, and pagination drain.
The constant lived inside CfQuotasListConfigService — that file is deleted as part of the signal-native quota migration. The legacy add/edit quota wizards still consume the token to route back to the list after save, so the constant now lives next to the wizards in features/cf/quota-definition-base/quota-route-tokens.ts.
Replaces CfQuotasDataSource + CfQuotasListConfigService and CfSpaceQuotasDataSource + CfSpaceQuotasListConfigService (and the table-cell-quota cell component) with two signal-config services (CfOrgQuotasSignalConfigService + CfSpaceQuotasSignalConfigService), two CnsiEntitySource implementations, and two SignalListComponent- driven page rewrites. Both pages render -1 limits as "Unlimited". The space-quotas service exposes a basePredicate signal so the org-page tab can restrict its foundation-wide list to the active org; the foundation-wide cf-quotas page and the org-scoped tab share the same backend handler with different filter shapes. Drops the ngrx pagination plumbing and the legacy SCSS files that went with the old card-mode renderers.
Adds [trace capi] and [trace handler] log lines at every cfClient.X.List() call site in listAllOrgs, listAllSpaces, and getNativeSpaces (counts + paginated paths) so a future 504 can be attributed to a specific page, filter shape, or to gorouter cutting us off mid-handler. Also adds a ?per_page&page passthrough branch to getNativeSpaces — single CAPI call returning a Stratos-shape paged envelope. Legacy callers without those params keep their existing full-drain wire shape.
Adds two service-plan verticals on the Jetstream V3 native surface: - Reads: GET list with StratosPagedResponse[StServicePlan], ?guids filter for batch lookup, ?return=counts fast path, single-resource GET /:planGuid for detail. - Visibility: GET/POST/PATCH/DELETE on /:planGuid/visibility with one Echo handler dispatching POST→ApplyVisibility (replace) and PATCH→UpdateVisibility (merge). Names are inverted relative to CAPI HTTP semantics — documented inline. Both verticals follow the wire-contract principles forced by the spaces-504 incident: bounded pagination, single-resource endpoints, guid-batch as a first-class branch, no implicit auto-drain.
Bounded list with ?guids batch + ?return=counts fast path, plus a single-resource GET /:brokerGuid for detail. Mirrors the wire-contract baseline established by service_plans: one CAPI call per request, no auto-drain, guid-batch as a first-class branch. Auth credentials are not surfaced on the read shape — those land with the broker write vertical when it follows.
Bounded list with ?guids batch + ?return=counts fast path, plus a single-resource GET /:domainGuid for detail. V3 unifies V2's split shared/private domain endpoints into one resource — Stratos shape flattens relationships into owningOrgGuid (empty = shared) and sharedOrgGuids, surfaces internal + supportedProtocols + router group guid as flat fields.
POST /pp/v1/cf/user_provided_service_instances/:cnsi creates via the
unified v3 /v3/service_instances with type=user-provided; PATCH
/:siGuid updates. Both are sync — no async-job dance — so the SDK
returns the resource directly via its interface{} return.
Surfaces syslogDrainUrl + routeServiceUrl on StServiceInstance as
omitempty fields, populated by the existing read pipeline as well.
Type discriminator is sent on create only; v3 forbids changing it
on update.
11 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Post-Angular-21 work stream consolidating signal-native page migrations, new SignalList framework slots, and an end-to-end async-job contract for slow CF v3 operations. Dev iterations v5.0.0-dev.10 → dev.26.
What's in here
Signal-native infrastructure
EndpointDataService/OrgDataService/EndpointDataRegistry— per-endpoint and per-org signal stores with parallel fetchEndpointDataShim— write-through bridge from Stratos-shape to NgRxPage migrations to signal-native list
SignalListConfig framework additions
headerActionsslot for page-level actions (Manage Roles, Invite User…)maxVisiblefor cells with hundreds of segmentsApp wall improvements
Async-job contract (Jetstream)
stratosjobsplugin with translator, tracker, typesnorman-abramovitz/fw-capifork forApps.Delete→(*Job, error)until upstream landsBug fixes
endpointDataServiceheld in a plain field;orgs/spacescomputeds tracked only the first endpoint's signal forever. Fix wraps the field inWritableSignalso the computeds re-track on CNSI swap. Affectscf-orgs-signal-configandcf-spaces-signal-config.signal-list.component.html— favorite/actions columns share an empty header, so tracking bycol.headerproduced duplicate""keys on every CD pass. Switched all six call sites tocol.key. Console quieter, rendering noticeably faster.[favorite]race with[entityConfig]— converted favorite to a setter that records whether the parent bound it, and moved the entity-monitor fallback subscription tongOnInitso the race no longer overwrites a parent-supplied favorite via the entity-stamped cfGuid.authTypesdefault to UsernamePassword + None so plugin-package endpoints (metrics, autoscaler) render their Connect step instead of crashing onObject.keys(undefined).transformutility on modal content was creating a containing block and breakingposition:fixedmath).markForCheck'd after busy resets so retry works under OnPush + zoneless.Dependency bumps
golang.org/x/cryptoacross three plugins (clears 6 moderates)@stratosui/devkitto Angular 21 toolchainTest plan
make check gate) greenNotes for review