---
title: SAIF.Framework.Core business rules
summary: Enumerated business rules with per-rule trigger, enforcement, and outcomes.
status: draft
owner: <owner>
last_reviewed: 2026-09-15
library: SAIF.Framework.Core
reference_type: package
---

# SAIF.Framework.Core business rules

This page captures the 12 business rules enforced by this library, spanning AD/machine authorization naming conventions, configuration precedence, REST security-client input validation, fax validation, and an authorization-validation side effect.

## BR-CORE-01 AD resource naming suffix

| Field | Value |
| --- | --- |
| **Statement** | An AD resource name is suffixed with `Resource` in production or `TestResource` outside production, after stripping any existing suffix. |
| **Trigger** | Every call to `SecurityGroupService.GetMembersByResource`. |
| **Enforcement** | `SecurityGroupService.GetMembersByResource` (`Services\SecurityGroupService.cs`). |
| **Outcome** | The correct environment-scoped AD group is queried instead of the raw resource name. |
| **Source** | `Services\SecurityGroupService.cs` |

---

## BR-CORE-02 Machine authorization group naming

| Field | Value |
| --- | --- |
| **Statement** | A machine-authorization group name is suffixed with (`Test`+)`Resource` only when `isResource=true`, honoring `isProductionResource`. |
| **Trigger** | `MachineSecurityService.IsAuthorized` call with `isResource=true`. |
| **Enforcement** | `MachineSecurityService.IsAuthorized` (`Core\Services\MachineSecurityService.cs`). |
| **Outcome** | Correct environment-scoped group name used for the machine membership check. |
| **Source** | `Core\Services\MachineSecurityService.cs` |

---

## BR-CORE-03 Developer machine hostname gate

| Field | Value |
| --- | --- |
| **Statement** | A machine is never classified as a developer machine unless its hostname matches the tag-number pattern `^[TV]\d+$`. |
| **Trigger** | Every `EnvironmentServiceBase.IsDeveloperMachine` read. |
| **Enforcement** | `EnvironmentServiceBase.IsDeveloperMachine` (`Services.Common\EnvironmentServiceBase.cs`). |
| **Outcome** | Short-circuits to `false` with no AD call for non-tag hostnames; only tag-numbered hosts proceed to the AD group check. |
| **Source** | `Services.Common\EnvironmentServiceBase.cs` |

---

## BR-CORE-04 Developer settings override precedence

| Field | Value |
| --- | --- |
| **Statement** | Developer machine local JSON config overrides (`DeveloperSettingsFile`) take precedence over environment-API-sourced and in-memory cached settings. |
| **Trigger** | Every `GetConfigSetting`/`GetConfigSetting<T>` call, when `IsDeveloperMachine` is true and an override file resolves. |
| **Enforcement** | `EnvironmentServiceBase.GetConfigSettingInfo` (`Services.Common\EnvironmentServiceBase.cs`). |
| **Outcome** | The first matching override entry is returned instead of the platform-sourced value. |
| **Source** | `Services.Common\EnvironmentServiceBase.cs` |

---

## BR-CORE-05 Security API username format requirement

