---
title: SAIF.Application.Policy business rules
summary: Enumerated business rules with triggers, enforcement points, outcomes, and stored-procedure cross-references.
status: draft
owner: SAIF Documentation Generation
last_reviewed: 2026-07-31
library: SAIF.Application.Policy
reference_type: package
---

# SAIF.Application.Policy business rules

This page captures the business and security rules enforced by `SAIF.Application.Policy`.

## BR-101: Fixed GEN database user

| Field | Value |
| --- | --- |
| Statement | The policy portal always connects by setting `DataLayer.DBUser = "GEN"`. |
| Trigger | Manager initialization. |
| Enforcement | `PolicyAppManager.OnInitialize`. |
| Outcome | All policy-portal Oracle access uses the fixed `GEN` identity. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-102: Failed portal creation revokes context and access

| Field | Value |
| --- | --- |
| Statement | If the Oracle policy portal cannot be created, the manager marks the context not set, marks no access, and rethrows `ApplicationException("Unable to Establish Database Connection")`. |
| Trigger | `OnCreateDataLayer`. |
| Enforcement | `PolicyAppManager.OnCreateDataLayer`. |
| Outcome | Connection failure leaves the manager in a no-access state and surfaces a wrapped portal-creation error. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-103: Missing policy number returns PolicyNotEntered

| Field | Value |
| --- | --- |
| Statement | A zero policy number is reported as `PolicyNotEntered`, and authorization is not evaluated. |
| Trigger | `OnRetrieve`. |
| Enforcement | `PolicyAppManager.OnRetrieve`. |
| Outcome | Missing input is distinguished from authorization failure. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-104: Policy data is cached per policy number

| Field | Value |
| --- | --- |
| Statement | Cached `clsPolicyData` is reused only while its policy number matches the current manager policy number; otherwise it is re-retrieved. |
| Trigger | Read of `PolicyData` or call to `ReLoadPolicyData()`. |
| Enforcement | `PolicyAppManager.PolicyData`, `GetPolicyData`, and `ReLoadPolicyData`. |
| Outcome | Policy-context changes transparently reload the underlying policy data. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-105: Invalid policy returns PolicyNotFound

| Field | Value |
| --- | --- |
| Statement | An invalid retrieved policy marks the context not set and returns the `PolicyNotFound` message. |
| Trigger | `OnRetrieve` after policy-data retrieval. |
| Enforcement | `PolicyAppManager.OnRetrieve`. |
| Outcome | Invalid policy data cannot establish a usable context. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-106: Policy authorization runs only in web context

| Field | Value |
| --- | --- |
| Statement | `UserCanAccessPolicy` grants access unconditionally when `HttpContext.Current Is Nothing`; only web-request hosts delegate to the view-layer authorization check. |
| Trigger | Read of `UserCanAccessPolicy`. |
| Enforcement | `PolicyAppManager.UserCanAccessPolicy`. |
| Outcome | Non-web hosts bypass per-policy authorization entirely. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-107: Unauthorized policy keeps context set

| Field | Value |
| --- | --- |
| Statement | An unauthorized but otherwise valid policy keeps the context set while marking no access and returning `PolicyNotAuthorized`. |
| Trigger | `OnRetrieve` authorization-denied branch. |
| Enforcement | `PolicyAppManager.OnRetrieve`. |
| Outcome | Callers can distinguish denied access from missing or invalid policy context. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-108: Business Online access comes from external accounts

| Field | Value |
| --- | --- |
| Statement | Business Online access is true when at least one external account exists for the policy, and the reported logon date is the latest external logon across those accounts. |
| Trigger | First read of `HasBusinessOnlineAccess`, `LastLoginDate`, or `BOAccessText`. |
| Enforcement | `PolicyAppManager.HasBusinessOnlineAccess`. |
| Outcome | The access flag and last-logon date are derived once and cached on the manager instance. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-109: Business Online text is internal only

| Field | Value |
| --- | --- |
| Statement | Business Online text is rendered only for non-external clients, and the cutover date `1/1/2000` is treated as “Never logged on”. |
| Trigger | Read of `BOAccessText`. |
| Enforcement | `PolicyAppManager.BOAccessText`. |
| Outcome | External callers see no Business Online text, and legacy placeholder dates are suppressed. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-110: Only default header association types are candidates

