---
title: SAIF.NetCore.EnvironmentClient business rules
summary: Catalog of business rules enforced by this library.
status: draft
owner: Framework.NCore maintainers
last_reviewed: 2026-10-02
library: SAIF.NetCore.EnvironmentClient
reference_type: package
---

# SAIF.NetCore.EnvironmentClient business rules

This page catalogs every business rule this library enforces, identified by stable rule IDs referenced from operations, configuration, security, and API reference pages.

## BR-EC-01 The Environment API base URL must be present at construction

| Field | Value |
| --- | --- |
| **Statement** | The OS environment variable `EnvironmentApiUrl` must be set. It is the Environment API base URL. |
| **Trigger** | Client construction |
| **Enforcement** | `BaseEnvironmentClient.ServiceUrl` field initializer; `BaseEnvironmentClient.Setup` |
| **Outcome** | `MissingEnvironmentUrlVariableException` if null or empty |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Initialize environment client](operations/initialize-environment-client.md) |

---

## BR-EC-02 The track/host map must resolve to at least one track

| Field | Value |
| --- | --- |
| **Statement** | The track/host map must be retrieved and contain at least one track. Empty counts as failure. |
| **Trigger** | `Setup` |
| **Enforcement** | `BaseEnvironmentClient.GetHostsByTrack` |
| **Outcome** | `EnvironmentClientException` with the Environment API URL and accumulated error log |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Initialize environment client](operations/initialize-environment-client.md) |

---

## BR-EC-03 Track retrieval is retried with linear back-off