| Field | Value |
| --- | --- |
| **Statement** | A username supplied to the Security API client must be formatted `domain\username` (exactly one `\`, both segments non-empty). |
| **Trigger** | `SecurityApiClient.GetUser(string)` / `IsAuthorized(username, role)`. |
| **Enforcement** | `SecurityApiClient.TryParseDomainUsername` (`Services\Utilities\SecurityApiClient.cs`). |
| **Outcome** | `ArgumentException` thrown when the format is invalid; request never reaches the REST API. |
| **Source** | `Services\Utilities\SecurityApiClient.cs` |

---

## BR-CORE-06 REST role name suffix normalization

| Field | Value |
| --- | --- |
| **Statement** | An authorization role name passed to `SecurityApiClient.IsAuthorized` has any trailing "resource" text replaced with the environment-configured suffix (`SecurityClient.resourcesuffix`) before the call. |
| **Trigger** | `SecurityApiClient.IsAuthorized`. |
| **Enforcement** | `SecurityApiClient.HandleResourceNaming` (`Services\Utilities\SecurityApiClient.cs`). |
| **Outcome** | The REST API receives an environment-correct role/resource name. |
| **Source** | `Services\Utilities\SecurityApiClient.cs` |

---

## BR-CORE-07 Fax file required

| Field | Value |
| --- | --- |
| **Statement** | A `FaxConfig.File` must not be empty. |
| **Trigger** | `FaxService` fax-send validation. |
| **Enforcement** | `FaxService.FaxConfigValidator` (`Services\Utilities\Documents\FaxService.cs`). |
| **Outcome** | Validation failure surfaced through `IValidationService.Validate` if violated. |
| **Source** | `Services\Utilities\Documents\FaxService.cs` |

---

## BR-CORE-08 Fax recipients required

| Field | Value |
| --- | --- |
| **Statement** | A `FaxConfig.Recipients` collection must not be empty. |
| **Trigger** | `FaxService` fax-send validation. |
| **Enforcement** | `FaxService.FaxConfigValidator` (`Services\Utilities\Documents\FaxService.cs`). |
| **Outcome** | Validation failure if violated. |
| **Source** | `Services\Utilities\Documents\FaxService.cs` |

---

## BR-CORE-09 Fax recipient fax number required

| Field | Value |
| --- | --- |
| **Statement** | Each fax recipient must have a non-empty `FaxNumber`. |
| **Trigger** | `FaxService` fax-send validation, per recipient. |
| **Enforcement** | `FaxService.FaxRecipientValidator` (`Services\Utilities\Documents\FaxService.cs`). |
| **Outcome** | Validation failure if violated. |
| **Source** | `Services\Utilities\Documents\FaxService.cs` |

---

## BR-CORE-10 Fax recipient name required

| Field | Value |
| --- | --- |
| **Statement** | Each fax recipient must have a non-empty `RecipientName`. |
| **Trigger** | `FaxService` fax-send validation, per recipient. |
| **Enforcement** | `FaxService.FaxRecipientValidator` (`Services\Utilities\Documents\FaxService.cs`). |
| **Outcome** | Validation failure if violated. |
| **Source** | `Services\Utilities\Documents\FaxService.cs` |

---

## BR-CORE-11 AuthorizationRules side-effect execution

| Field | Value |
| --- | --- |
| **Statement** | Every `IValidationService.Validate<T>(T)` call additionally executes the `"AuthorizationRules"` FluentValidation rule set on the same entity, in addition to the default rule set.* |
| **Trigger** | Any call to the single-argument `Validate<T>(T)` overload. |
| **Enforcement** | `FluentValidationService.Validate<T>(T)` (`Services\Utilities\FluentValidationService.cs`). |
| **Outcome** | The `"AuthorizationRules"` rule set always executes as a side effect, though its result is currently discarded — origin of authorization-rule enforcement for consuming validators, not fully wired. Flagged as an open question: unclear whether this is intentional warm-up/caching behavior or a latent defect where authorization-rule failures are silently ignored.* |
| **Source** | `Services\Utilities\FluentValidationService.cs` |

---

## BR-CORE-12 Security API request pre-validation

| Field | Value |
| --- | --- |
| **Statement** | A `SecurityApiClient` request whose domain/username cannot be parsed throws before any network call is made. |
| **Trigger** | `GetUser`/`IsAuthorized`. |
| **Enforcement** | `SecurityApiClient.GetUser(string, string)` (`ArgumentNullException` guard). |
| **Outcome** | Prevents malformed REST calls. |
| **Source** | `Services\Utilities\SecurityApiClient.cs` |

---

## Notes
- Mark inferred statements with `*` and unknown statements with `**`. Do not use bold inline confidence labels.
- [BR-CORE-11](#br-core-11-authorizationrules-side-effect-execution) is flagged in the analysis as an open question rather than a confirmed defect — see [Architecture](architecture.md#design-constraints).

## 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
- `Services\SecurityGroupService.cs`
- `Core\Services\MachineSecurityService.cs`
- `Services.Common\EnvironmentServiceBase.cs`
- `Services\Utilities\SecurityApiClient.cs`
- `Services\Utilities\Documents\FaxService.cs`
- `Services\Utilities\FluentValidationService.cs`
