---
title: Work release and status management
summary: Maintains a claim's work-release and work-status history rows under an injury-claim aggregate root, with cross-object date validation and sequence ordering.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Business.Claim.Maintenance
reference_type: package
operation_id: OP-CM-08
trigger: Caller retrieves clsWorkStatusInjuryClaim for a claim, adds or edits work-release and work-status rows, and calls Save()
---

# Work release and status management

Work release and status management is organized around an injury-claim aggregate root that carries the claim's injury date, leave-work date, and inmate-supervisor knowledge date, and owns two sibling history collections: work-release rows and work-status rows. Each child row validates its own dates against the aggregate's dates through cross-object rules, and the collections require dates to run in strictly descending sequence order. Saving from the aggregate root saves every child collection first, and only persists the claim row itself if all of them succeed.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-CM-08 |
| **Trigger** | Caller retrieves `clsWorkStatusInjuryClaim` for a claim, calls `NewWorkRelease` or `NewWorkStatus` to stage a row or edits and deletes existing rows, and calls `Save()` on the aggregate root or on a collection* |
| **Inputs** | `ClaimID` (Decimal retrieval key); per-row `WorkReleaseCode` and `WorkReleaseDate` or `WorkStatusCode` and `WorkStatusDate`; sequence numbers assigned from a database sequence rather than by the user; `UpdateNum` as the concurrency token; the acting user from the data-portal info; the aggregate's injury date and leave-work date used by cross-object rules |
| **Outputs** | Inserted, updated, and deleted rows in the claim work-release-status and claim work-status tables; refreshed audit fields; broken rules surfaced through validity aggregation; DB contention messages when an insert, update, or delete affects no rows |
| **Primary components** | `clsWorkStatusInjuryClaim` (retrieve, update, save orchestration, cross-object rule methods), `clsWorkRelease` and `clsWorkReleaseCollection`, `clsWorkStatus` and `clsWorkStatusCollection` |
| **Entry point** | `Business\SAIF.Business.Claim.Maintenance\clsWorkStatusInjuryClaim.vb` |

## Steps

