Wayfinder / Case study / Current-system documentation

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

Source-derived diagram. Some relationships may be inferred and require review.

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 MovementReceipt is 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.

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.