Skip to content

feat(cache): add opt-in SSR fragment caching - #707

Draft
m2broth wants to merge 4 commits into
masterfrom
add_ilc_cache
Draft

feat(cache): add opt-in SSR fragment caching#707
m2broth wants to merge 4 commits into
masterfrom
add_ilc_cache

Conversation

@m2broth

@m2broth m2broth commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Adds opt-in, per-app caching of SSR fragment responses to cut redundant renders under load, via a registry-configured ssr.cache.{enabled,ttlSeconds}.

  • Stale-while-revalidate: one background refresh per key; concurrent requests get the stale copy instantly instead of queuing behind it.
  • Single-flight capture with a byte/count/concurrency-bounded, evicting in-memory store; capacity is injectable and asserted at composition time.
  • Strict user isolation: shared renders forward only an anonymized header set (host/locale) — never cookies, auth, UA, or the query string.
  • A response is cached only on a plain 200 with no Set-Cookie and no Cache-Control directive (bare or field-qualified) forbidding reuse.
  • A named refusal taxonomy surfaced through New Relic metrics, an HTML debug marker, and logs, so "why wasn't this cached" is diagnosable without reading code.
  • A render deadline bounds how long a stale/cold render can buffer before falling back to a private render, without capping legitimately slow ones.

Known limitation: there's no automated way to exclude price-bearing routes from caching — enforcement relies on per-app opt-in discipline and the fragment responding with Cache-Control: no-store (see "Fragments rendering prices" in docs/ssr_fragment_caching.md). An app serving both a static and a price-bearing route under the same ssr.cache config has no per-route exclusion today.

Volodymyr Malyhin added 3 commits August 18, 2026 17:08
Adds opt-in, per-app caching of SSR fragment responses to cut redundant
renders under load, via a registry-configured ssr.cache.{enabled,ttlSeconds}.

- Stale-while-revalidate: one background refresh per key; concurrent
  requests get the stale copy instantly instead of queuing behind it.
- Single-flight capture with a byte/count/concurrency-bounded, evicting
  in-memory store; capacity is injectable and asserted at composition time.
- Strict user isolation: shared renders forward only an anonymized header
  set (host/locale) — never cookies, auth, UA, or the query string.
- A response is cached only on a plain 200 with no Set-Cookie and no
  Cache-Control directive (bare or field-qualified) forbidding reuse.
- A named refusal taxonomy surfaced through New Relic metrics, an HTML
  debug marker, and logs, so "why wasn't this cached" is diagnosable
  without reading code.
- A render deadline bounds how long a stale/cold render can buffer before
  falling back to a private render, without capping legitimately slow ones.
Adds opt-in, per-app caching of SSR fragment responses to cut redundant
renders under load, via a registry-configured ssr.cache.{enabled,ttlSeconds}.

- Stale-while-revalidate: one background refresh per key; concurrent
  requests get the stale copy instantly instead of queuing behind it.
- Single-flight capture with a byte/count/concurrency-bounded, evicting
  in-memory store; capacity is injectable and asserted at composition time.
- Strict user isolation: shared renders forward only an anonymized header
  set (host/locale) — never cookies, auth, UA, or the query string.
- A response is cached only on a plain 200 with no Set-Cookie and no
  Cache-Control directive (bare or field-qualified) forbidding reuse.
- A named refusal taxonomy surfaced through New Relic metrics, an HTML
  debug marker, and logs, so "why wasn't this cached" is diagnosable
  without reading code.
- A render deadline bounds a cold miss before falling back to a private
  render, and separately bounds how long a background refresh may run
  before it's abandoned - a stale request itself is never delayed by it.