1. **Retrieve the aggregate root.** `clsWorkStatusInjuryClaim.GetWorkStatusInjuryClaim(dataPortal, claimID)` calls the portal's retrieve, and `BeforeRetrieve` reads the claim row by claim identifier ([SQL-076](../sql/SQL-076.md), [CL_INJURY_CLAIM](../database-tables.md#cl_injury_claim)).
2. **Fill the root and cascade into the children.** `AfterRetrieve` maps claim identifier, occupational-disease code, injury date, inmate-supervisor knowledge date, leave-work date and time, and audit fields, then loads and registers the work-release collection, the work-status collection, and the three-day-wait collection as child objects.
3. **Load the work-release history.** The work-release collection selects its rows by claim identifier ordered by release sequence number descending ([SQL-074](../sql/SQL-074.md), [CL_CLAIM_WORK_RELEASE_STATUS](../database-tables.md#cl_claim_work_release_status)); each row is loaded and filled, given a fresh criteria, re-armed with its own and its cross-object rules, and marked old, after which the collection re-sorts descending.
4. **Load the work-status history.** The work-status collection follows the identical pattern, selecting by claim identifier ordered by status sequence number descending ([SQL-075](../sql/SQL-075.md), [CL_CLAIM_WORK_STATUS](../database-tables.md#cl_claim_work_status)).
5. **Stage a new work-release row.** `NewWorkRelease(claimID)` builds an empty release item — claim identifier set, sequence and update numbers zeroed, update date now, release code defaulted to `0`, release date cleared, rules re-armed, marked new — then immediately pulls the next value from the work-release sequence, adds the item, and re-sorts descending.
6. **Stage a new work-status row.** `NewWorkStatus(claimID)` mirrors that flow against the work-status sequence.
7. **Edit row properties.** The code and date setters compare old and new values and mark the item dirty only on an actual change; the sequence-number setter always marks dirty because the new-row helpers use it.
8. **Validate the work-release rows.** The item rules run whenever the row is dirty and not deleted:
   - If the release date is more than seven days in the future: reject as invalid.
   - If the release date is earlier than the aggregate's injury date: reject as invalid.
   - If the release date precedes the leave-work date: warn (does not block the save).
   - If the collection's dates are not in strictly descending sequence: reject as invalid.
   - If the release date is empty or the collection holds more than one row: require a real (non-default) release code.
   - If the collection holds more than one row: require a release date on every row.*
9. **Validate the work-status rows.** The status rules mirror the release rules against the work-status collection:
   - If the status date is more than seven days in the future: reject as invalid.
   - If the status date is earlier than the aggregate's injury date: reject as invalid.
   - If the status date precedes the leave-work date: reject as invalid (error severity here, unlike the release-side warning).
   - If the collection's dates are not in strictly descending sequence: reject as invalid.
   - If the status date is empty or the collection holds more than one row: require a real status code.
   - If the collection holds more than one row: require a status date on every row.*
10. **Validate the aggregate root.** The root rules require the leave-work date not to be in the future and not to precede the injury date, warn when the leave-work date is later than the current work-release date, and error when it is later than the current work-status date. The root's validity also aggregates each child collection's validity and propagates child broken rules upward, and its dirty state is the union of the children's.*
11. **Save from the aggregate root.** `Save()` applies the pending edit and then saves the work-release collection, the work-status collection, and the three-day-wait collection in sequence; only when all three succeed does the base save persist the root's own dirty fields ([SQL-102](../sql/SQL-102.md), [CL_INJURY_CLAIM](../database-tables.md#cl_injury_claim)) ([BR-CM-001](../business-rules.md#br-cm-001-optimistic-concurrency-updates-fail-if-rowsaffected-1)).
12. **Save a collection directly.** Calling save on either collection applies the pending edit and lets the base save iterate the dirty, new, and deleted items, dispatching the per-item lifecycle through the data portal.
13. **Insert a work-release row.** `BeforeInsert` sets the acting user and binds the release code, release date, claim identifier, and sequence number; the statement stamps the update date and initial update number server-side. `AfterInsert` adds an insert error carrying the DB contention message when no rows were affected ([SQL-018](../sql/SQL-018.md), [CL_CLAIM_WORK_RELEASE_STATUS](../database-tables.md#cl_claim_work_release_status)) ([BR-CM-001](../business-rules.md#br-cm-001-optimistic-concurrency-updates-fail-if-rowsaffected-1)).*
14. **Update a work-release row.** `BeforeUpdate` binds the acting user, release code, and release date plus the claim identifier, sequence number, and current update number; the statement increments the update number and filters on the prior value. `AfterUpdate` adds an update error carrying the DB contention message when no rows were affected ([SQL-100](../sql/SQL-100.md), [CL_CLAIM_WORK_RELEASE_STATUS](../database-tables.md#cl_claim_work_release_status)) ([BR-CM-001](../business-rules.md#br-cm-001-optimistic-concurrency-updates-fail-if-rowsaffected-1)).*
15. **Delete a work-release row.** `BeforeDelete` binds the claim identifier, sequence number, and update number and the statement filters on all three; `AfterDelete` adds a delete error carrying the DB contention message when no rows were affected ([SQL-119](../sql/SQL-119.md), [CL_CLAIM_WORK_RELEASE_STATUS](../database-tables.md#cl_claim_work_release_status)) ([BR-CM-001](../business-rules.md#br-cm-001-optimistic-concurrency-updates-fail-if-rowsaffected-1)).*
16. **Persist work-status rows.** The work-status item mirrors the three steps above against its own table: insert ([SQL-019](../sql/SQL-019.md), [CL_CLAIM_WORK_STATUS](../database-tables.md#cl_claim_work_status)), update with the incremented and filtered update number ([SQL-101](../sql/SQL-101.md), [CL_CLAIM_WORK_STATUS](../database-tables.md#cl_claim_work_status)), and delete filtered by claim, sequence, and update number ([SQL-120](../sql/SQL-120.md), [CL_CLAIM_WORK_STATUS](../database-tables.md#cl_claim_work_status)) ([BR-CM-001](../business-rules.md#br-cm-001-optimistic-concurrency-updates-fail-if-rowsaffected-1)).*
17. **Copy a row.** The copy path runs the base copy then clears and re-adds the item's own and cross-object rules, resets the sequence number to zero, refreshes the audit fields, and marks the copy clean, producing a detached non-dirty duplicate used to seed a placeholder row without a database round trip.
18. **Expose the current row.** The current-release and current-status properties scan the in-memory items for the highest sequence number, or synthesize an empty placeholder through the data portal when the collection is empty; the placeholder performs in-memory initialization and rule wiring only.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([GetWorkStatusInjuryClaim claimID]) --> Root[Read claim row]
	Root --> Kids[Load work release,<br>work status, and<br>three-day-wait collections]
	Kids --> Mutate{Caller action}
	Mutate -->|Add row| Seq[Create empty item;<br>pull next sequence number;<br>add and re-sort desc]
	Mutate -->|Edit or delete row| Dirty[Mark item dirty or deleted]
	Seq --> Rules
	Dirty --> Rules[Item rules: date bounds,<br>code and date required]
	Rules --> Cross[Cross-object rules compare<br>against injury date, leave work date,<br>and sibling current row]
	Cross --> Seqr[Collection rule: dates must be<br>strictly descending]
	Seqr --> Agg[Aggregate root propagates<br>child broken rules into IsValid]
	Agg --> Ok{Valid?}
	Ok -->|No| Invalid([Broken rules returned;<br>no persistence])
	Ok -->|Yes| Save[Root Save applies edit]
	Save --> C1[Save work release collection]
	C1 --> C1ok{Succeeded?}
	C1ok -->|No| Abort([Remaining child saves skipped;<br>claim row not updated])
	C1ok -->|Yes| C2[Save work status collection]
	C2 --> C2ok{Succeeded?}
	C2ok -->|No| Abort
	C2ok -->|Yes| C3[Save three-day-wait collection]
	C3 --> C3ok{Succeeded?}
	C3ok -->|No| Abort
	C3ok -->|Yes| Parent[Update claim row]
	Parent --> Rows{Rows affected?}
	Rows -->|None| Contention([DB contention error added])
	Rows -->|Yes| Done([Save succeeded])
```

## Failure and edge-case behavior

- An insert, update, or delete that affects no rows — stale update number, concurrent modification, or an already-removed row — does not throw; it surfaces as an insert, update, or delete error message carrying the DB contention text, which the caller must detect through the validity or broken-rule collections ([BR-CM-001](../business-rules.md#br-cm-001-optimistic-concurrency-updates-fail-if-rowsaffected-1)).
- The code-required and date-required rules fire only when the collection holds more than one row, so a single empty placeholder row is tolerated; once a second row exists, both code and date become mandatory on all rows.
- The future-date rules evaluate only when the item is dirty and not deleted, so clean or deleted rows are not blocked by a stale or invalid date.
- The leave-work-date comparison is a warning on the work-release side but an error on the work-status side — the same-shaped rule with different severity between sibling classes.
- The date-sequence rules treat any two non-empty dates that are not strictly descending as invalid, so exact duplicate dates across rows are rejected just like out-of-order dates.
- Statement properties that belong to the complementary class — the item versus the collection — deliberately throw an invalid-statement application exception, guarding against use of the wrong criteria object.
- The aggregate save short-circuits: if the work-release collection fails, the work-status and three-day-wait saves are skipped entirely and the claim row is never updated, so one child failure aborts the whole aggregate save without partial commits to the remaining children.*
- New rows consume a sequence number as soon as they are staged, even if the row is never saved, which can leave permanent gaps in the sequence.*
- Removing an item only takes it out of the in-memory list and deleted list; the database delete happens through dirty and deleted tracking on the next save.

## Related documentation

- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources

- `Business\SAIF.Business.Claim.Maintenance\clsWorkStatusInjuryClaim.vb`
- `Business\SAIF.Business.Claim.Maintenance\clsWorkRelease.vb`
- `Business\SAIF.Business.Claim.Maintenance\clsWorkReleaseCollection.vb`
- `Business\SAIF.Business.Claim.Maintenance\clsWorkStatus.vb`
- `Business\SAIF.Business.Claim.Maintenance\clsWorkStatusCollection.vb`