| Field | Value |
| --- | --- |
| Statement | The header only considers association types whose code-table rows are flagged `IsDefaultPolicyHeaderType`. |
| Trigger | First read of `AssociationTypeTargets`. |
| Enforcement | `clsStandardPolicyHeaderSettings.AssociationTypeTargets`. |
| Outcome | Non-header association types are excluded before later filtering. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderSettings.vb` |

---

## BR-111: Test information is hidden in production

| Field | Value |
| --- | --- |
| Statement | Test information is viewable only when `AppGlobal.EnvironmentService.IsProduction` is false. |
| Trigger | Read of `IsTestInformationViewable`. |
| Enforcement | `clsStandardPolicyHeaderSettings.IsTestInformationViewable`. |
| Outcome | Production renderings suppress user-id, user-number, database-name, and database-date diagnostics. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderSettings.vb` |

---

## BR-112: Secured association types require matching resource

| Field | Value |
| --- | --- |
| Statement | A secured association type is visible only when the principal is authorized for its security-group name, using the `Ext` suffix for external users; unsecured types are visible to everyone. |
| Trigger | Validated association-type computation. |
| Enforcement | `clsPolicyHeaderSecurityManager.clsValidatedUserAssociationTypeInfo.ValidatedUserAssociationType`. |
| Outcome | Association-type visibility is resource-gated before header rows are rendered. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsPolicyHeaderSecurityManager.vb` |

---

## BR-113: Association filtering applies only to policyholders and agents

| Field | Value |
| --- | --- |
| Statement | Users who are neither policyholders nor agents receive the unfiltered association set. |
| Trigger | `FilterAssociationsByUserType`. |
| Enforcement | `clsPolicyHeaderSecurityManager.FilterAssociationsByUserType`. |
| Outcome | Ownership filtering is limited to the two external user categories that require it. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsPolicyHeaderSecurityManager.vb` |

---

## BR-114: Non-numeric user number fails closed

| Field | Value |
| --- | --- |
| Statement | A policyholder or agent whose user number cannot be converted to `Decimal` raises `ApplicationException("Unable to determine user number.")`. |
| Trigger | `FilterAssociationsByUserType` for policyholder or agent principals. |
| Enforcement | `clsPolicyHeaderSecurityManager.FilterAssociationsByUserType`. |
| Outcome | The header aborts rather than returning over-broad association data. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsPolicyHeaderSecurityManager.vb` |

---

## BR-115: Policyholders see only their parented association types

| Field | Value |
| --- | --- |
| Statement | Policyholders keep only association types for which their own policy appears as a parent row. |
| Trigger | `FilterAssociationsByUserType` policyholder branch. |
| Enforcement | `clsPolicyHeaderSecurityManager.FilterAssociationsByUserType`. |
| Outcome | Policyholders cannot browse unrelated association groups. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsPolicyHeaderSecurityManager.vb` |

---

## BR-116: Agents see only their own agent or agency associations

| Field | Value |
| --- | --- |
| Statement | Agents keep only association rows whose `AgentNumber` or `AgencySeqNum` matches their user number. |
| Trigger | `FilterAssociationsByUserType` agent branch. |
| Enforcement | `clsPolicyHeaderSecurityManager.FilterAssociationsByUserType`. |
| Outcome | Agents see only their own book within the header association set. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsPolicyHeaderSecurityManager.vb` |

---

## BR-117: Default association type is lowest sort order

| Field | Value |
| --- | --- |
| Statement | The selected default association type is the lowest-sort-order type that survives target-type and validated-type filtering; when none survive, an unknown-type null object is returned. |
| Trigger | `GetDefaultAssociationType`. |
| Enforcement | `PolicyAppManager.GetDefaultAssociationType`. |
| Outcome | The header always has a non-null association-type selection. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

---

## BR-118: Demo mode masks policyholder values

| Field | Value |
| --- | --- |
| Statement | Demo mode masks agency name, legal name, and policy name with fixed strings, except SAIF agencies retain their real agency name. |
| Trigger | Demo-mode header rendering. |
| Enforcement | `clsStandardPolicyHeaderDataProvider.AgencyName`, `LegalName`, and `PolicyName`. |
| Outcome | Demo users do not see real policyholder-identifying header values. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderDataProvider.vb` |

---

## BR-119: Coverage-bound indicator requires bound status and period

