State Machines

Formal definitions of the SG/Send UI state machines, derived from the QA test code and verified against the live application. These are the single source of truth โ€” both the tests and this documentation are generated from the same Python classes.

Source: sg_send_qa/state_machines/ ยท Exported via python -m sg_send_qa.state_machines.export_schemas


Upload Wizard

The upload wizard walks through 6 UI steps. Two branching paths exit file-ready: single files and text skip the delivery-method step and go straight to share-mode selection.

9 states ยท 9 transitions

stateDiagram-v2 idle --> file-ready : file_selected [file_input_has_file] file-ready --> choosing-delivery : auto_advance [needs_delivery_choice] file-ready --> choosing-share : auto_advance [single_file_or_text] choosing-delivery --> choosing-share : click_next [delivery_mode_selected] choosing-share --> confirming : select_share_mode [share_card_clicked] confirming --> encrypting : click_encrypt_upload encrypting --> uploading : auto_advance [encryption_complete] uploading --> completing : auto_advance [upload_complete] completing --> complete : auto_advance [finalisation_complete]

Security Annotations

Transition Security tag
confirming โ†’ encrypting (click_encrypt_upload) plaintext_in_memory
encrypting โ†’ uploading (auto_advance) ciphertext_only
completing โ†’ complete (auto_advance) key_in_url

Download Flow

The download flow branches on whether the URL contains a hash fragment, and again on content type when auto-routing to browse/gallery/viewer.

9 states ยท 12 transitions

stateDiagram-v2 loading --> entry : no_hash [url_has_no_fragment] loading --> ready : hash_resolved [transfer_fetch_succeeded] loading --> error : hash_failed [transfer_fetch_failed] entry --> ready : submit_valid_id [transfer_id_resolved] entry --> error : submit_invalid_id [transfer_id_not_found] entry --> entry : submit_bogus [inline_error_shown] ready --> decrypting : click_decrypt ready --> browse : auto_route [content_type_is_folder] ready --> gallery : auto_route [content_type_is_multi_image] ready --> viewer : auto_route [content_type_is_single_file] decrypting --> complete : decrypt_succeeded decrypting --> error : decrypt_failed [wrong_key_or_corrupt]

Security Annotations

Transition Security tag
ready โ†’ decrypting (click_decrypt) key_in_memory
decrypting โ†’ complete (decrypt_succeeded) plaintext_in_dom

How This Works

Python classes          JSON export             QA site
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€       โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€       โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
State_Transition    โ†’   schemas/upload.json  โ†’  This page
State_Machine__*    โ†’   _data/state_machines/   (Jekyll reads _data/)
State_Machine__Utils    mermaid text embedded   Mermaid.js renders

The mermaid field in each JSON file is pre-rendered by State_Machine__Utils.to_mermaid(). The QA site reads it at build time โ€” no runtime generation needed.

Test Coverage

When the QA API is used to run workflows, each response includes transitions_observed โ€” the list of (from_state, to_state) pairs actually traversed. Aggregate these across a test run to compute coverage:

{
  "status": "pass",
  "transitions_observed": [
    {"from_state": "idle",       "to_state": "file-ready"},
    {"from_state": "file-ready", "to_state": "choosing-share"},
    {"from_state": "confirming", "to_state": "encrypting"}
  ]
}

Compare against the defined transitions to find untested paths.