| Field | Value |
| --- | --- |
| **Statement** | Track retrieval is retried `EnvironmentClient:GetHostsByTrack:RetryCount` times (default 3). A sleep of `attempt × RetrySleepMs` (default 3000 ms) follows **every** failed attempt, including the final one, before the next attempt or the terminal exception — e.g. 3 + 6 + 9 = 18 s total with defaults, not just the delays between attempts. |
| **Trigger** | Failure in [BR-EC-02](#br-ec-02-the-track%2Fhost-map-must-resolve-to-at-least-one-track) |
| **Enforcement** | `BaseEnvironmentClient.GetHostsByTrackWithResilience`; `GetHostsByTrackConfig` |
| **Outcome** | Final `EnvironmentClientException` with the accumulated log; a `RetryCount ≤ 0` means no attempt is made and the exception is thrown immediately with an empty log* |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs`; `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/ClientConfigs/GetHostsByTrackConfig.cs` |
| **Operations** | [Initialize environment client](operations/initialize-environment-client.md) |

---

## BR-EC-04 A config-file host override requires AD override permission and group membership

| Field | Value |
| --- | --- |
| **Statement** | A config-file host override is considered only when `AppSettings:EnvApiDeveloperOverrideAllowed` is not false **and** the computer is a member of AD group `Developer_Machine_Users`. |
| **Trigger** | Host resolution |
| **Enforcement** | `HostResolver.IsConfigOverrideAllowed` |
| **Outcome** | `false` → skip config override |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/HostResolver.cs` |
| **Operations** | [Resolve host](operations/resolve-host.md), [Initialize environment client](operations/initialize-environment-client.md) |

---

## BR-EC-05 A non-empty ApplicationHost override sets the host and marks AppConfigOverride

| Field | Value |
| --- | --- |
| **Statement** | When the override is allowed, a non-empty `AppSettings:ApplicationHost` sets the host and marks `AppConfigOverride = true`. |
| **Trigger** | Host resolution |
| **Enforcement** | `HostResolver.TryResolveHostFromAppConfig` |
| **Outcome** | `Host` = configured value (lowercased) |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/HostResolver.cs` |
| **Operations** | [Resolve host](operations/resolve-host.md) |

---

## BR-EC-06 Otherwise the host is inferred from the content root path

| Field | Value |
| --- | --- |
| **Statement** | Otherwise the host is the first known track host that appears as an exact segment of the application content root path. |
| **Trigger** | Host resolution |
| **Enforcement** | `HostResolver.TryResolveHostFromFilePath` |
| **Outcome** | `Host` = matched path segment |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/HostResolver.cs` |
| **Operations** | [Resolve host](operations/resolve-host.md) |

---

## BR-EC-07 Otherwise the host defaults to the machine name

| Field | Value |
| --- | --- |
| **Statement** | Otherwise the host defaults to the lowercased machine name, and `DefaultedToMachineName = true`. |
| **Trigger** | Host resolution |
| **Enforcement** | `HostResolver.ResolveHost` |
| **Outcome** | `Host` = machine name |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/HostResolver.cs` |
| **Operations** | [Resolve host](operations/resolve-host.md) |

---

## BR-EC-08 The resolved host must belong to a known track

| Field | Value |
| --- | --- |
| **Statement** | The resolved host must belong to a track. The track is the (last) track whose host list contains the host. |
| **Trigger** | `Setup` |
| **Enforcement** | `BaseEnvironmentClient.ResolveEnvironmentTrack` |
| **Outcome** | `EnvironmentClientException("No environment track found for host! Host value: {ApplicationHost}")` if no track matches |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Initialize environment client](operations/initialize-environment-client.md) |

---

## BR-EC-09 A developer override file is honored only when it exists and the machine is a developer machine

| Field | Value |
| --- | --- |
| **Statement** | A developer settings override file (`AppSettings:EnvApiDeveloperSettingsOverride`) is honored only if it exists and `IsDeveloperMachine()` is true. Its entries take precedence over Environment API values for non-secure lookups. |
| **Trigger** | `Setup`; each lookup |
| **Enforcement** | `BaseEnvironmentClient.ResolveDeveloperSettingsOverride`, `TryGetDeveloperOverride`, `GetSettingFromDictionary` |
| **Outcome** | Override value returned ahead of the Environment API cache |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Initialize environment client](operations/initialize-environment-client.md), [Get setting value](operations/get-setting-value.md), [Developer override lookup](operations/developer-override-lookup.md) |

---

## BR-EC-10 Environment API requests identify the caller by host and application name

| Field | Value |
| --- | --- |
| **Statement** | Requests to the Environment API identify the caller as client `NetCore.EnvironmentClient` with the resolved `ApplicationHost` and `ApplicationName`. The pre-resolution call uses the machine name. |
| **Trigger** | `Setup` |
| **Enforcement** | `BaseEnvironmentClient.Setup` |
| **Outcome** | Header/metadata semantics belong to the `IHttpJsonClient` implementation (unknown here)** |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Initialize environment client](operations/initialize-environment-client.md) |

---

## BR-EC-11 A section-less setting request resolves in the application's track section

| Field | Value |
| --- | --- |
| **Statement** | A setting requested without a section is resolved in the application's track section (`{track}.{key}`). |
| **Trigger** | Get setting |
| **Enforcement** | `BaseEnvironmentClient.GetConfigSetting[Async]` |
| **Outcome** | Track-scoped value |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Get setting value](operations/get-setting-value.md) |

---

## BR-EC-12 Setting keys and section names are lowercased on lookup

| Field | Value |
| --- | --- |
| **Statement** | `BuildDictionaryKey` lowercases the entire composed lookup key, so a request key's casing never matters on the lookup side. However, `StoreSettingInDictionary` lowercases only the section when storing an entry — the setting-key portion is stored exactly as the Environment API returned it (`ConfigKey.Key`, unmodified). Lookups are therefore guaranteed case-insensitive for the section but not for the key: a stored key whose casing differs from the lowercased request will not match*. |
| **Trigger** | Get/has setting |
| **Enforcement** | `BaseEnvironmentClient.BuildDictionaryKey`, `GetSectionKey`, `StoreSettingInDictionary` |
| **Outcome** | Lowercased lookup key; stored keys lowercase only the section part, not the setting key* |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Get setting value](operations/get-setting-value.md), [Load section](operations/load-section.md), [Has setting](operations/has-setting.md) |

---

## BR-EC-13 Each section is loaded from the Environment API at most once per cache generation

| Field | Value |
| --- | --- |
| **Statement** | A section is recorded as **loaded** in `Sections` only after a fetch succeeds and returns one or more settings; such a successfully-loaded, nonempty section is then skipped (not re-fetched) on every subsequent `LoadSection[Async]` call until the next global refresh, i.e. at most once per cache generation. A **zero-result** response is never marked loaded — it is explicitly removed from `Sections` (self-healing), so it is retried on the very next call, not gated by the global refresh. A **thrown exception** during a per-section reload (performed by [Refresh check and cache reload](operations/refresh-check-and-cache-reload.md) for every section already in `Sections`) is not caught at that point: `Sections` is left unchanged, so a section that was already marked loaded before the refresh remains marked loaded — with no matching `Settings` entries, because `Settings` was already cleared — until the next global refresh clears and reloads it again. The root/empty section is never recorded in `Sections`, so it has no "loaded" state and is reloaded from the Environment API on every call that reaches it, even within the same cache generation. |
| **Trigger** | Get/has/section setting |
| **Enforcement** | `BaseEnvironmentClient.LoadSection[Async]`, `HandleGetConfigurationSettingsResults` |
| **Outcome** | Cached section reused |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Load section](operations/load-section.md) |

---

## BR-EC-14 Cache refresh is throttled to at most every 60 seconds

| Field | Value |
| --- | --- |
| **Statement** | The client checks the Environment API's `lastRefreshed` timestamp at most once every `TimeToWaitSeconds` (60 s). If the server timestamp is newer than the client's `LastRefreshed`, the whole cache is cleared and every known section is reloaded. An empty cache always triggers a load. |
| **Trigger** | Any lookup |
| **Enforcement** | `BaseEnvironmentClient.TestForRefreshSettings`, `CheckForUpdates`, `Setup` |
| **Outcome** | Cache refresh |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Load section](operations/load-section.md), [Refresh check and cache reload](operations/refresh-check-and-cache-reload.md), [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-15 Track-section and named-section settings use different URL shapes

| Field | Value |
| --- | --- |
| **Statement** | Track-section settings use `/v2/settings/{app}/{host}/value`. Other sections use `/v2/settings/{app}/{host}/{section}/value`. |
| **Trigger** | Load section |
| **Enforcement** | `BaseEnvironmentClient.GetEnvironmentApiUrl` |
| **Outcome** | URL selection |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Load section](operations/load-section.md) |

---

## BR-EC-16 A null, failed, or settings-less Environment API response is an error

| Field | Value |
| --- | --- |
| **Statement** | A null, failed, or settings-less Environment API response is an error. |
| **Trigger** | Load section |
| **Enforcement** | `BaseEnvironmentClient.HandleGetConfigurationSettingsResults` |
| **Outcome** | `EnvironmentClientException` (one of three messages) |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Load section](operations/load-section.md), [Refresh check and cache reload](operations/refresh-check-and-cache-reload.md) |

---

## BR-EC-17 A section with zero returned settings is retried rather than marked loaded

| Field | Value |
| --- | --- |
| **Statement** | A section for which the server returns zero settings is **not** marked as loaded, and is removed if it was previously marked, so it is retried on the next access (fix for the 2026-07-14 incident). |
| **Trigger** | Load section |
| **Enforcement** | `BaseEnvironmentClient.HandleGetConfigurationSettingsResults` |
| **Outcome** | Self-healing retry; no exception |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Load section](operations/load-section.md), [Refresh check and cache reload](operations/refresh-check-and-cache-reload.md) |

---

## BR-EC-18 A missing non-secure setting returns an empty string from string overloads

| Field | Value |
| --- | --- |
| **Statement** | A missing non-secure setting is returned as an empty string by string overloads (no error). |
| **Trigger** | Get setting (string) |
| **Enforcement** | `BaseEnvironmentClient.GetSettingValue`/`GetSettingValueAsync`, `GetSettingFromDictionary` |
| **Outcome** | `""` |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Get setting value](operations/get-setting-value.md) |

---

## BR-EC-19 A missing setting requested through a generic overload is an error

| Field | Value |
| --- | --- |
| **Statement** | A missing setting requested through a generic `<T>` overload is an error. Present values are converted with `Convert.ChangeType`. |
| **Trigger** | Get setting `<T>` |
| **Enforcement** | `ConfigSettingExtensions.ThrowExceptionIfNullOnGeneric`/`GetValue<T>` |
| **Outcome** | `EnvironmentClientException("Environment setting does not exist.  It must exist when calling the generic implementation of {methodName}.")` |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/Extensions/ConfigSettingExtensions.cs` |
| **Operations** | [Get setting value](operations/get-setting-value.md) |

---

## BR-EC-20 The base client must never return secure settings

| Field | Value |
| --- | --- |
| **Statement** | The base (non-secure) client must never return secure settings. |
| **Trigger** | Any `GetSecureSetting*` call on `BaseEnvironmentClient` |
| **Enforcement** | `BaseEnvironmentClient.RetrieveSecureSetting[Async]` |
| **Outcome** | `EnvironmentClientException("Operation not allowed! This application is restricted from retrieving secure settings.")` |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-21 SystemType overloads derive the system hash from the injected service

| Field | Value |
| --- | --- |
| **Statement** | `SystemType` overloads derive the system hash from the injected `ISystemHashService`. |
| **Trigger** | Secure get by `SystemType` |
| **Enforcement** | `BaseEnvironmentClient.GetSecureSetting(configKey, SystemType)` and `GetSecureSetting(configKey, section, SystemType)` overloads (generic `<T>`, non-generic, and their async counterparts) |
| **Outcome** | Hash computed by the `SAIF.NetCore.SystemHash` implementation via `ISystemHashService.Get` |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-22 A secure setting request is scoped by track and authorized by a system hash

| Field | Value |
| --- | --- |
| **Statement** | A secure setting is requested with the track (not the host) and an authorizing `systemHashValue`. |
| **Trigger** | Secure get |
| **Enforcement** | `SecureEnvironmentClient.GetSecureSettingUrlPart` |
| **Outcome** | URL built with a query-string hash |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureEnvironmentClient.cs` |
| **Operations** | [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-23 Secure values are cached per section/key and re-fetched only after a refresh

| Field | Value |
| --- | --- |
| **Statement** | Secure values are cached per `"{section}.{key}"` and re-fetched only when the non-secure cache's `LastRefreshed` is later than the cached fetch time. Null fetches are not cached on first fetch. |
| **Trigger** | Secure get |
| **Enforcement** | `SecureSettingCache.GetSetting`/`GetFromCache`/`FetchAndCache` (and async equivalents) |
| **Outcome** | Cached or refreshed value; cache is not partitioned by the system hash presented* |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureSettingCache.cs` |
| **Operations** | [Get secure setting](operations/get-secure-setting.md), [Secure setting cache](operations/secure-setting-cache.md) |

---

## BR-EC-24 A secure setting is fetched only if a matching non-secure key exists

| Field | Value |
| --- | --- |
| **Statement** | A secure setting is fetched only if a matching (non-secure) key exists in the same section of the settings cache. |
| **Trigger** | Secure get |
| **Enforcement** | `SecureEnvironmentClient.RetrieveSecureSetting[Async]` |
| **Outcome** | Otherwise `default(T)`, which leads to [BR-EC-26](#br-ec-26-a-secure-setting-resolving-to-null-or-the-type-default-is-an-error) |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureEnvironmentClient.cs` |
| **Operations** | [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-25 Secure fetch failures map to one of three error messages

| Field | Value |
| --- | --- |
| **Statement** | Secure fetch errors: an inner transport exception is rethrown as-is, 404 means "could not find a value", anything else means "Failed to retrieve". |
| **Trigger** | Secure get |
| **Enforcement** | `SecureEnvironmentClient.GetValueFromResult` |
| **Outcome** | Exception raised matching the failure category |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureEnvironmentClient.cs` |
| **Operations** | [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-26 A secure setting resolving to null or the type default is an error

| Field | Value |
| --- | --- |
| **Statement** | A secure setting that resolves to null or `default(T)` is an error. |
| **Trigger** | Secure get |
| **Enforcement** | `SecureEnvironmentClient.RetrieveSecureSetting[Async]` |
| **Outcome** | `EnvironmentClientException("No crypto data found for requested secure setting: {section}.{configKey}")` |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureEnvironmentClient.cs` |
| **Operations** | [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-27 Developer override file errors are silently swallowed

| Field | Value |
| --- | --- |
| **Statement** | Errors reading or parsing the developer override file are silently ignored. |
| **Trigger** | Each lookup |
| **Enforcement** | `BaseEnvironmentClient.TryGetDeveloperOverride` |
| **Outcome** | Falls through to the normal Environment API-backed value |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Developer override lookup](operations/developer-override-lookup.md) |

---

## BR-EC-28 HasSetting reports presence in the loaded cache for the given section

| Field | Value |
| --- | --- |
| **Statement** | `HasSetting` reports whether the key exists in the loaded cache for the given section (root when the section is empty). |
| **Trigger** | Has setting |
| **Enforcement** | `BaseEnvironmentClient.HasSetting`, `CheckForSetting` |
| **Outcome** | `bool` |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Has setting](operations/has-setting.md), [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-29 A developer machine is one where the config-file host override applied

| Field | Value |
| --- | --- |
| **Statement** | A "developer machine" is one where the config-file host override was applied (AD group membership + `AppSettings:ApplicationHost`). |
| **Trigger** | Developer checks |
| **Enforcement** | `BaseEnvironmentClient.IsDeveloperMachine` |
| **Outcome** | `bool` |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` |
| **Operations** | [Is developer machine](operations/is-developer-machine.md), [Initialize environment client](operations/initialize-environment-client.md), [Get secure setting](operations/get-secure-setting.md) |

---

## BR-EC-30 SecureEnvironmentClient construction requires server enablement or a developer machine

| Field | Value |
| --- | --- |
| **Statement** | `SecureEnvironmentClient` can be constructed only when configuration key `COREAPIENABLED` = `"1"` (typically env var `ASPNETCORE_COREAPIENABLED=1` through the host's prefixed env-var provider) **or** the machine is a developer machine. |
| **Trigger** | Construction of `SecureEnvironmentClient` |
| **Enforcement** | `SecureEnvironmentClient..ctor` |
| **Outcome** | `EnvironmentClientException("This server is not enabled for CORE APIs.")`; this runs **after** base `Setup()` has already made network calls |
| **Source** | `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureEnvironmentClient.cs` |
| **Operations** | [Initialize environment client](operations/initialize-environment-client.md), [Get secure setting](operations/get-secure-setting.md) |

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Security and authorization](security-authorization.md)
- [API reference](api/index.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts. Statements marked with `**` could not be confirmed; treat
> as unknown until verified.

## Sources
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureEnvironmentClient.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureSettingCache.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/HostResolver.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/ClientConfigs/GetHostsByTrackConfig.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/Extensions/ConfigSettingExtensions.cs`

---