| Field | Value |
| --- | --- |
| Statement | `Coverage Bound` is appended only when the policy status is coverage-bound and the most recent policy period is also coverage-bound. |
| Trigger | Read of `StatusDescription`. |
| Enforcement | `clsStandardPolicyHeaderDataProvider.DisplayCoverageBoundIndicator` and `StatusDescription`. |
| Outcome | The indicator reflects both policy-level and period-level bound status. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderDataProvider.vb` |

---

## BR-120: Cancellation status is for SAIF employees only

| Field | Value |
| --- | --- |
| Statement | Cancellation status text is appended only for SAIF employees and only when the derived cancellation description is non-blank. |
| Trigger | Read of `StatusDescription`. |
| Enforcement | `clsStandardPolicyHeaderDataProvider.DisplayCancellationStatus`. |
| Outcome | External users never see internal cancellation-status text. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderDataProvider.vb` |

---

## BR-121: Null cancellation status becomes empty

| Field | Value |
| --- | --- |
| Statement | A `Nothing` or `DBNull` return from `SP72268_GET_CANCEL_STATUS` is normalized to an empty string. |
| Trigger | `GetCancellationStatusDescription`. |
| Enforcement | `clsStandardPolicyHeaderDataProvider.GetCancellationStatusDescription`. |
| Outcome | Null return values do not propagate into `StatusDescription`, which then applies [BR-120](business-rules.md#br-120-cancellation-status-is-for-saif-employees-only). |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderDataProvider.vb` |

---

## BR-122: Rate account comes from ER combination parent

| Field | Value |
| --- | --- |
| Statement | The rate-account number is the parent policy number of the ER-combination association, or zero when no ER combination exists. |
| Trigger | Read of `RateAccountNumber`. |
| Enforcement | `clsStandardPolicyHeaderDataProvider.RateAccountNumber`. |
| Outcome | Policies with no ER combination return `0`. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderDataProvider.vb` |

---

## BR-123: Relationship description uses parent type and policy number

| Field | Value |
| --- | --- |
| Statement | Relationship description is built from the parent association type description and parent policy number when a `PolicyRelationship` association exists. |
| Trigger | Read of `RelationshipDescription`. |
| Enforcement | `clsStandardPolicyHeaderDataProvider.RelationshipDescription`. |
| Outcome | Policies without a relationship association render an empty relationship description. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderDataProvider.vb` |

---

## BR-124: Other-states coverage emits a header message

| Field | Value |
| --- | --- |
| Statement | When the current policy period has other-states coverage, the header emits a message and appends the other-states period range only when it differs from the current policy period range. |
| Trigger | Read of `Messages`. |
| Enforcement | `clsStandardPolicyHeaderDataProvider.GetOtherStatesCoverageMessage`. |
| Outcome | The header highlights other-states coverage and only adds date detail when needed. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderDataProvider.vb` |

---

## BR-125: Help text uses the POLHD application code

| Field | Value |
| --- | --- |
| Statement | Policy-header help text is loaded from the `POLHD` help-text application and association-type help keys use the `POLHD_<code>Descr` pattern. |
| Trigger | Read of `HelpTexts` members. |
| Enforcement | `clsStandardPolicyHeaderHelpTextCollection` and `PolicyAssociationTypeExtensions.ToHelpTextKey`. |
| Outcome | Missing help-text entries collapse to empty strings and blank association entries are filtered out. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderSettings.vb` |

---

## BR-126: Agent status comes from three resource paths

| Field | Value |
| --- | --- |
| Statement | Agent status is true when the principal is authorized for `AgencyExternal`, or is a producer, or is authorized for `ARPAgencyExternal`. |
| Trigger | Read of `clsPolicySecurity.IsAgent`. |
| Enforcement | `clsPolicySecurity.IsAgent` and `IsProducer`. |
| Outcome | Producers and assigned-risk agency users are treated as agents for downstream policy behavior. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\clsPolicySecurity.vb` |

---

## BR-127: SAIF employee status comes from domain

| Field | Value |
| --- | --- |
| Statement | SAIF-employee status is determined by comparing the security principal domain to the literal `SAIF`, not by checking an authorization resource. |
| Trigger | Read of `clsPolicySecurity.IsSAIFEmployee`. |
| Enforcement | `clsPolicySecurity.IsSAIFEmployee`. |
| Outcome | Internal-versus-external classification depends on authenticated domain name. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\clsPolicySecurity.vb` |

---

## BR-128: The manager never writes

| Field | Value |
| --- | --- |
| Statement | `OnWrite` always returns `False`, and transaction start/stop only run when the portal is not already in the requested transaction state. |
| Trigger | Write attempt or transaction-boundary call. |
| Enforcement | `PolicyAppManager.OnWrite`, `Write`, `OnTransactionStart`, and `OnTransactionStop`. |
| Outcome | The application manager remains read-only and nested transaction calls are idempotent. |
| Confidence | Verified |
| Source | `Application\SAIF.Application.Policy\PolicyAppManager.vb` |

## Stored procedure business rules

Rules sourced from the Oracle function referenced by this library.

## PROC-RULE-001: Cancellation status is derived only for `PENDCA`, `CANCEL`, or `APP` policy-status groups

| Field | Value |
| --- | --- |
| Statement | Cancellation status is derived only for `PENDCA`, `CANCEL`, or `APP` policy-status groups. |
| Trigger | `POLICY_STATUS_GROUP_CODE` is `PENDCA`, `CANCEL`, or `APP`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS` executes only the matching main-program branch. |
| Outcome | All other policy-status groups return no cancellation status. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-002: Pending-cancel policies can only derive `Demanded`

| Field | Value |
| --- | --- |
| Statement | Pending-cancel policies can only derive `Demanded`. |
| Trigger | `POLICY_STATUS_GROUP_CODE` is `PENDCA`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.pending_cancel_status` runs only `look_for_demand_status`. |
| Outcome | Pending-cancel evaluation can return `Demanded` but never the cancelled-policy statuses. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.pending_cancel_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-003: Cancelled-policy derivation uses strict first-match precedence

| Field | Value |
| --- | --- |
| Statement | Cancelled-policy derivation uses strict first-match precedence. |
| Trigger | `POLICY_STATUS_GROUP_CODE` is `CANCEL`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.cancel_status` checks judgment, lien, defaulted, demanded, pending audit, pending payroll report, and closed-with-balance in order, stopping once one sets `v_cancel_status`. |
| Outcome | Earlier matches suppress later cancelled-policy statuses. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.cancel_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-004: Open judgment action yields `Judgment`

| Field | Value |
| --- | --- |
| Statement | Open judgment action yields `Judgment`. |
| Trigger | `COLLECTION_ACTION_CODE = '018'` and `CANCEL_DATE IS NULL`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.look_for_judgement` counts matching `COLLECTION_LEGAL_ACTION` rows and sets `v_cancel_status = 'Judgment'` when any exist. |
| Outcome | Judgment outranks all later cancelled-policy status checks. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.look_for_judgement` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-005: Open lien action yields `Lien`

| Field | Value |
| --- | --- |
| Statement | Open lien action yields `Lien`. |
| Trigger | `COLLECTION_ACTION_CODE IN ('016','017')` and `CANCEL_DATE IS NULL`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.look_for_lien` counts matching `COLLECTION_LEGAL_ACTION` rows and sets `v_cancel_status = 'Lien'` when any exist. |
| Outcome | Lien becomes the cancellation status when no earlier judgment match is found. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.look_for_lien` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-006: Demand response `D` yields `Defaulted`

| Field | Value |
| --- | --- |
| Statement | Demand response `D` yields `Defaulted`. |
| Trigger | A `POLICY_DEMAND` row exists with `COLLECTION_ACT_RESPONSE_CODE = 'D'`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.look_for_default_status` opens `default_csr` and sets `v_cancel_status = 'Defaulted'` when it finds a row. |
| Outcome | Cancelled policies with a defaulted demand stop at `Defaulted` unless judgment or lien already matched. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.look_for_default_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-007: Null collection response yields `Demanded`

| Field | Value |
| --- | --- |
| Statement | Null collection response yields `Demanded`. |
| Trigger | A `POLICY_DEMAND` row exists with `COLLECTION_ACT_RESPONSE_CODE IS NULL`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.look_for_demand_status` opens `demand_csr` and sets `v_cancel_status = 'Demanded'` when it finds a row. |
| Outcome | Pending-cancel policies and unmatched cancelled policies surface `Demanded` when an unanswered demand exists. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.look_for_demand_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-008: Only physical outstanding audits before cancel date yield `Pending Audit`

| Field | Value |
| --- | --- |
| Statement | Only physical outstanding audits before the latest cancel date yield `Pending Audit`. |
| Trigger | Matching audit rows are `A` or `R`, start before the latest cancel date, and use `PHYS` or `PHYSR` audit types. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.look_for_pending_audit_status` queries `POLICY_PERIOD_PAYROLL_AUDIT` joined to `AUDIT_CODE` and sets `v_cancel_status = 'Pending Audit'` when it finds a qualifying row. |
| Outcome | Non-physical or non-outstanding audits do not produce the pending-audit status. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.look_for_pending_audit_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-009: Audit or payroll periods starting on or after cancel date are ignored

| Field | Value |
| --- | --- |
| Statement | Audit or payroll periods starting on or after the latest cancel date are ignored. |
| Trigger | `AUDIT_PERIOD_START_DATE >=` the latest cancellation date. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.look_for_pending_audit_status` and `look_for_pending_pr_status` both require `audit_period_start_date <` the latest cancel date in their cursor predicates. |
| Outcome | No pending-audit or pending-payroll-report status is derived for periods with no pre-cancel coverage window. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.look_for_pending_audit_status` / `look_for_pending_pr_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-010: Non-physical outstanding payroll reports yield `Pending PR`

| Field | Value |
| --- | --- |
| Statement | Non-physical outstanding payroll reports yield `Pending PR`. |
| Trigger | Matching `POLICY_PERIOD_PAYROLL_AUDIT` rows are `A`, `I`, or `R`, start before the latest cancel date, and are not physical audits. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.look_for_pending_pr_status` queries outstanding payroll-report rows and sets `v_cancel_status = 'Pending PR'` when it finds one. |
| Outcome | Pending payroll-report status is reserved for non-physical outstanding items that survive earlier checks. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.look_for_pending_pr_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-011: Non-zero current balance yields `Closed w/Bal`

| Field | Value |
| --- | --- |
| Statement | Non-zero current balance yields `Closed w/Bal`. |
| Trigger | `NVL(POLICY.CURRENT_BALANCE, 0) <> 0`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.look_for_closed_bal_status` reads the cached policy cursor row and sets `v_cancel_status = 'Closed w/Bal'` when the balance is non-zero. |
| Outcome | Balance-based closure is used only after every earlier cancelled-policy derivation leaves the status null. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.look_for_closed_bal_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-012: Cancelled policies with no earlier match become `Closed`

| Field | Value |
| --- | --- |
| Statement | Cancelled policies with no earlier match become `Closed`. |
| Trigger | All prior cancelled-policy checks leave `v_cancel_status` null. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.cancel_status` assigns `v_cancel_status := 'Closed'` after the ordered helper calls when no earlier branch matched. |
| Outcome | Every cancelled policy exits the function with a terminal status text. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.cancel_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-013: Unowned applications become `saifQuote`

| Field | Value |
| --- | --- |
| Statement | Unowned applications become `saifQuote`. |
| Trigger | `POLICY_STATUS_GROUP_CODE = 'APP'` and `pk73102_policy.does_wcis_own_submission(in_policy_num) = 'N'`. |
| Enforcement | `SP72268_GET_CANCEL_STATUS.saifquote_status` sets `v_cancel_status = 'saifQuote'` only when WCIS does not own the submission and no prior status is present. |
| Outcome | Application policies can surface the special `saifQuote` status instead of a cancellation label. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS.saifquote_status` — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

---

## PROC-RULE-014: Unexpected PL/SQL errors raise tagged application error `-20002`

| Field | Value |
| --- | --- |
| Statement | Unexpected PL/SQL errors raise tagged application error `-20002`. |
| Trigger | The function reaches its `WHEN OTHERS` handler. |
| Enforcement | `SP72268_GET_CANCEL_STATUS` raises `RAISE_APPLICATION_ERROR(-20002, 'Error in sp72268: ' || SQLERRM)`. |
| Outcome | Callers receive a tagged Oracle application error instead of the raw exception. |
| Confidence | Verified |
| Source | `SP72268_GET_CANCEL_STATUS` exception handler — [Details](procedures/sp72268-get-cancel-status.md#business-rules) |

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

## Sources
- `Application\SAIF.Application.Policy\PolicyAppManager.vb`
- `Application\SAIF.Application.Policy\clsPolicySecurity.vb`
- `Application\SAIF.Application.Policy\PolicyHeader\clsPolicyHeaderSecurityManager.vb`
- `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderDataProvider.vb`
- `Application\SAIF.Application.Policy\PolicyHeader\clsStandardPolicyHeaderSettings.vb`

