Source-derived document; review findings and open questions with the application owner.
04 — Journeys and state machines
In this document
Purpose and scope
The current system coordinates import-notification assessment with the receipt, completion, rejection and cancellation of individual movements. Its business purpose is to record whether a proposed movement can proceed, capture evidence about what happened to a shipment, and retain assessment outcomes such as consent and financial-guarantee decisions. The source supports a model containing notification statuses, movement statuses, assessment records and financial-guarantee statuses, but it does not establish one complete, end-to-end workflow. E0013 E0093 E0143
This chapter documents observed implementation behavior, then identifies inferred or unresolved behavior. It does not treat status names or enum values alone as proof of operational transitions. In particular, notification statuses such as Submitted, InAssessment, Consented, FileClosed, UnderProhibition and InDetermination are representable by the model, but numeric ordering and complete transition policy are not evidenced. E0006
Actors and journey entry points
The observed actors are:
Provenance gap: This passage has no artifact/source citation.
- an external or internal user who captures or submits a movement;
- an internal operator who receives, completes, rejects or partially rejects a movement;
- an assessment user who records consent and financial-guarantee decisions;
- repositories, file storage and persistence services that retain the resulting records.
Provenance gap: This passage has no artifact/source citation.
The external/internal distinction is supported by separate movement creation and receipt methods. Movement.Capture(...) creates a movement with status Captured, while an internal constructor creates one with status New. External receipt requires a file identifier; internal receipt does not. This establishes different application paths, but not the exact user roles or authorization policy. E0013 E0184
A movement may enter through capture or internal creation and then proceed through submission, receipt and completion, or through rejection, partial rejection or cancellation. The system also has handlers that persist files, audits and receipts around these operations. The handlers demonstrate coordination of these activities but do not prove that all writes are transactionally atomic. E0013 E0184 E0243
Preparing diagram…
View Mermaid diagram source
stateDiagram-v2
[*] --> Captured: Capture
[*] --> New: internal creation
Captured --> Submitted
Captured --> Received
New --> Submitted
New --> Received
Submitted --> Received
Received --> Completed
Submitted --> Rejected
Received --> Rejected
Submitted --> Cancelled
Received --> Cancelled
Received --> PartiallyRejected
Submitted --> PartiallyRejected
PartiallyRejected --> Completed
Rejected --> [*]
Cancelled --> [*]
The diagram shows only transitions reported in Movement.CreateStateMachine(). Rejected and Cancelled appear terminal within that definition; whether other application or persistence code permits later activity is unresolved. E0013
Journey A: create, submit and receive a movement
Movement capture initializes the notification identifier, movement number, movement date, creator, creation timestamp, prenotification flag and Captured status. It rejects the combination of hasNoPrenotification == true and a supplied prenotification date. Internal construction instead initializes status as New. No uniqueness check for the movement number was identified in these constructors. E0013
Movement creation is subject to several domain gates. The supplied analysis of MovementFactory reports checks for movement-date validity, maximum movement count, active loads for the date, remaining shipment quantity, notification status Consented, at least one approved financial guarantee, consent-period validity and movement-number generation. This is observed as a sequence of checks in the factory; the evidence does not show whether the complete operation is protected by a transaction or database constraint. E0372
Submission changes a movement to Submitted through the state machine. The application handler SetMovementFileIdHandler stores a certificate, calls movement.Submit(fileId), and saves. The evidence therefore supports a submission path involving a file identifier and persistence, but not the full file-validation or cleanup policy. E0184
External receipt validates a non-default file ID, a date and a quantity before firing the receive trigger. The resulting MovementReceipt is created with the external file ID. Internal receipt validates date and quantity and rejects a date later than SystemTime.UtcNow.Date; its receipt does not contain a file ID. E0013
Receipt does not, on the supplied evidence, clear an existing receipt. The earlier claim that receiving clears a previous receipt is specifically unsupported by Receive(...), OnReceived(...) and OnInternallyReceived(...). E0013
REQ-JSM-001 — Movement receipt recording. When a valid external receipt is submitted, the system shall transition an eligible movement to Received and persist a receipt containing the receipt date, quantity and external file identifier. When an internal receipt is submitted, the system shall use the internal receipt path and persist the date and quantity without requiring an external file identifier. This requirement is a characterization of observed behavior and should be confirmed against the production callers and persistence mappings. E0013
CHAR-JSM-001 — External receipt candidate
Provenance gap: This passage has no artifact/source citation.
- Given a movement for which the external receipt path is available;
- When a non-default file ID, receipt date and quantity are supplied;
- Then the movement transitions through the receive trigger and a
MovementReceiptis created.
Provenance gap: This passage has no artifact/source citation.
Journey B: complete, reject, partially reject or cancel
External completion validates a non-default completion date and file ID before firing its completion trigger. The supplied code does not show the same receipt-date ordering check on this path. Internal completion checks that the completion date is not before Receipt.Date and is not in the future. The narrower, evidenced rule is therefore “internal completion cannot precede the recorded receipt”; it is not safe to document this as a universal rule for external completion. E0013
Completion creates a MovementCompletedReceipt. A separate handler can store a certificate, complete the movement, save, select Recovered for recovery notifications or Disposed for other notification types, then add an audit and save again. Because file storage occurs before all later persistence succeeds, an orphaned stored file is possible if a later operation fails; cleanup behavior is not shown. E0243
Rejection and partial rejection create corresponding rejection entities and fire their state-machine triggers. If the current status is Received, both paths set Receipt = null. PartiallyRejected can subsequently transition to Completed, creating an unresolved edge case if completion expects Receipt.Date after the receipt has been cleared. The supplied range does not show an invariant, restoration step or repository guarantee that resolves this. E0013
Cancellation is represented as a transition from Submitted or Received in the reported state machine. CancelMovementsHandler also creates captured movements for additions, saves them, cancels requested movements, adds cancellation audits, and saves again. The writes are split across multiple saves, and the evidence does not establish an ambient transaction or behavior when one requested movement ID is missing. E0243
Open question for Harten: Does production permit completion of a partially rejected movement after its receipt has been cleared? Inspected artifacts: Movement.cs::CompleteInternally, Movement.cs::PartialReject, Movement.cs::Reject, and CancelMovementsHandler.cs. Evidence that would resolve it: the concrete repository implementations, database constraints, callers for the partial-rejection completion path, and tests covering PartiallyRejected → Completed.
Provenance gap: This passage has no artifact/source citation.
REQ-JSM-002 — Completion date guard. The internal completion operation shall reject a completion date earlier than the stored receipt date and shall reject a future completion date. The external operation’s equivalent date-ordering rule remains unconfirmed and must not be stated as a current requirement without further evidence. E0013
CHAR-JSM-002 — Internal completion candidate
Provenance gap: This passage has no artifact/source citation.
- Given a received movement with a receipt date;
- When internal completion is requested with a date earlier than that receipt date;
- Then the request is rejected and no completed receipt is created.
Provenance gap: This passage has no artifact/source citation.
Journey C: assessment consent and financial guarantees
Assessment status values include New, NotificationReceived, Submitted, AwaitingPayment, AwaitingAssessment, InAssessment, ReadyToAcknowledge, DecisionRequiredBy, Consented, ConsentWithdrawn, Objected, Withdrawn, FileClosed, Resubmitted and UnderProhibition. These values establish the vocabulary of assessment outcomes and milestones, not a complete state machine. E0093
ConsentHandler calls the consent operation with the notification identifier, a DateRange(message.From, message.To), conditions and a consent date, then calls SaveChangesAsync() and returns true. The observed data change is therefore persistence of a consent period, conditions and date. The source does not establish whether consent automatically changes notification status, enables movement creation, or triggers downstream notifications. E0010
Financial guarantees have explicit statuses: AwaitingApplication, ApplicationReceived, ApplicationComplete, Approved, Refused and Released. The domain state machine additionally reports Approved → Superseded. Approval, refusal and release are separate operations; approval includes a reference, refusal includes a reason, and release has no additional decision detail in the observed handler call. E0093 E0143
Approval is more constrained than a simple status change. The approval view model checks decision-date ordering and future dates, active loads, a positive permitted-load value, blanket-bond selection, a nonblank reference, cover amount, continued-calculation amount and decimal precision. Monetary upper-limit checks are commented out, so the evidence does not support a current maximum-value rule. E0516
Where another approved guarantee exists, the observed domain logic supersedes the previous guarantee when the reference is identical, and releases it when the reference differs. The evidence does not establish whether the target guarantee can be the same object as the current approved guarantee or whether persistence enforces one approved guarantee per notification. E0143
REQ-JSM-003 — Consent record persistence. On a valid consent command, the system shall persist the notification identifier, consent start and end dates, conditions and consent date, and shall report successful completion only after the observed save operation succeeds. Whether the command also changes notification status is unresolved. E0010
REQ-JSM-004 — Financial-guarantee decision records. The system shall represent separate approval, refusal, release and supersession outcomes, including an approval reference and refusal reason where supplied by the corresponding operation. The complete downstream effects of each outcome remain unresolved. E0093 E0143
Open question for Harten: Does recording consent transition an assessment or notification status, and does it directly authorize movement creation? Inspected artifact: ConsentHandler.cs, together with MovementFactory.cs. Evidence that would resolve it: the consent domain method, status-change handler/event consumers, and an integration test covering consent followed by movement creation.
Provenance gap: This passage has no artifact/source citation.
Auditing and unresolved cross-cutting behavior
Assessment status changes record source status, destination status and user ID. Financial-guarantee status auditing records analogous information and uses DateTimeOffset.UtcNow. Movement handlers also create audit records for submission, receipt, recovery/disposal, rejection, cancellation and missing prenotification in selected paths. This supports the existence of audit writes, but not a complete audit taxonomy, retention policy or guarantee that every state transition is audited. E0010 E0184 E0243
Open question for Harten: Are all state changes persisted atomically with their audit records? Inspected artifacts: SetMovementAcceptedHandler.cs, SetMovementRejectedHandler.cs, CancelMovementsHandler.cs, ChangeImportNotificationAssessmentStatus.cs and AuditStatusChange.cs. Evidence that would resolve it: transaction configuration, unit-of-work implementation, database transaction traces or integration tests that force a failure between the business write and audit write.
Provenance gap: This passage has no artifact/source citation.
Contains public sector information licensed under the Open Government Licence v3.0. Original public repository. This independent Harten analysis was not commissioned, approved or endorsed by DEFRA or the Environment Agency.
Analysed source-archive hash is recorded; its exact upstream Git commit has not been established. The generated material does not establish complete requirements, operational security or functional equivalence.