Known limitations:
- No automated way to exclude price-bearing routes from caching -
  enforcement relies on per-app opt-in discipline and the fragment
  responding with Cache-Control: no-store (see "Fragments rendering
  prices" in docs/ssr_fragment_caching.md). An app serving both a static
  and a price-bearing route under the same ssr.cache config has no
  per-route exclusion today.
- Per-instance, in-memory cache: no cross-instance sharing, cold after
  every deploy/restart.
@github-actions

Copy link
Copy Markdown

Coverage Report

Ilc/server

Commit SHA:a3eb0f068cde5f47e6293fcd545b980fd2f0aa98

Test coverage results 🧪

Code coverage diff between base branch:master and head branch: add_ilc_cache 
File details
Status File % Stmts % Branch % Funcs % Lines
🟢 total 95.98 (0.79) 90.03 (-0.41) 91.71 (0.99) 96.13 (0.76)
/codebase/common/DefaultCacheWrapper.ts 100 100 100 100
/codebase/common/EvictingCacheStorage.ts 100 100 100 100
/codebase/common/utils.ts 100 100 100 100
/codebase/common/router/Router.ts 98 91.66 100 98
/codebase/common/router/errors.ts 100 100 100 100
/codebase/common/transition-hooks/ActionType.ts 100 100 100 100
/codebase/common/transition-hooks/errors.ts 100 100 100 100
/codebase/server/TransitionHooksExecutor.ts 100 100 100 100
/codebase/server/app.js 96.96 81.81 100 96.96
/codebase/server/i18n.js 97.95 95.83 100 97.82
/codebase/server/index.js 0 100 0 0
/codebase/server/objectToBase64.js 100 100 100 100
/codebase/server/serveStatic.ts 29.41 0 16.66 33.33
/codebase/server/server.js 0 0 0 0
/codebase/server/application/application.ts 100 100 75 100
/codebase/server/context/context.ts 88.88 50 75 88.88
/codebase/server/errorHandler/ErrorHandler.ts 100 100 100 100
/codebase/server/errorHandler/factory.js 100 100 100 100
/codebase/server/experiments/StaticConfigRulesetProvider.ts 73.33 0 100 73.33
/codebase/server/experiments/assign.ts 100 97.5 88.88 100
/codebase/server/experiments/bucket.ts 100 100 100 100
/codebase/server/experiments/consent.ts 100 66.66 100 100
/codebase/server/experiments/cookies.ts 100 100 100 100
/codebase/server/experiments/index.ts 91.66 76 50 90.62
/codebase/server/experiments/ruleset.ts 100 75 100 100
/codebase/server/experiments/validate.ts 90.19 83.33 100 90.19
/codebase/server/logger/accessLogger.js 100 87.5 100 100
/codebase/server/logger/enhanceLogger.js 100 100 100 100
/codebase/server/plugins/PluginsLoader.js 82.35 100 50 86.66
/codebase/server/plugins/pluginManager.js 100 100 100 100
/codebase/server/plugins/reportingPlugin.js 100 50 100 100
/codebase/server/registry/Registry.js 92.36 79.06 83.33 93.75
/codebase/server/registry/TemplateParser.js 100 100 100 100
/codebase/server/registry/errors.ts 100 100 100 100
/codebase/server/registry/factory.ts 90.9 100 50 90
/codebase/server/registry/isTemplateValid.js 100 100 100 100
/codebase/server/routes/pingPluginFactory.ts 100 100 100 100
/codebase/server/routes/renderTemplateHandlerFactory.ts 100 100 100 100
/codebase/server/routes/wildcardRequestHandlerFactory.ts 100 100 100 100
/codebase/server/services/CanonicalTagService.ts 100 100 100 100
/codebase/server/services/CspBuilderService.js 100 91.66 100 100
/codebase/server/services/HrefLangService.js 92.59 62.5 100 92.59
/codebase/server/tailor/configs-injector.ts 97.27 91.66 100 97.27
/codebase/server/tailor/error-handler.js 100 100 100 100
/codebase/server/tailor/errors.js 100 100 100 100
✨ 🆕 /codebase/server/tailor/factory.ts 100 66.66 100 100
/codebase/server/tailor/fetch-template.ts 100 100 100 100
/codebase/server/tailor/filter-headers.ts 100 90 100 100
✨ 🆕 /codebase/server/tailor/fragment-hooks.ts 100 100 100 100
✨ 🆕 /codebase/server/tailor/fragment-render.ts 100 75 100 100
/codebase/server/tailor/merge-configs.ts 100 90.62 100 100
/codebase/server/tailor/parse-override-config.js 100 100 100 100
/codebase/server/tailor/process-fragment-response.js 100 93.75 100 100
✨ 🆕 /codebase/server/tailor/request-fragment.ts 97.77 92.1 100 97.77
✨ 🆕 /codebase/server/tailor/server-router.ts 98.41 97.14 100 98.38
✨ 🆕 /codebase/server/tailor/request-fragment-cache/cached-fragment-requester.ts 100 80 91.66 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/index.ts 100 100 80 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/marker.ts 100 100 100 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/pending-call-registry.ts 100 100 100 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/response-cache.ts 100 94.44 100 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/response-snapshot.ts 100 100 100 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/storage-factory.ts 87.5 66.66 66.66 87.5
✨ 🆕 /codebase/server/tailor/request-fragment-cache/store.ts 100 100 100 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/types/refusal.ts 100 100 100 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/utils/capacity-budget.ts 100 100 100 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/utils/capture.ts 100 72.72 100 100
✨ 🆕 /codebase/server/tailor/request-fragment-cache/utils/policy.ts 100 86.2 100 100
/codebase/server/types/FastifyReply.ts 100 100 100 100
/codebase/server/types/IlcRequest.ts 100 100 100 100
/codebase/server/types/PatchedHttpRequest.ts 100 100 100 100
/codebase/server/utils/helpers.ts 100 100 100 100
/codebase/server/utils/utils.js 100 100 100 100
/codebase/server/tailor/factory.js 100 0 100 100
/codebase/server/tailor/fragment-hooks.js 100 100 100 100
/codebase/server/tailor/request-fragment.js 96.51 92 100 96.51
/codebase/server/tailor/server-router.js 98.61 96.42 100 98.59

Ilc/client

Commit SHA:a3eb0f068cde5f47e6293fcd545b980fd2f0aa98

Test coverage results 🧪

Code coverage diff between base branch:master and head branch: add_ilc_cache 
File details
Status File % Stmts % Branch % Funcs % Lines
🔴 total 94.28 (-0.08) 86.85 (0.08) 92.89 (-0.42) 94.52 (-0.03)
/codebase/client.plugins.manifest.js 100 100 100 100
/codebase/client/AsyncBootUp.js 100 80 100 100
/codebase/client/BundleLoader.ts 92.72 97.05 81.25 92.45
/codebase/client/CanonicalTagHandler.ts 100 93.75 100 100
/codebase/client/Client.js 89.92 79.48 88.23 89.85
/codebase/client/ClientRouter.js 95.29 90.9 95.65 95.09
/codebase/client/CssTrackedApp.ts 94.04 88.57 92.3 96.15
/codebase/client/HrefLangHandler.js 100 100 100 100
/codebase/client/ParcelApi.js 97.05 87.5 100 96.96
/codebase/client/PluginsLoader.js 55.55 25 33.33 62.5
/codebase/client/TransitionHooksExecutor.js 96.15 88.88 100 96.15
/codebase/client/WrapApp.js 97.18 76.47 93.75 98.52
/codebase/client/composeAppSlotPairsToRegister.js 100 100 100 100
/codebase/client/dispatchSynchronizedEvent.js 96.96 100 100 96.55
/codebase/client/i18n.js 90.9 86.66 90.9 90.47
/codebase/client/initIlcState.js 100 100 100 100
/codebase/client/registerSpaApps.js 78.46 59.09 53.33 79.36
/codebase/client/utils.js 92 80.95 90 95.83
/codebase/client/ErrorHandlerManager/ErrorHandlerManager.js 100 90 100 100
/codebase/client/Sdk/SdkAdapterFactory.js 100 100 100 100
/codebase/client/Sdk/SdkFactoryBuilder.js 100 100 100 100
/codebase/client/TransitionManager/TransitionBlocker.js 93.93 87.5 100 93.93
/codebase/client/TransitionManager/TransitionBlockerList.js 94.73 50 100 93.33
/codebase/client/TransitionManager/TransitionManager.js 92.14 81.48 89.28 92.08
/codebase/client/TransitionManager/GlobalSpinner/GlobalSpinner.js 100 100 100 100
/codebase/client/TransitionManager/ScrollController/ScrollController.js 95.83 100 100 95.83
/codebase/client/TransitionManager/SlotRenderObserver/SlotRenderObserver.js 85.18 79.16 100 84.61
/codebase/client/TransitionManager/TransitionHooks/BaseTransitionHook.js 0 100 0 0
/codebase/client/TransitionManager/TransitionHooks/PerformanceTransitionHook.js 100 100 100 100
/codebase/client/TransitionManager/TransitionHooks/TitleCheckerTransitionHook.js 100 100 100 100
/codebase/client/TransitionManager/TransitionHooks/TransitionHooks.js 100 80 100 100
/codebase/client/TransitionManager/errors/CriticalSlotTransitionError.js 100 100 100 100
/codebase/client/configuration/IlcConfigRoot.js 92.3 60 100 92.3
/codebase/client/configuration/SystemJSImportMap.js 93.33 75 100 93.33
/codebase/client/configuration/getIlcConfigRoot.js 100 100 100 100
/codebase/client/constants/ilcEvents.js 100 100 100 100
/codebase/client/errors/BaseError.js 100 86.66 100 100
/codebase/client/errors/CorsError.js 100 100 100 100
/codebase/client/errors/CriticalFragmentError.js 100 100 100 100
/codebase/client/errors/CriticalInternalError.js 100 100 100 100
/codebase/client/errors/CriticalRuntimeError.js 100 100 100 100
/codebase/client/errors/FetchTemplateError.js 100 100 100 100
/codebase/client/errors/FragmentError.js 100 100 100 100
/codebase/client/errors/InternalError.js 100 100 100 100
/codebase/client/errors/NavigationError.js 100 100 100 100
/codebase/client/errors/RuntimeError.js 100 100 100 100
/codebase/client/errors/UnhandledError.js 100 100 100 100
/codebase/client/navigationEvents/index.js 100 100 100 100
/codebase/client/navigationEvents/setupEvents.js 90.24 88.09 94.11 90
🔴 /codebase/client/registry/BrowserCacheStorage.ts 75 (-25) 100 (0) 75 (-25) 75 (-25)
/codebase/client/registry/Registry.js 90 50 100 90
/codebase/client/registry/errors.js 100 100 100 100
/codebase/client/registry/factory.ts 100 100 100 100
/codebase/client/utils/exponentialRetry.ts 100 100 100 100
/codebase/common/DefaultCacheWrapper.ts 98.07 95.45 100 97.95
/codebase/common/Environment.js 100 100 100 100
/codebase/common/EvictingCacheStorage.ts 100 100 100 100
/codebase/common/SdkOptions.js 100 100 100 100
/codebase/common/UrlProcessor.js 100 100 100 100
/codebase/common/constants.js 100 100 100 100
/codebase/common/i18nCookie.js 100 100 100 100
🔴 /codebase/common/utils.ts 97.22 (-2.78) 100 (0) 93.33 (-6.67) 100 (0)
/codebase/common/Slot/Slot.js 100 100 100 100
/codebase/common/Slot/SlotCollection.js 100 100 100 100
/codebase/common/Slot/SpaSlot.js 100 100 100 100
/codebase/common/Slot/SpaSlotCollection.js 100 100 100 100
/codebase/common/router/Router.ts 97.87 93.54 100 97.87
/codebase/common/router/errors.ts 100 100 100 100
/codebase/common/transition-hooks/errors.ts 100 100 100 100

Registry

Commit SHA:a3eb0f068cde5f47e6293fcd545b980fd2f0aa98

Test coverage results 🧪

Code coverage diff between base branch:master and head branch: add_ilc_cache 
File details
Status File % Stmts % Branch % Funcs % Lines
total 90.15 78.73 81.43 90.21
/codebase/newrelic.js 100 50 100 100
/codebase/server.plugins.manifest.ts 100 100 100 100
/codebase/lde/oauth-server.ts 0 100 0 0
/codebase/server/app.ts 100 50 100 100
/codebase/server/index.ts 0 100 0 0
/codebase/server/runnerAssetsDiscovery.ts 0 0 0 0
/codebase/server/server.ts 0 0 0 0
/codebase/server/appRoutes/interfaces/index.ts 100 100 100 100
/codebase/server/appRoutes/routes/RoutesService.ts 100 100 100 100
/codebase/server/appRoutes/routes/createAppRoute.ts 97.22 100 100 97.22
/codebase/server/appRoutes/routes/deleteAppRoute.ts 100 100 100 100
/codebase/server/appRoutes/routes/getAppRoute.ts 100 100 100 100
/codebase/server/appRoutes/routes/getAppRoutes.ts 96 87.5 100 96
/codebase/server/appRoutes/routes/index.ts 100 100 100 100
/codebase/server/appRoutes/routes/updateAppRoute.ts 100 100 100 100
/codebase/server/appRoutes/services/prepareAppRoute.ts 100 60 100 100
/codebase/server/appRoutes/services/resolveDomainAlias.ts 100 100 100 100
/codebase/server/appRoutes/services/transformSpecialRoutes.ts 100 100 100 100
🟢 /codebase/server/apps/interfaces/index.ts 95.23 (0.23) 100 (0) 75 (0) 95.23 (0.23)
/codebase/server/apps/repositories/AppsRepository.ts 97.5 86.66 100 97.5
/codebase/server/apps/routes/createApp.ts 100 100 100 100
/codebase/server/apps/routes/deleteApp.ts 100 100 100 100
/codebase/server/apps/routes/getApp.ts 100 100 100 100
/codebase/server/apps/routes/getApps.ts 100 50 100 100
/codebase/server/apps/routes/index.ts 100 100 100 100
/codebase/server/apps/routes/updateApp.ts 96.29 85.71 100 96.29
/codebase/server/apps/services/resolveDomainAlias.ts 100 100 100 100
/codebase/server/auth/index.ts 97.5 0 100 97.5
/codebase/server/auth/handlers/availableMethodsHandler.ts 100 100 100 100
/codebase/server/auth/handlers/localLoginHandler.ts 100 100 100 100
/codebase/server/auth/handlers/logoutHandler.ts 75 25 100 81.81
/codebase/server/auth/handlers/openIdAuthCallbackHandler.ts 94.44 66.66 100 94.44
/codebase/server/auth/middleware/bearerAuthenticationMiddleware.ts 100 100 100 100
/codebase/server/auth/middleware/initializeOpenIdMiddleware.ts 92.85 66.66 100 92.85
/codebase/server/auth/middleware/rolesMiddleware.ts 100 100 100 100
/codebase/server/auth/services/AuthService.ts 100 100 100 100
/codebase/server/auth/services/OpenIdService.ts 100 100 100 100
/codebase/server/auth/strategies/CustomOIDCStrategy.ts 88.88 60 100 88.88
/codebase/server/auth/strategies/bearer.ts 100 100 100 100
/codebase/server/auth/strategies/local.ts 100 100 100 100
/codebase/server/auth/strategies/oidc.ts 94.11 73.07 100 93.93
/codebase/server/authEntities/interfaces.ts 100 100 100 100
/codebase/server/authEntities/routes/create.ts 100 100 100 100
/codebase/server/authEntities/routes/deleteRoute.ts 100 100 100 100
/codebase/server/authEntities/routes/get.ts 100 100 100 100
/codebase/server/authEntities/routes/getAll.ts 100 100 100 100
/codebase/server/authEntities/routes/index.ts 100 100 100 100
/codebase/server/authEntities/routes/update.ts 100 100 100 100
/codebase/server/common/services/json.ts 81.81 84 91.66 80
/codebase/server/common/services/preProcessResponse.ts 85.71 100 0 85.71
/codebase/server/common/services/protectedEntities.ts 100 100 100 100
/codebase/server/common/services/validateRequest.ts 92.59 80 100 92.3
/codebase/server/common/services/assets/AssetsDiscovery.ts 95 76.47 93.33 95
/codebase/server/common/services/assets/AssetsDiscoveryProcessor.ts 94.11 66.66 100 94.11
/codebase/server/common/services/assets/AssetsDiscoveryWhiteLists.ts 100 100 100 100
/codebase/server/common/services/assets/AssetsManifestReader.ts 100 100 100 100
/codebase/server/common/services/assets/AssetsValidator.ts 100 100 100 100
/codebase/server/common/services/assets/assetsManifestProcessor.ts 100 100 100 100
/codebase/server/common/services/assets/errors/AssetsManifestError.ts 100 100 100 100
/codebase/server/common/services/entries/ApplicationEntry.ts 95.16 81.81 100 95.16
/codebase/server/common/services/entries/Entry.ts 0 0 0 0
/codebase/server/common/services/entries/EntryFactory.ts 95.23 80 100 95.23
/codebase/server/common/services/entries/SharedLibEntry.ts 97.56 85.71 100 97.56
/codebase/server/common/services/entries/error/EntryError.ts 100 100 100 100
/codebase/server/common/services/entries/error/IncorrectEntryError.ts 100 100 100 100
/codebase/server/common/services/entries/error/NotFoundApplicationError.ts 100 100 100 100
/codebase/server/common/services/entries/error/NotFoundFqrnError.ts 100 100 100 100
/codebase/server/common/services/entries/error/NotFoundSharedLibraryError.ts 100 100 100 100
/codebase/server/common/services/entries/error/ValidationFqrnError.ts 100 100 100 100
/codebase/server/config/ConfigService.ts 97.18 91.89 100 97.1
/codebase/server/config/getConfig.ts 100 100 100 100
/codebase/server/config/index.ts 100 100 100 100
/codebase/server/config/transformConfig.ts 95.83 80.64 100 95.34
/codebase/server/config/updateConfig.ts 93.33 100 100 93.33
/codebase/server/config/validateConfig.ts 100 100 100 100
/codebase/server/db/cascadeTruncate.ts 71.42 50 100 71.42
/codebase/server/db/index.ts 100 80 100 100
/codebase/server/db/logger.ts 100 100 100 100
/codebase/server/db/range.ts 100 100 100 100
/codebase/server/db/structure.ts 100 100 100 100
/codebase/server/db/syncSequence.ts 100 100 100 100
/codebase/server/db/versioning.ts 93.33 0 100 93.33
/codebase/server/entries/entries.ts 87.09 85.71 100 87.09
/codebase/server/errorHandler/httpErrors.ts 100 100 100 100
/codebase/server/errorHandler/index.ts 100 100 100 100
/codebase/server/errorHandler/noticeError.ts 100 0 100 100
/codebase/server/middleware/context.ts 100 66.66 100 100
/codebase/server/middleware/filters.ts 100 100 100 100
/codebase/server/middleware/unless.ts 100 75 100 100
/codebase/server/middleware/userContext.ts 100 100 100 100
/codebase/server/middleware/validatelocales.ts 95.23 66.66 100 95
/codebase/server/migrations/20191016185102_apps.ts 100 100 66.66 100
/codebase/server/migrations/20191017131220_templates.ts 100 100 66.66 100
/codebase/server/migrations/20191017131749_routes.ts 100 100 66.66 100
/codebase/server/migrations/20191017144455_route_slots.ts 100 100 66.66 100
/codebase/server/migrations/20200113141956_apps.ts 66.66 100 50 66.66
/codebase/server/migrations/20200113142437_route_slots.ts 66.66 100 50 66.66
/codebase/server/migrations/20200120162838_apps_config_selector.ts 66.66 100 50 66.66
/codebase/server/migrations/20200121110723_shared_props.ts 83.33 100 66.66 83.33
/codebase/server/migrations/20200409184919_auth_entitites.ts 100 100 66.66 100
/codebase/server/migrations/20200409190157_auth_entitites_default.ts 100 100 50 100
/codebase/server/migrations/20200410180130_sessions.ts 88.88 50 66.66 88.88
/codebase/server/migrations/20200518134531_apps_initProps_removal.ts 66.66 100 50 66.66
/codebase/server/migrations/20200729141256_settings.ts 100 100 66.66 100
/codebase/server/migrations/20201012152003_settings_meta.ts 58.33 100 50 58.33
/codebase/server/migrations/20201013140633_settings_default.ts 90.9 50 75 90.9
/codebase/server/migrations/20201027180112_settings_globalSpinner.ts 80 100 50 80
/codebase/server/migrations/20201028142200_settings_i18n.ts 80 100 50 80
/codebase/server/migrations/20201029122727_settings_AuthOpenIdUniqueIdentifierClaimName.ts 80 100 50 80
/codebase/server/migrations/20201105155522_versioning.ts 90.9 100 66.66 90.9
/codebase/server/migrations/20201130141801_i18n_enabled_by_default.ts 80 100 50 80
/codebase/server/migrations/20201228201314_route_meta.ts 66.66 100 50 66.66
/codebase/server/migrations/20210125185210_app_wrapper_kind.ts 66.66 25 75 66.66
/codebase/server/migrations/20210125185211_apps_wrappedWith.ts 66.66 100 50 66.66
/codebase/server/migrations/20210219174348_settings_overrideConfigTrustedOrigins.ts 80 100 50 80
/codebase/server/migrations/20210226191151_apps_ssrProps.ts 66.66 100 50 66.66
/codebase/server/migrations/20210226191205_shared_props_ssrProps.ts 66.66 100 50 66.66
/codebase/server/migrations/20210405164831_router_domains.ts 85.71 100 66.66 85.71
/codebase/server/migrations/20210405182655_routes_domainId.ts 63.46 37.5 59.09 63.46
/codebase/server/migrations/20210426163602_routes_orderPosIsNullable.ts 66 37.5 54.16 66
/codebase/server/migrations/20210430154258_routes_uniqfromSpecialRoleToRoute.ts 62.5 100 50 62.5
/codebase/server/migrations/20210430154639_routes_moveSpecialRolesToRoute.ts 35.29 0 37.5 35.29
/codebase/server/migrations/20210430155514_routes_removeColumnSpecialRole.ts 66.66 100 50 66.66
/codebase/server/migrations/20210505151225_routes_domainIdIdxble.ts 46.15 40 33.33 46.15
/codebase/server/migrations/20210505181754_routes_orderPos_unique_per_domain.ts 62.5 100 50 62.5
/codebase/server/migrations/20210505182004_routes_route_unique_per_domain.ts 62.5 100 50 62.5
/codebase/server/migrations/20210505182425_old_tbls_cleanup.ts 80 50 50 80
/codebase/server/migrations/20210521125202_routes_drop_unique_route.ts 66.66 100 50 66.66
/codebase/server/migrations/20210607160910_apps_discoveryMetadata.ts 66.66 100 50 66.66
/codebase/server/migrations/20210607161242_apps_adminNotes.ts 66.66 100 50 66.66
/codebase/server/migrations/20210625150840_roles_userToReadonly.ts 50 50 50 50
/codebase/server/migrations/20210701183133_auth_entity_readonly.ts 80 100 50 80
/codebase/server/migrations/20210826144904_shared_libs.ts 88.88 100 66.66 88.88
/codebase/server/migrations/20220121115756_settings_onPropsUpdate.ts 80 100 50 80
/codebase/server/migrations/20220315155008_increase-template-size.ts 66.66 100 50 66.66
/codebase/server/migrations/20220316133143_versioning-text-update.ts 62.5 100 50 62.5
/codebase/server/migrations/20220323123155_add-locale-to-template.ts 88.88 100 66.66 88.88
/codebase/server/migrations/20220520083801_apps_enforceDomain.ts 66.66 100 50 66.66
/codebase/server/migrations/20220815164948_l20nManifest.ts 66.66 100 50 66.66
/codebase/server/migrations/20220819204836_rename-use-l10n.ts 66.66 100 50 66.66
/codebase/server/migrations/20220928161155_shared-lib-add-localization.ts 66.66 100 50 66.66
/codebase/server/migrations/20221118164122_add_csp_settings.ts 80 100 50 80
/codebase/server/migrations/20221123163817_csp-available-host-for-local.ts 80 100 50 80
/codebase/server/migrations/20221201191407_csp_enable_scrict_mode.ts 100 100 50 100
/codebase/server/migrations/20230303174003_settings-add-primary-key.ts 66.66 100 50 66.66
/codebase/server/migrations/20230303175443_settings-domain-value-table.ts 90 100 66.66 90
/codebase/server/migrations/20230703130802_remove-spa-bundle-constraint.ts 66.66 100 50 66.66
/codebase/server/migrations/20231003103643_routes_meta.ts 44.44 0 25 44.44
/codebase/server/migrations/20240315141721_pg_versioning_idx.ts 57.14 0 50 57.14
/codebase/server/migrations/20250225163431_unique_route.ts 70 100 50 70
/codebase/server/migrations/20250227154210_unique_app.ts 70 100 50 70
/codebase/server/migrations/20250303125703_orderpos_sequence.ts 30.76 0 25 30.76
/codebase/server/migrations/20250313162453_unique_route_v2.ts 63.63 50 50 63.63
/codebase/server/migrations/20250331085251_routeIdCascadeDelete.ts 62.5 100 50 62.5
/codebase/server/migrations/20250404133940_orderpos_sequence_revert.ts 30.76 0 25 30.76
/codebase/server/migrations/20250618105344_add_props_to_router_domains.ts 62.5 100 50 62.5
/codebase/server/migrations/20250818155232_canonical_domain_to_router_domain.ts 66.66 100 50 66.66
/codebase/server/migrations/20260113105120_sanitize_versioning_secrets.ts 44.44 0 50 42.3
/codebase/server/migrations/20260216120000_add_alias_to_router_domains.ts 66.66 100 50 66.66
/codebase/server/migrations/20260319000000_settings_proxyHeaders.ts 80 100 50 80
/codebase/server/public/interfaces.ts 0 0 0 0
/codebase/server/public/routes/appDiscovery.ts 100 100 100 100
/codebase/server/public/routes/index.ts 100 100 100 100
/codebase/server/routerDomains/interfaces/index.ts 100 100 100 100
/codebase/server/routerDomains/routes/createRouterDomains.ts 100 100 100 100
/codebase/server/routerDomains/routes/deleteRouterDomains.ts 92 100 100 92
/codebase/server/routerDomains/routes/getAllRouterDomains.ts 100 100 100 100
/codebase/server/routerDomains/routes/getRouterDomains.ts 100 100 100 100
/codebase/server/routerDomains/routes/index.ts 100 100 100 100
/codebase/server/routerDomains/routes/updateRouterDomains.ts 95.83 100 100 95.83
/codebase/server/routes/routes.ts 100 100 100 100
/codebase/server/seeds/00_cleanup.ts 81.81 0 100 81.81
/codebase/server/seeds/01_apps.ts 100 100 100 100
/codebase/server/seeds/02_templates.ts 100 100 100 100
/codebase/server/seeds/03_routerDomains.ts 100 100 100 100
/codebase/server/seeds/04_routes.ts 100 100 100 100
/codebase/server/seeds/05_route_slots.ts 100 100 100 100
/codebase/server/seeds/06_settings.ts 90.9 50 100 90.9
/codebase/server/seeds/07_rootPwd.ts 83.33 0 100 83.33
/codebase/server/settings/interfaces/cspSchema.ts 100 100 100 100
/codebase/server/settings/interfaces/index.ts 100 100 100 100
/codebase/server/settings/routes/createSetting.ts 100 100 100 100
/codebase/server/settings/routes/deleteDomainSetting.ts 100 100 100 100
/codebase/server/settings/routes/getSetting.ts 100 50 100 100
/codebase/server/settings/routes/getSettings.ts 100 82.35 100 100
/codebase/server/settings/routes/index.ts 100 100 100 100
/codebase/server/settings/routes/updateSetting.ts 100 100 100 100
/codebase/server/settings/services/SettingsService.ts 88.97 75.43 100 95.2
/codebase/server/sharedLibs/interfaces/index.ts 100 100 100 100
/codebase/server/sharedLibs/repositories/SharedLibsRepository.ts 100 100 100 100
/codebase/server/sharedLibs/routes/createSharedLib.ts 95 100 100 95
/codebase/server/sharedLibs/routes/deleteSharedLib.ts 100 100 100 100
/codebase/server/sharedLibs/routes/getSharedLib.ts 100 100 100 100
/codebase/server/sharedLibs/routes/getSharedLibs.ts 100 50 100 100
/codebase/server/sharedLibs/routes/index.ts 100 100 100 100
/codebase/server/sharedLibs/routes/updateSharedLib.ts 92.59 85.71 100 92.59
/codebase/server/sharedProps/interfaces/index.ts 100 100 100 100
/codebase/server/sharedProps/routes/createSharedProps.ts 100 100 100 100
/codebase/server/sharedProps/routes/deleteSharedProps.ts 100 100 100 100
/codebase/server/sharedProps/routes/getAllSharedProps.ts 100 100 100 100
/codebase/server/sharedProps/routes/getSharedProps.ts 100 100 100 100
/codebase/server/sharedProps/routes/index.ts 100 100 100 100
/codebase/server/sharedProps/routes/updateSharedProps.ts 100 100 100 100
/codebase/server/templates/errors.ts 100 100 100 100
/codebase/server/templates/interfaces/index.ts 0 0 0 0
/codebase/server/templates/routes/createTemplate.ts 92.85 100 100 92.85
/codebase/server/templates/routes/deleteTemplate.ts 100 100 100 100
/codebase/server/templates/routes/deleteTemplateLocalizedVersion.ts 100 66.66 100 100
/codebase/server/templates/routes/getRenderedTemplate.ts 96.55 94.73 100 96.55
/codebase/server/templates/routes/getTemplate.ts 100 100 100 100
/codebase/server/templates/routes/getTemplates.ts 100 50 100 100
/codebase/server/templates/routes/index.ts 100 100 100 100
/codebase/server/templates/routes/partialUpdateTemplate.ts 100 66.66 100 100
/codebase/server/templates/routes/updateTemplate.ts 100 80 100 100
/codebase/server/templates/routes/upsertTemplateLocalizedVersion.ts 100 66.66 100 100
/codebase/server/templates/routes/validation.ts 93.33 0 100 93.33
/codebase/server/templates/services/parseLinkHeader.ts 100 100 100 100
/codebase/server/templates/services/renderTemplate.ts 97.33 90 100 97.1
/codebase/server/templates/services/templatesRepository.ts 98.16 86.95 100 98.11
/codebase/server/templates/services/resources/Attributes.ts 100 100 100 100
/codebase/server/templates/services/resources/Resource.ts 100 100 100 100
/codebase/server/templates/services/resources/ResourceLinkParser.ts 100 100 100 100
/codebase/server/templates/services/resources/ResourcePreload.ts 100 100 100 100
/codebase/server/templates/services/resources/ResourceScript.ts 100 100 100 100
/codebase/server/templates/services/resources/ResourceStylesheet.ts 100 100 100 100
/codebase/server/templates/services/resources/buildAttributes.ts 100 100 100 100
/codebase/server/templates/services/resources/filterObject.ts 100 100 100 100
/codebase/server/util/TemplateParser.ts 100 100 100 100
/codebase/server/util/TypedMap.ts 100 100 100 100
/codebase/server/util/axiosErrorTransformer.ts 93.54 84.61 100 93.54
/codebase/server/util/axiosExponentialRetry.ts 100 100 100 100
/codebase/server/util/db.ts 100 92.3 100 100
/codebase/server/util/exhaustiveCheck.ts 50 100 0 50
/codebase/server/util/extendError.ts 100 100 100 100
/codebase/server/util/helpers.ts 97.61 94.73 100 97.5
/codebase/server/util/hmac.ts 100 100 100 100
/codebase/server/util/isTemplateValid.ts 87.5 66.66 100 87.5
/codebase/server/util/logger.ts 73.68 84.61 40 72.97
/codebase/server/util/normalizeArray.ts 83.33 75 100 83.33
/codebase/server/util/ping.ts 100 100 100 100
/codebase/server/util/pluginManager.ts 88.88 50 100 88.88
/codebase/server/util/set.ts 100 100 100 100
/codebase/server/versioning/config.ts 100 100 100 100
/codebase/server/versioning/errors.ts 100 100 100 100
/codebase/server/versioning/interfaces.ts 100 100 100 100
/codebase/server/versioning/routes/getVersions.ts 86.66 57.14 100 85.71
/codebase/server/versioning/routes/index.ts 100 100 100 100
/codebase/server/versioning/routes/revertVersion.ts 53.33 0 100 53.33
/codebase/server/versioning/services/Versioning.ts 87.61 75 100 87
/codebase/server/versioning/utils/secretSanitizer.ts 95.23 91.66 100 94.73
/codebase/typings/PaginatedResult.ts 0 0 0 0
/codebase/typings/User.ts 0 0 0 0

@m2broth
m2broth marked this pull request as ready for review August 18, 2026 15:26

@stas-nc stas-nc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two functional findings on the cache module (details in the line comments).

Comment thread ilc/server/tailor/request-fragment-cache/response-cache.ts Outdated
Comment thread ilc/server/tailor/request-fragment.ts
Comment thread ilc/server/tailor/request-fragment-cache/cached-fragment-requester.ts Outdated
Comment thread ilc/server/tailor/request-fragment-cache/storage-factory.ts Outdated
Two correctness defects on the render-deadline path, plus the log volume
this feature would have added at production traffic.

Capture slot leaked when load() never settled. The pending entry was
removed only when the capture promise settled, while the deadline was raced
from outside it, so a fragment that never finishes sending response headers
held its registry entry - and the concurrent-capture slot it occupies - for
the lifetime of the process. The deadline now lives inside the pending call,
so the existing settle-cleanup reclaims the slot; a response arriving after
the deadline is destroyed rather than buffered, since it no longer holds a
slot. Joiners now share one deadline instead of each arming its own.

Cold-miss deadline failed the render instead of falling back. The rejection
propagated out of cache.get() and was rethrown, failing the user's request
as a bare TimeoutError. It is now converted to a named 'render-deadline'
refusal (metric, HTML marker, log line, docs table), which the coordinator
already answers with a private render. Genuine transport failures still
propagate unchanged.

Log volume on the hot path. hit/stale/miss moved from info to debug; refuse
and error stay at info. `fragmentProxyHeaders` being dropped on cacheable
renders is a configuration fact that never changes for a given app, so it
now warns once per appId per process. Evictions - a permanently full cache
warns on every insert, reachable with the docs' own sizing example - report
at most one warn per minute, carrying the count evicted since the previous
line, with the first still immediate. The eviction throttle lives in the
fragment cache's storage factory, leaving EvictingCacheStorage a generic
bounded map for the registry.

Adds regression tests for slot reclamation, dropping a late response and the
private-render fallback, and corrects the observability doc, which claimed
all `[ILC Cache]` entries are emitted at info.

Known limitation: a fragment refused for a static config reason
(forward-querystring, wrapper-conf, ttl-invalid) still logs one info line
per request, because those reasons are re-evaluated per render rather than
tombstoned.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@m2broth
m2broth marked this pull request as draft August 20, 2026 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants