BioFlow Requirements
Software Requirements Specification
  • SYS-001
    change in progress 1. First-launch readiness for local enrolment UID: SYS-001 TYPE: functional STATUS: Approved RELATIONS (Child): STATEMENT:

    When the device is opened on a workstation that has no pre-existing BioFlow data directory, a default local clinic shall be present and immediately available for the clinician to attach newly-enrolled patient records, without requiring the clinician to first create or configure a clinic record manually.

    RATIONALE:

    Stakeholder commitment: clinicians installing the device on a fresh workstation expect to enrol their first patient within minutes of starting the application, without learning a separate clinic-management workflow as a prerequisite. Auto-provisioning a default local clinic removes that friction.

    REVIEWED_HASH:

    1c8a5a84aebeb1b05f0044436dce6685870daaaade275946cde09b1b935e7fc5

    REVIEWED_BY:

    @DougYoungberg

SRS-001
change in progress 1. First-launch database initialisation UID: SRS-001 TYPE: functional STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

On first launch, when no database file exists at the configured application data path, the software shall create the local database, apply the current schema version, and create a default local clinic record that serves as the container for locally-created patient records.

RATIONALE:

Refines SYS-001: the software-level mechanism that realises the device's first-launch readiness commitment. Establishes the minimum persistent state required for any subsequent clinical operation — without it, patient records cannot be stored and recording sessions cannot be attached to a patient.

REVIEWED_HASH:

98b05f66e64fdd504ec9ab458d051d1bf7ac6ef1cc6703c83eec0bbfcfa52d83

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST-001 on clean install — fresh workstation, first launch, verify the local clinic is visible in the Patients menu.

  • ARCH-001
    change in progress 1. Local persistence subsystem UID: ARCH-001 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

    The local persistence subsystem owns the application's local database — a SQLite file encrypted at rest via SQLCipher, located under the configured AppData path — applies schema migrations via Drift on first open, and exposes a typed API to the application layer for the clinic, patient, and recording domain entities.

    RATIONALE:

    Hexagonal layer realising the broader local persistence concern. Encapsulates file lifecycle, encryption (SQLCipher), schema migration (Drift), and the typed domain-API contract — keeps the rest of the application unaware of storage details.

    REVIEWED_HASH:

    cc7fc276970b8e3d7fcf9027298cfa0095eef00c2bb6e8ae4eee52404ffa4fa2

    REVIEWED_BY:

    @DougYoungberg

  • ST-001
    change in progressSkipped 1. Local clinic visible in Patients menu UID: ST-001 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched on a workstation that has no pre-existing BioFlow data directory, navigate to the Patients menu and open the clinics dropdown. The local clinic entry shall be visible in the dropdown.

    ACCEPTANCE_CRITERIA:

    Preconditions: application is launched on a clean workstation (no prior data directory); the main screen is visible. Steps: navigate to the Patients menu; open the clinics dropdown. Verification: a VisionTrace AI agent.verify(...) call confirms the local clinic is visible in the dropdown. No error dialog appears during launch or navigation.

    REVIEWED_HASH:

    1abfb93d30805f56ec9159fab5db3477d395bc27c4bc8ac0c6b4aac3b6164005

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Launching the application on a clean workstation is a test precondition handled by the VisionTrace app_session fixture, not a step in the test body. Test code lives in this repo at visiontrace_tests/bioflow/st001/, decorated with @visiontrace_test_case("ST-001"). The agent.verify(...) call takes a screenshot of the current UI and asks an AI model to confirm the described condition — for this test, that the local clinic is present in the dropdown. Running this test in CI requires VisionTrace to be installed in the CI environment and a Windows runner with a usable desktop session. Multi-link verifies SYS-001 (operator can enrol on first launch) and SRS-001 (software creates default clinic); both close via this same end-to-end observation.

  • SYS-002
    change in progress 2. Confidentiality of patient data at rest UID: SYS-002 TYPE: regulatory STATUS: Approved RELATIONS (Child): STATEMENT:

    The device shall keep clinic, patient, clinical-user, recording, and audit-log data stored on the local workstation confidential against any party gaining access to the workstation's filesystem without the operator's BioFlow credentials.

    RATIONALE:

    BioFlow workstations are deployed in clinical environments where multiple staff and IT roles share physical access, and the local data store carries identifiable patient records. HIPAA Security Rule §164.312(a)(2)(iv) (encryption of ePHI at rest) and GDPR Art. 32(1)(a) (encryption as appropriate technical safeguard) require that filesystem-level access does not yield readable PHI on its own.

    STANDARD_REF:

    45 CFR §164.312(a)(2)(iv); GDPR Art. 32(1)(a)

    REVIEWED_HASH:

    940ecc884b9e74e53cf0626b9253a7be885b903762de73e2a7b847831533eebb

    REVIEWED_BY:

    @DougYoungberg

SRS-002
change in progress 2. Local database confidentiality at rest UID: SRS-002 TYPE: security STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall keep the local database file unreadable to any process that opens it without supplying the database credential, and shall reject database read and write operations when the credential is missing or incorrect.

RATIONALE:

Refines SYS-002. A workstation that is lost, stolen, imaged, or backed up off-site shall not yield PHI from the local database file alone. Tying readability to a credential held outside the database file ensures offline copies of the file cannot be opened independently of the BioFlow application's credential pathway.

STANDARD_REF:

NIST SP 800-111; IEC 81001-5-1 §5.5

THREAT_REF:

PHI exfiltration from a lost, stolen, or imaged Windows host

REVIEWED_HASH:

bbce0aa8a344b16781b9aa4fd86855e614b296b31d614039b4a2221e7e5bda23

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: IT-002 attempts to read the on-disk file without a credential and confirms the read does not yield plaintext records, then opens it through the application's pathway and confirms the records are readable.

  • ARCH-002
    change in progress 2. Local database encryption UID: ARCH-002 TYPE: data STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The local SQLite database is encrypted on disk via the SQLCipher extension. The encryption key is held by flutter_secure_storage, which on Windows persists it as an entry in a DPAPI-encrypted file (flutter_secure_storage.dat) under the user's local app-data directory. On application bootstrap, the key is retrieved from secure storage and generated-and-persisted on first launch if absent. On every database connection open, the database connection service applies the key as the first statement (PRAGMA key) before any other operation; SQLCipher then transparently encrypts and decrypts SQLite pages.

    RATIONALE:

    Page-level encryption via SQLCipher avoids per-record encryption logic in application code. Holding the key in flutter_secure_storage (rather than alongside the database file) ensures a copy of the database file alone cannot be opened. Bootstrap-time key generation lets the application be self-installing on a fresh workstation without a manual setup step.

    REVIEWED_HASH:

    a62962252646969da606f5d40f8fee50864ace3a43692de8b29c62a1fbeed8fb

    REVIEWED_BY:

    @DougYoungberg

  • SYS-003
    change in progress 3. Integrity of patient data at rest UID: SYS-003 TYPE: regulatory STATUS: Approved RELATIONS (Child): STATEMENT:

    The device shall preserve the integrity of clinic, patient, recording, and audit-log data stored on the local workstation against accidental alteration, partial writes, referential inconsistency, and concurrent-write corruption — such that any record returned by the device represents a complete and consistent state authored through the application.

    RATIONALE:

    BioFlow's local data store is the authoritative source for clinic and patient records on a given workstation; clinical decisions and uploads to the cloud are made against it. A record silently corrupted by a partial write after a crash, by a dangling foreign-key reference, or by a schema-violating row would mis-attribute a recording, mis-identify a patient, or strand orphan rows that mask deletion intent. HIPAA Security Rule §164.312(c)(1) (integrity) and GDPR Art. 5(1)(f) (integrity and confidentiality, including accidental loss, destruction or damage) both require the device to protect ePHI against improper alteration or destruction; the standards explicitly include accidental corruption, not only adversarial tampering. SYS-003 is the device- level commitment that the local store does not silently drift out of internal consistency.

    STANDARD_REF:

    45 CFR §164.312(c)(1); GDPR Art. 5(1)(f); GDPR Art. 32(1)(b)

    REVIEWED_HASH:

    2c29cc4c8c670d6d9fa809e35fac9e1425ad652f765332fccf15573952b5eb69

    REVIEWED_BY:

    @DougYoungberg

SRS-003
change in progress 3. Local database integrity enforcement UID: SRS-003 TYPE: data STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall enforce referential integrity between clinic, patient, and recording records through database foreign-key constraints; shall wrap any multi-row or cross-table mutation in a single transaction such that a crash or process termination during the mutation leaves the database in either the pre-mutation state or the post-mutation state and never a partial state; and shall reject — rather than silently truncate or drop — any write that would violate a NOT NULL, FOREIGN KEY, or CHECK constraint declared in the schema.

RATIONALE:

Refines SYS-003. Three independent failure modes can corrupt the local store: (1) concurrent or crashing writes that complete only part of a multi-row update; (2) referential drift where a child row outlives its parent or never had one; (3) constraint-violating inserts that older code paths or migrations may attempt. Each is addressed by a specific software mechanism — schema-declared constraints applied by the persistence layer, transactional wrappers around use-case writes, and the underlying database engine's constraint enforcement — and each is observable through a failed write or a post-condition query. The requirement names the three mechanisms together so that removing any one of them (for example, disabling foreign-key enforcement for a performance change) is a visible regression against SRS-003 rather than a silent loosening of guarantees relied on by the rest of the application.

STANDARD_REF:

45 CFR §164.312(c)(1); GDPR Art. 5(1)(f)

REVIEWED_HASH:

0de558744d983b3d37d5f67856e20552eba80bae3e3f3fb4a235b12bbb886ee3

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: IT-003 exercises each rejection category named in this requirement against the production encrypted-connection pathway: (a) FK violation — attempt to insert a patient with a non-existent clinic_id; (b) transactional atomicity — perform two writes inside a transaction, throw, and assert no partial state remains visible on re-open; (c) CHECK violation — attempt to insert a clinics row with an out-of-set origin value; (d) NOT NULL violation — issue a raw SQL INSERT (bypassing the typed API which guards NOT NULL at compile time) that supplies NULL for a non-nullable column. Test file location: test/integration/database_integrity_integration_test.dart.

  • ARCH-003
    change in progress 3. Local database integrity mechanisms UID: ARCH-003 TYPE: data STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

    The local SQLite database enforces referential integrity and write atomicity through three schema- and connection-level mechanisms. First, the Drift-declared schema carries foreign-key constraints linking patient rows to their clinic and to their assigned clinical user, and recording rows to their patient. Column-level constraints declared in Dart (NOT NULL by default, plus CHECK on enumerated text columns such as clinics.origin, patients.origin, and recordings.upload_status) cause the SQLite engine to reject schema-violating writes at insert time. Second, the database connection service enables foreign-key enforcement on every connection by issuing PRAGMA foreign_keys = ON immediately after applying the encryption key, so the schema-declared FK relations are enforced by the SQLite engine for every read and write throughout the application's lifetime. Third, application-layer use cases that perform multi-row or cross-table writes execute them inside a single Drift transaction, so a crash or process termination during the mutation leaves the database in either the pre-mutation or the post-mutation state and never a partial state. Together, these three properties of how the persistence subsystem is configured realise SRS-003.

    RATIONALE:

    Integrity could in principle be realised at the application layer through per-use-case validation, but is enforced at the schema and connection layer here so that any new use case, any data-migration script, and any future maintenance write inherits the same constraints automatically without duplicating logic. Schema-level FK constraints and SQLite's built-in enforcement engine are battle-tested mechanisms; lifting them into application code would invite duplication and gradual drift. The per-connection PRAGMA foreign_keys = ON statement is non-negotiable because SQLite's default is OFF — an omission would parse FK declarations and silently ignore them, leaving the integrity story broken at runtime. Drift transactions wrap the multi-row case at the use-case boundary because that is the smallest granularity at which atomicity is meaningfully observable to the rest of the application. Audit-log rows intentionally use a polymorphic (entity_type, entity_id) reference rather than a foreign key because audit entries cover events on clinic, patient, recording, and clinical-user subjects — an FK on entity_id could only target one table — and integrity of the audit chain is preserved instead by making audit_id the immutable primary key with the row content fixed at insert time.

    REVIEWED_HASH:

    1fb8538abde3bc3860262ab683243fae4ce27045bcc31dc75e427bd65c79a4d2

    REVIEWED_BY:

    @DougYoungberg

  • SYS-004
    change in progress 4. Audit trail of clinical record operations UID: SYS-004 TYPE: functional STATUS: Approved RELATIONS (Child): STATEMENT:

    The device shall maintain an audit trail that independently records every operation that creates, modifies, or deletes a clinical record on the local workstation, and every action that exports such a record to an external system. Each entry shall capture the action, the affected record, and a system-generated UTC timestamp. Audit entries shall not be modified in a way that obscures previously recorded information after they are written.

    RATIONALE:

    An audit trail of clinical-record operations is a stakeholder-level commitment of the device. It supports the clinical organisation's internal review duties (knowing what happened to which clinical record, and when) and the integrity of the local clinical data store (so that accidental or unauthorised modifications can be reconstructed and investigated after the fact). The record-modification clause is included because an entry whose content can be silently overwritten after the fact ceases to be a useful record of what happened.

    REVIEWED_HASH:

    f4ff59b59ede96ba3085b89a1e864d2debc3215cb3b0042298a5801c5207b53a

    REVIEWED_BY:

    @DougYoungberg

SRS-004
change in progress 4. Audit logging of clinical record operations UID: SRS-004 TYPE: functional STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall write one audit-log entry for each of the following operations on local clinical records: creation, modification, and deletion of a patient; start, stop, and deletion of a recording; and successful upload of a recording to the cloud. Each entry shall carry the action, the identifier of the affected record, and a system-generated UTC timestamp. After an entry is written, the software shall not modify it in a way that obscures previously recorded information, and shall not delete audit entries.

RATIONALE:

Refines SYS-004. The list of audited operations corresponds to the operator-initiated mutations and exports of patient or recording data that the application currently exposes. Clinic and clinical-user mutations are not in scope because the application does not permit those operations on the local workstation — clinics are read-only mirrors of an external cloud directory the device is configured to sync with; clinical users are authenticated rather than created in-app. The required content per entry (action, target, time) is the minimum that lets an audit reviewer reconstruct what happened: which clinical record was affected, what action was performed, and when. The immutability clause expresses the underlying invariant that an audit entry must remain a faithful record of the operation it describes; an application-layer path that overwrites the details of a prior entry would functionally be a record change that obscures original information, and is therefore prohibited.

REVIEWED_HASH:

8670efd17561286bd5396fe9d81ff480539400a00719b06c3f4619af3242feb4

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: IT-004 exercises the audit chain end-to-end by invoking each of the audited operations through the application's use-case pathway (or the corresponding production caller when no use case exists) and asserting that the audit-log entry is written with the correct action, target identifier, and system-generated timestamp. IT-005 verifies the data-shape and immutability commitments — entries have the required fields and an existing entry's content cannot be changed after write.

  • ARCH-004
    change in progress 4. Audit-logging subsystem UID: ARCH-004 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

    The audit-logging subsystem realises SRS-004 through three software items in the hexagonal architecture. A domain-layer audit-repository port whose surface offers create and read operations only — no update or delete is exposed to the application. A service in the application/infrastructure boundary that exposes one semantic logging method per audited operation (logPatientCreated, logPatientUpdated, logPatientDeleted, logRecordingStarted, logRecordingStopped, logRecordingDeleted, logRecordingUploaded). A Drift-backed adapter that persists entries into the audit_logs table of the local persistence subsystem (ARCH-001). Application- layer use cases invoke the service after the corresponding record mutation; the service composes an entry (action, entity type, entity identifier, actor identifier when available, JSON details, and timestamp) and delegates persistence to the port.

    RATIONALE:

    Routing every audit call through one semantic service keeps the audit concern decoupled from each use case: the use case calls "a patient was created" without assembling the entry itself. Limiting the port surface to create-and-read is what enforces the SRS-004 immutability clause at the architectural level — no application-layer code can mutate or delete an entry because no such method is exposed by the port. Composing entries inside the service rather than inside each use case prevents drift in the shape of entries across operations. The persistence handoff to ARCH-001 means audit entries inherit the same encryption-at-rest (ARCH-002) and integrity (ARCH-003) properties as the rest of the local store.

    REVIEWED_HASH:

    d5dbb469c6940e7b5d709b6f836a7b6c4096c44582959560c23d9c103c47bc67

    REVIEWED_BY:

    @DougYoungberg

  • ARCH-005
    change in progress 5. Audit-log record shape and immutability UID: ARCH-005 TYPE: data STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

    The audit_logs table in the local SQLite database stores one row per audit entry. Each row carries an audit identifier (UUID, primary key, immutable), an action string drawn from the application's enumerated set of audited operations, an entity_type and entity_id polymorphic reference to the subject record, a nullable user_id for the authenticated actor, a JSON-serialised details payload, and a UTC timestamp defaulted at the database level. No production code path issues UPDATE or DELETE against the table; the audit-repository port surface (ARCH-004) does not expose those operations.

    RATIONALE:

    Polymorphic (entity_type, entity_id) is used in place of a foreign key because audit entries cover events on multiple subject tables (patient, recording, system bootstrap, future clinical_user) — an FK on entity_id could only target one. Integrity instead rests on the immutable primary key being chosen at insert time and the database-side default for timestamp preventing application code from back-dating entries. The JSON details payload allows operation-specific context (e.g., the changed-field list on a patient update, the file size and target clinic on an upload) without inflating the schema with per-operation columns; the trade-off is that detail content is not directly indexable and is intended for human-readable reconstruction of what happened rather than for analytical queries.

    REVIEWED_HASH:

    b4f2ae7558b9c98456db381d46324adf474c77c5b2e4eddd9e825e783339b427

    REVIEWED_BY:

    @DougYoungberg

  • ST-003
    change in progressSkipped 3. Audit trail captures every operator-initiated clinical record operation UID: ST-003 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the operator shall perform each audited clinical-record operation through the UI — patient creation, patient update, recording start, recording stop, recording deletion, and patient deletion — and the audit trail surfaced in the Audit Log tab shall contain one entry per operation, naming the affected patient or recording. Recording is exercised against the device's playback signal source so the test does not depend on a live amplifier.

    ACCEPTANCE_CRITERIA:

    Preconditions: application is launched; the main screen is visible; the playback signal source is available. Steps: create a patient with a known first/last name; edit a field on that patient and save; start playback; start a recording; stop the recording; delete the recording from the recent recordings list; delete the patient; open the Activities overlay and select the Audit Log tab. Verification: a VisionTrace agent.verify(...) call confirms the Audit Log tab lists six entries for the test patient and recording in newest-first order — one whose title indicates a patient creation, one a patient update, one a recording start, one a recording completion, one a recording deletion, and one a patient deletion — each carrying a system timestamp. No error dialog appears during any step.

    REVIEWED_HASH:

    f1b89562a9ab7e5eb067776f5ed4112f487dbe33a551b39139ac9dccbd6c2dd8

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Coverage: ST-003 verifies the SRS-004 commitment at the operator- facing altitude — every audited operation an operator can perform through BioFlow's UI produces an audit entry the operator can see. IT-004 verifies the same SRS-004 commitment exhaustively at the integration tier by invoking each operation through its production use-case pathway; ST-003 demonstrates the same commitment at the UX surface using one representative patient and one representative recording. The two are complementary: IT-004 would still pass if a UI control failed to invoke its use case (a regression ST-003 catches); ST-003 would still pass if the audit-write inside the use case were silently dropped (a regression IT-004 catches).

    Out of scope for ST-003: recording upload. The audit-write half of that operation is exhaustively verified at the integration tier by IT-004 (g) (production UploadManager path against a real audit service), and the operator-facing visibility half is already verified by ST-002 (the Audit Log tab surfaces every entry regardless of which use case produced it). Adding upload here would add cloud-credential and network dependencies without adding new compliance evidence.

    Out of scope for ST-003: review and export of the trail. ST-002 covers the operator-facing review and export commitments (SRS-005).

    Test code lives in this repo at visiontrace_tests/bioflow/st003/, decorated with @visiontrace_test_case("ST-003"). The recording-lifecycle steps depend on the playback signal source being available on the test workstation.

  • SYS-004
    change in progress 4. Audit trail of clinical record operations UID: SYS-004 TYPE: functional STATUS: Approved RELATIONS (Child): STATEMENT:

    The device shall maintain an audit trail that independently records every operation that creates, modifies, or deletes a clinical record on the local workstation, and every action that exports such a record to an external system. Each entry shall capture the action, the affected record, and a system-generated UTC timestamp. Audit entries shall not be modified in a way that obscures previously recorded information after they are written.

    RATIONALE:

    An audit trail of clinical-record operations is a stakeholder-level commitment of the device. It supports the clinical organisation's internal review duties (knowing what happened to which clinical record, and when) and the integrity of the local clinical data store (so that accidental or unauthorised modifications can be reconstructed and investigated after the fact). The record-modification clause is included because an entry whose content can be silently overwritten after the fact ceases to be a useful record of what happened.

    REVIEWED_HASH:

    f4ff59b59ede96ba3085b89a1e864d2debc3215cb3b0042298a5801c5207b53a

    REVIEWED_BY:

    @DougYoungberg

SRS-005
change in progress 5. Audit-trail review and export UID: SRS-005 TYPE: functional STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall present the local audit trail to an authorised operator in a form that lists each entry's action, affected record, and system timestamp, ordered by time. The software shall additionally provide a means to export the current audit trail to a file in a portable, human-readable format that preserves the same fields as the on-screen presentation, so that the exported file can be examined off the device by an auditor or by the clinical organisation's own information-security review.

RATIONALE:

Refines SYS-004. Capturing audit entries in the local database is necessary but not sufficient: the entries live inside the encrypted application database, which an internal reviewer or external auditor is not expected to access directly. The device therefore surfaces the trail to an authorised operator inside the application and provides an exportable copy that can be examined off the device. Without a viewer-and-export surface, the audit trail is opaque to the clinical organisation's own review duties — the entries exist but cannot be examined without direct access to the encrypted database file. The "human-readable" wording is deliberate: a binary or schema-coupled export defeats the off-device review use case, which is conducted by people reading entries on a workstation other than the device. The "ordered by time" presentation rule keeps the on-screen view faithful to the chronology of operations; the export preserves the same fields so that the exported copy is a copy of the on-screen trail rather than a transformation of it.

REVIEWED_HASH:

3da5c78892fc7f563c2fd96cb6b7e93ad305672d437b12b2a59dd039044ad207

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: IT-006 verifies the export round-trip — written audit entries appear in the exported file with the same fields and content. ST-002 (planned, to be authored once the viewer surface ships) verifies an operator can locate the audit trail in the application, see the expected entries, and invoke the export from the workstation.

  • ARCH-006
    change in progress 6. Audit-trail review-and-export presentation surface UID: ARCH-006 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

    The audit-trail review-and-export surface realises SRS-005 by extending the Activities overlay (lib/presentation/overlays/activities_overlay.dart) with a tab titled "Audit Log". The pre-existing first tab is renamed from "Recent Activities" to "Recent Recordings" so that its name matches what it actually lists (rows from the recordings table) and does not collide with the new audit-trail tab. The resulting tab set, in order, is: Recent Recordings, Audit Log, Statistics, Archive. The Audit Log tab subscribes to the auditLogListProvider exposed by the application/providers layer, which streams the audit_logs rows from the local persistence subsystem (ARCH-001) via the audit-repository read side (ARCH-004). Entries are rendered as a scrollable list ordered by timestamp descending, each row showing the action, the entity_type/entity_id pair, and the UTC timestamp. The tab carries an Export button whose on-press handler serialises the currently-loaded entries to a file in one of two portable, human-readable formats — CSV (one row per entry, fields: audit_id, timestamp, action, entity_type, entity_id, user_id, details) or JSON (an array of entry objects with the same fields) — and writes the file to a workstation path chosen by the operator through the platform's standard save-file dialog.

    RATIONALE:

    The audit-trail viewer is placed in the existing Activities overlay because that overlay already groups operator-visible event surfaces (recent activities, statistics, archive) and audit-log review is a peer concern — adding a parallel tab there preserves the operator's mental model rather than introducing a separate menu entry. The auditLogListProvider is already exposed by the application layer for unrelated reasons, so the viewer attaches to existing wiring rather than introducing a new data path; the read side of the audit-repository port (ARCH-004) is already permitted by the SRS-004 immutability rule (the port surface offers create and read only — no mutating method exists for the viewer to invoke). CSV and JSON are both portable, human-readable, and parseable without specialised tooling on a clinical workstation; the export deliberately writes the same fields shown on screen so the exported file is a faithful copy of what the operator reviewed — a transformation rather than a copy would defeat the off-device review use case. The save-file dialog is the platform-native path because it lets the operator choose a destination outside the application's working directory (typically a clinical share or removable media), which is the realistic workflow for handing the file to an auditor.

    REVIEWED_HASH:

    5ba229d3b36ffd3ddc7705b5933bb742e3f639fa7fc16d4ad6c759c865b1ab15

    REVIEWED_BY:

    @DougYoungberg

  • ST-002
    change in progressSkipped 2. Operator can review and export the local audit trail UID: ST-002 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the operator shall be able to perform an audited clinical operation, locate the resulting entry in the on-screen audit-trail review surface, and export the audit trail to a workstation-side file from the same surface. The operator performs a patient creation and a patient deletion (representative audited clinical operations), then opens the Activities overlay and selects the Audit Log tab. The audit entries corresponding to the two operations shall be visible there. The operator then invokes Export CSV, completes the platform save-file dialog, and the application shall confirm a successful export.

    ACCEPTANCE_CRITERIA:

    Preconditions: application is launched; the main screen is visible. Steps: create a patient with a known first/last name through the patient-management surface; delete that same patient through the same surface; open the Activities overlay; select the Audit Log tab; invoke Export CSV; complete the save-file dialog with a workstation-side path. Verification: a VisionTrace agent.verify(...) call confirms that the Audit Log tab lists at least one entry for the patient creation and one entry for the patient deletion, each naming the patient and showing a system timestamp; a second verify(...) call confirms that after the save-file dialog completes the application surfaces a success indication (success snackbar or toast) reporting that the audit log has been exported. No error dialog appears during any step.

    REVIEWED_HASH:

    6af8b30c75fbc477db2f17b298fc62512d592e088d96999e86ae00fba8c4705b

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Coverage: ST-002 verifies the SRS-005 / ARCH-006 commitment at the operator-facing altitude — that the audit trail is reviewable and exportable through the application's UI, not only via the underlying repository. IT-006 verifies that the exported file is a faithful copy of the trail at the file-content level; ST-002 verifies that an operator can reach that file through the UI flow. The two are complementary: IT-006 would still pass if the Export buttons were never wired up (a non-conformance ST-002 catches), and ST-002 would still pass if the exported file were silently corrupted (a non-conformance IT-006 catches).

    Out of scope for ST-002: recording lifecycle (start/stop/upload/ delete). These are verified end-to-end at the integration tier by IT-004 and need not be re-verified here. Patient CRUD is sufficient to demonstrate the operator-facing review-and-export path.

    Test code lives in this repo at visiontrace_tests/bioflow/st002/, decorated with @visiontrace_test_case("ST-002"). The save-file dialog is the platform-native Windows dialog driven by the file_picker package; the recording must capture typing a known temp path and clicking Save so the file is actually written and the success snackbar appears.

SRS-006
reviewed 6. Maximized main window on launch UID: SRS-006 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

On application launch, the software shall display the main application window in a maximized state.

RATIONALE:

Refines SYS-005. Maximising the main window on launch gives the EEG signal display the full available screen area from the start of a session, so the operator can monitor the live signal without first resizing the window manually.

REVIEWED_HASH:

dc7ca8a24c6e21afa7a978cbb02263cfeab63085a843e6e7432c25b610be934a

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST item (planned) — verify the main application window is maximized immediately after launch.

  • ARCH-007
    reviewed 7. Application window launch and state subsystem UID: ARCH-007 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (File): STATEMENT:

    The application's top-level desktop window is shown maximised at launch by the native Windows runner: Win32Window::Show() (windows/runner/win32_window.cpp) calls ShowWindow with SW_SHOWMAXIMIZED, invoked from flutter_window.cpp during startup. The Dart application bootstrap additionally calls windowManager.maximize() after the window_manager package initialises, reinforcing the maximised state once the Flutter engine is running. Runtime window state — size, position, and maximised flag — is owned by the WindowStateNotifier (application layer), which applies changes through the window_manager package and persists them to SharedPreferences for restoration on the next launch. The window's minimum size is configured as 1024x768 through the window_manager package's WindowOptions in main.dart, which the package enforces against resize requests so the window cannot be made smaller than that floor.

    RATIONALE:

    Launching maximised is set at the native window layer so the window is already maximised the instant it first paints, before the Flutter engine and Dart layer are ready to act; the Dart bootstrap maximise call then keeps the state correct once window_manager owns the window. Window-state persistence is kept in the application-layer notifier so size and position survive across sessions independently of the launch behaviour.

    REVIEWED_HASH:

    59e14f00ae2b25d6492e269b9ff3fe6debc9ec0a0f261bd3eba952eb582fe3fa

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    coverage-plan: verified at system level by ST-004, which observes the maximised window in the running application. No flutter_test integration test is feasible for the launch maximise itself: it is performed by the native Win32 runner and by the window_manager package singleton at bootstrap, neither of which is injectable in a widget test. The minimum window size is verified the same way — at system level by ST-012 (planned), which resizes the window below the minimum and asserts the bounds are clamped — since it too is enforced by the window_manager singleton rather than in a widget tree.

  • ST-004
    reviewedSkipped 4. Main window maximised on launch UID: ST-004 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched on the workstation, the main application window shall be displayed maximised, filling the available screen work area, with the EEG signal area occupying the main region.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible. Steps: observe the main window immediately after launch. Verification: a VisionTrace agent.verify(...) call confirms the application window is maximised — it fills the screen work area and the signal display occupies the main region rather than appearing in a small or floating window. No error dialog appears during launch.

    REVIEWED_HASH:

    35a6ff9d436d21c3d6f8cf83ad53a40df20ebd21b1762fba472114b03b64d688

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st004/, decorated with @visiontrace_test_case("ST-004"). Launching the application is a precondition handled by the VisionTrace app_session fixture, not a test step. Verifies SRS-006 at the operator-facing altitude; the launch-maximise mechanism it exercises is described by ARCH-007, which carries no flutter_test integration test because that path (native runner plus window_manager singleton) is not injectable.

SRS-007
reviewed 7. Always-visible recording control widget UID: SRS-007 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall display a recording control widget anchored to the top of the main window, and shall keep that widget visible in all interaction states, including signal-control mode, menu mode, and while any overlay is open.

RATIONALE:

Refines SYS-005. The recording controls govern the active session — its start, its stop, and its running status. Keeping the widget visible in every interaction state ensures the operator can always see and reach the recording controls without first dismissing a menu or overlay.

REVIEWED_HASH:

bccb9886c2528cb600bccee06daef365798ce97ad2887816160909f6270bd10f

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST item (planned) — verify the recording control widget remains visible in signal-control mode, menu mode, and while an overlay is open.

  • ARCH-008
    reviewed 8. Recording control widget UID: ARCH-008 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The recording control widget occupies the fixed top region of the main window. It is a provider-bound presentation container (RecordingWidget) that subscribes to the recording, selected-patient, and signal-engine application providers and renders, through its view (RecordingWidgetView) and the recording sub-components (status badge, action buttons, center content, and menu panel), the recording controls, the current patient name and recording status, and the elapsed-recording-time readout. It dispatches operator actions — start and stop recording — to the recording view-model and holds no recording domain logic itself. The recorded duration shown in that readout is derived from the native recording engine's sample-accurate timing, pushed into the recording view-model as signal is captured rather than from a wall-clock timer, and is formatted as zero-padded HH:MM:SS by the recording widget state (RecordingWidgetState.formattedElapsedTime).

    RATIONALE:

    Keeping the recording widget as a thin provider-bound container, with rendering delegated to a separate view and sub-components, decouples the always-visible top region from recording domain logic. The widget is driven entirely by provider state, so its presentation can be exercised by pumping it with seeded provider values independently of how a recording is actually performed.

    REVIEWED_HASH:

    535519a4d087d4a5931deb257e7c48e7266ea4f7b96de89810a49f41b5c2685c

    REVIEWED_BY:

    @DougYoungberg

  • ST-005
    reviewedSkipped 5. Recording widget visible across states UID: ST-005 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the recording control widget at the top of the main window shall remain visible as the operator moves between interaction states: in the default signal mode, after switching the bottom bar to menu mode, and while a navigation overlay is open.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible. Steps: observe the top of the main window in the default signal mode; activate the bottom-bar toggle to enter menu mode (which opens a navigation overlay); observe the top of the window again. Verification: a VisionTrace agent.verify(...) call confirms the recording control widget is visible at the top of the window in signal mode, and a second agent.verify(...) call confirms it is still visible at the top once the bar is in menu mode with the navigation overlay open. No error dialog appears during any step.

    REVIEWED_HASH:

    50ee55956b278d705943373e174457601218236c278edf1241a5dcca3f424a5d

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st005/, decorated with @visiontrace_test_case("ST-005"). Verifies SRS-007 at the operator-facing altitude (the always-visible commitment across UI states); IT-008 verifies the recording widget's rendering at the integration tier (ARCH-008).

SRS-008
reviewed 8. Bottom-bar signal and menu mode toggle UID: SRS-008 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall provide a bottom bar that switches between a signal-control mode and a menu mode when the operator activates the bottom-bar mode toggle.

RATIONALE:

Refines SYS-005. A single bottom bar that switches between signal-control functions and menu functions keeps both sets of controls reachable from one fixed location, without permanently consuming screen area that would otherwise reduce the live signal display.

REVIEWED_HASH:

a2bd1b9f841162a89db68d43b7a5e544d65872f6e094573158396d0f6e6f4943

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST item (planned) — verify activating the bottom-bar toggle switches the bar between signal-control mode and menu mode.

  • ARCH-009
    reviewed 9. Bottom-bar mode controller UID: ARCH-009 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The bottom-bar mode controller owns the bottom bar's signal/menu mode. The mode is modelled as a domain value object (BottomBarMode) carrying the two modes and the pure toggle and per-mode content definitions; an application view-model (BottomBarNotifier) holds the current mode — signal mode at launch — and switches it via toggleMode(). The bottom bar widget (BottomBar) watches the mode provider and renders the controls for the current mode: the signal-parameter controls (high-pass, low-pass and notch filters, sensitivity, timebase, and montage) in signal mode, and the Patients/Montages/Settings/Activities navigation buttons in menu mode. A single toggle control invokes toggleMode() when the operator activates it; switching to menu mode opens the corresponding navigation overlay (the last-opened one, or Patients by default) and switching back to signal mode closes it. Dismissing the open overlay — by Escape, a click outside it, or re-selecting the active navigation item — clears the navigation selection, which resets the controller to signal mode.

    RATIONALE:

    Modelling the mode and its toggle as a pure domain value object, with the view-model holding only the current-mode state, keeps the mode-switch rule free of presentation and platform concerns so it can be verified at unit level, while the widget stays a thin renderer of whichever mode is current.

    REVIEWED_HASH:

    ea1afa48d51bd8a9eb5e14ecb9ebf753683c392a6412f641e1257291efd544ac

    REVIEWED_BY:

    @DougYoungberg

  • ST-006
    reviewedSkipped 6. Bottom bar toggles signal and menu modes UID: ST-006 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the bottom bar shall begin in signal mode showing the signal-parameter controls; activating the bottom-bar toggle shall switch it to menu mode showing the Patients, Montages, Settings, and Activities navigation items; activating the toggle again shall return it to signal mode.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible with the bottom bar in its default signal mode. Steps: observe the bottom bar; activate the centre toggle control; observe the bottom bar; activate the centre toggle control again; observe the bottom bar. Verification: a VisionTrace agent.verify(...) call confirms the bottom bar shows signal-parameter controls initially; a second confirms it shows the Patients/Montages/Settings/Activities navigation items after the first toggle; a third confirms it has returned to the signal-parameter controls after the second toggle. No error dialog appears during any step.

    REVIEWED_HASH:

    4efc230698735603fb7956284db0f435b55ca922edf621eed359c7faa6d6236b

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st006/, decorated with @visiontrace_test_case("ST-006"). Verifies SRS-008 at the operator-facing altitude; IT-009 verifies the widget-to-view-model mode switching at the lower tier.

SRS-009
reviewed 9. Dismiss overlay on ESC or click-outside UID: SRS-009 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall dismiss the active navigation overlay when the operator either presses the ESC key or clicks outside the overlay's content area.

RATIONALE:

Refines SYS-005. Navigation overlays float above the live EEG signal; providing the conventional dismissal gestures — ESC and click-away — lets the operator return to the unobstructed signal view quickly. An overlay with in-progress edits is guarded against accidental dismissal (see ARCH-010), so the dismissal applies to overlays that permit it.

REVIEWED_HASH:

b262c063b65c057df8f8d5f2d6aaaa0541cee3f7eb9887b695ffdbca7577e649

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST-007 opens a navigation overlay and verifies it is dismissed both by pressing ESC and by clicking outside the overlay content.

  • ARCH-010
    reviewed 10. Overlay navigation subsystem UID: ARCH-010 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The overlay navigation subsystem manages the application's modal navigation overlays (Patients, Montages, Settings, Activities). The open-overlay state is held as a single selected index in the navigation view-model (NavigationNotifier), which drives which overlay the main page renders. A companion overlay view-model (OverlayNotifier) tracks overlay visibility, the dismissible flag, and per-overlay data. Because the rendered overlay is keyed off one index rather than a stack, at most one overlay is shown at a time and selecting another replaces it: MainPage renders the selected overlay in a single AnimatedSwitcher slot above a dimmed signal area, with the recording widget and bottom bar layered above it. Dismissal is wired two ways: a KeyboardListener closes the active overlay on the ESC key, and a full-screen barrier behind the overlay closes it when the operator taps outside the overlay content. Both paths call clearSelection(), which is gated by a dismissible flag (overlayDismissibleProvider) so an overlay with in-progress edits (the montage editor) intercepts the close attempt instead of discarding unsaved work.

    RATIONALE:

    Modelling the open overlay as one selected index — rather than a navigation stack — is what structurally enforces the single-overlay rule (SRS-010): there is no representation in which two overlays are open. Concentrating dismissal in clearSelection(), invoked by both the ESC handler and the tap-outside barrier, keeps the two dismissal triggers (SRS-009) behaviourally identical and routed through one place, and the dismissible gate keeps that single path safe for edit-bearing overlays.

    REVIEWED_HASH:

    d9ef3a3e1718ca469e67bab37fc0eedccbbf3fc9aea11b6ff4cce247fa7b3908

    REVIEWED_BY:

    @DougYoungberg

  • ST-007
    reviewedSkipped 7. Overlay dismissed by ESC and click-outside UID: ST-007 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the operator shall open a navigation overlay and dismiss it by pressing ESC, then open it again and dismiss it by clicking outside the overlay content; in each case the overlay closes and the underlying main view is shown again (the signal area may show the "Signal display inactive" placeholder when no signal is streaming).

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible. Steps: open a navigation overlay (switch the bottom bar to menu mode so the Patients overlay opens); press ESC; observe; open the overlay again; click an empty area outside the overlay panel; observe. Verification: a VisionTrace agent.verify(...) call confirms the overlay is no longer shown after the ESC press, and a second agent.verify(...) call confirms the overlay is no longer shown after clicking outside it. No error dialog appears during any step.

    REVIEWED_HASH:

    72067e7cf69fea627570fb8ea7644f0a7da979ee6c76f1427d850f41c272186c

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st007/, decorated with @visiontrace_test_case("ST-007"). Verifies SRS-009 at the operator-facing altitude; IT-010 verifies the dismissal mechanism (clearSelection) at the integration tier.

SRS-010
reviewed 10. At most one overlay open at a time UID: SRS-010 TYPE: functional STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall display at most one navigation overlay at a time; opening an overlay shall replace any overlay that is currently open.

RATIONALE:

Refines SYS-005. Limiting the interface to a single open overlay keeps the operator's focus clear and preserves the maximum visible area of the underlying signal display. The constraint is realised structurally by a single selected-overlay index rather than a navigation stack (see ARCH-010), so a second overlay cannot be layered over the first.

REVIEWED_HASH:

8b339f513a68052b72a0dab34f0ebc46b778848c38b8552a70abe5c96c660985

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST-008 opens one overlay, then opens a second, and verifies only the second is shown.

  • ARCH-010
    reviewed 10. Overlay navigation subsystem UID: ARCH-010 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The overlay navigation subsystem manages the application's modal navigation overlays (Patients, Montages, Settings, Activities). The open-overlay state is held as a single selected index in the navigation view-model (NavigationNotifier), which drives which overlay the main page renders. A companion overlay view-model (OverlayNotifier) tracks overlay visibility, the dismissible flag, and per-overlay data. Because the rendered overlay is keyed off one index rather than a stack, at most one overlay is shown at a time and selecting another replaces it: MainPage renders the selected overlay in a single AnimatedSwitcher slot above a dimmed signal area, with the recording widget and bottom bar layered above it. Dismissal is wired two ways: a KeyboardListener closes the active overlay on the ESC key, and a full-screen barrier behind the overlay closes it when the operator taps outside the overlay content. Both paths call clearSelection(), which is gated by a dismissible flag (overlayDismissibleProvider) so an overlay with in-progress edits (the montage editor) intercepts the close attempt instead of discarding unsaved work.

    RATIONALE:

    Modelling the open overlay as one selected index — rather than a navigation stack — is what structurally enforces the single-overlay rule (SRS-010): there is no representation in which two overlays are open. Concentrating dismissal in clearSelection(), invoked by both the ESC handler and the tap-outside barrier, keeps the two dismissal triggers (SRS-009) behaviourally identical and routed through one place, and the dismissible gate keeps that single path safe for edit-bearing overlays.

    REVIEWED_HASH:

    d9ef3a3e1718ca469e67bab37fc0eedccbbf3fc9aea11b6ff4cce247fa7b3908

    REVIEWED_BY:

    @DougYoungberg

  • ST-008
    reviewedSkipped 8. Only one overlay shown at a time UID: ST-008 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the operator shall open a navigation overlay and then switch to other overlays in turn; at each switch only the newly-opened overlay shall be shown, with the previously-open overlay no longer visible.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible. Steps: open the Patients overlay (switch the bottom bar to menu mode), then in turn open Montages, then Settings, then Activities via their bottom-bar navigation items. Verification: after each switch a VisionTrace agent.verify(...) call confirms the newly-selected overlay is shown and the previously-open overlay is no longer visible — i.e. only one overlay is visible at a time. No error dialog appears during any step.

    REVIEWED_HASH:

    9542be12e77de13936787b1148b34a5e3ac255d13614bf06786f45a54578f1a0

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st008/, decorated with @visiontrace_test_case("ST-008"). Verifies SRS-010 at the operator-facing altitude; IT-010 verifies the single-selected-index model at the integration tier.

SRS-011
reviewed 11. Signal-mode bottom-bar controls UID: SRS-011 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

In signal mode, the bottom bar shall present the signal-parameter controls: a high-pass filter, a low-pass filter, a notch filter, a sensitivity control, a timebase control, and a montage selector.

RATIONALE:

Refines SYS-005. These are the per-recording signal adjustments the operator reaches without leaving the signal view; presenting them on the bottom bar in signal mode keeps them one interaction away while the live signal remains visible.

REVIEWED_HASH:

87a993af0ca2801932f9df334a3860d5e9de62d699450987430e7dd994b65a07

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: IT-011 asserts the six controls render in signal mode; ST-006 confirms the signal-parameter controls are shown at the operator-facing tier.

  • ARCH-009
    reviewed 9. Bottom-bar mode controller UID: ARCH-009 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The bottom-bar mode controller owns the bottom bar's signal/menu mode. The mode is modelled as a domain value object (BottomBarMode) carrying the two modes and the pure toggle and per-mode content definitions; an application view-model (BottomBarNotifier) holds the current mode — signal mode at launch — and switches it via toggleMode(). The bottom bar widget (BottomBar) watches the mode provider and renders the controls for the current mode: the signal-parameter controls (high-pass, low-pass and notch filters, sensitivity, timebase, and montage) in signal mode, and the Patients/Montages/Settings/Activities navigation buttons in menu mode. A single toggle control invokes toggleMode() when the operator activates it; switching to menu mode opens the corresponding navigation overlay (the last-opened one, or Patients by default) and switching back to signal mode closes it. Dismissing the open overlay — by Escape, a click outside it, or re-selecting the active navigation item — clears the navigation selection, which resets the controller to signal mode.

    RATIONALE:

    Modelling the mode and its toggle as a pure domain value object, with the view-model holding only the current-mode state, keeps the mode-switch rule free of presentation and platform concerns so it can be verified at unit level, while the widget stays a thin renderer of whichever mode is current.

    REVIEWED_HASH:

    ea1afa48d51bd8a9eb5e14ecb9ebf753683c392a6412f641e1257291efd544ac

    REVIEWED_BY:

    @DougYoungberg

  • ST-006
    reviewedSkipped 6. Bottom bar toggles signal and menu modes UID: ST-006 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the bottom bar shall begin in signal mode showing the signal-parameter controls; activating the bottom-bar toggle shall switch it to menu mode showing the Patients, Montages, Settings, and Activities navigation items; activating the toggle again shall return it to signal mode.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible with the bottom bar in its default signal mode. Steps: observe the bottom bar; activate the centre toggle control; observe the bottom bar; activate the centre toggle control again; observe the bottom bar. Verification: a VisionTrace agent.verify(...) call confirms the bottom bar shows signal-parameter controls initially; a second confirms it shows the Patients/Montages/Settings/Activities navigation items after the first toggle; a third confirms it has returned to the signal-parameter controls after the second toggle. No error dialog appears during any step.

    REVIEWED_HASH:

    4efc230698735603fb7956284db0f435b55ca922edf621eed359c7faa6d6236b

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st006/, decorated with @visiontrace_test_case("ST-006"). Verifies SRS-008 at the operator-facing altitude; IT-009 verifies the widget-to-view-model mode switching at the lower tier.

SRS-012
reviewed 12. Menu-mode bottom-bar navigation buttons UID: SRS-012 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

In menu mode, the bottom bar shall present the navigation buttons: Patients, Montages, Settings, and Activities.

RATIONALE:

Refines SYS-005. Menu mode replaces the signal-parameter controls with the four primary navigation destinations, each of which opens its overlay, so the operator reaches patients, montages, settings, and activities from the same fixed bar.

REVIEWED_HASH:

68a5f126aba7210ab6bfdf3c3998fa61d7efa723f3b4cd42215e59a1f7fd2099

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: IT-011 asserts the four navigation buttons render in menu mode; ST-006 confirms the four items are shown at the operator-facing tier.

  • ARCH-009
    reviewed 9. Bottom-bar mode controller UID: ARCH-009 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The bottom-bar mode controller owns the bottom bar's signal/menu mode. The mode is modelled as a domain value object (BottomBarMode) carrying the two modes and the pure toggle and per-mode content definitions; an application view-model (BottomBarNotifier) holds the current mode — signal mode at launch — and switches it via toggleMode(). The bottom bar widget (BottomBar) watches the mode provider and renders the controls for the current mode: the signal-parameter controls (high-pass, low-pass and notch filters, sensitivity, timebase, and montage) in signal mode, and the Patients/Montages/Settings/Activities navigation buttons in menu mode. A single toggle control invokes toggleMode() when the operator activates it; switching to menu mode opens the corresponding navigation overlay (the last-opened one, or Patients by default) and switching back to signal mode closes it. Dismissing the open overlay — by Escape, a click outside it, or re-selecting the active navigation item — clears the navigation selection, which resets the controller to signal mode.

    RATIONALE:

    Modelling the mode and its toggle as a pure domain value object, with the view-model holding only the current-mode state, keeps the mode-switch rule free of presentation and platform concerns so it can be verified at unit level, while the widget stays a thin renderer of whichever mode is current.

    REVIEWED_HASH:

    ea1afa48d51bd8a9eb5e14ecb9ebf753683c392a6412f641e1257291efd544ac

    REVIEWED_BY:

    @DougYoungberg

  • ST-006
    reviewedSkipped 6. Bottom bar toggles signal and menu modes UID: ST-006 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the bottom bar shall begin in signal mode showing the signal-parameter controls; activating the bottom-bar toggle shall switch it to menu mode showing the Patients, Montages, Settings, and Activities navigation items; activating the toggle again shall return it to signal mode.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible with the bottom bar in its default signal mode. Steps: observe the bottom bar; activate the centre toggle control; observe the bottom bar; activate the centre toggle control again; observe the bottom bar. Verification: a VisionTrace agent.verify(...) call confirms the bottom bar shows signal-parameter controls initially; a second confirms it shows the Patients/Montages/Settings/Activities navigation items after the first toggle; a third confirms it has returned to the signal-parameter controls after the second toggle. No error dialog appears during any step.

    REVIEWED_HASH:

    4efc230698735603fb7956284db0f435b55ca922edf621eed359c7faa6d6236b

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st006/, decorated with @visiontrace_test_case("ST-006"). Verifies SRS-008 at the operator-facing altitude; IT-009 verifies the widget-to-view-model mode switching at the lower tier.

SRS-013
reviewed 13. Recorded-duration readout format UID: SRS-013 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

While a recording session is active, the software shall display the recorded duration in HH:MM:SS format.

RATIONALE:

Refines SYS-005. A recorded-duration readout in a fixed HH:MM:SS format lets the operator see how much signal has been captured so far while keeping the live signal in view.

REVIEWED_HASH:

44a71204c417957885ee30f52c99c5b19e8e51c0e3da1d1cda7243ae850f84c6

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: UT-001 verifies the duration-to-HH:MM:SS formatting at the unit tier; ST-009 observes the readout shown in HH:MM:SS format in the running application during an active recording.

  • ARCH-008
    reviewed 8. Recording control widget UID: ARCH-008 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The recording control widget occupies the fixed top region of the main window. It is a provider-bound presentation container (RecordingWidget) that subscribes to the recording, selected-patient, and signal-engine application providers and renders, through its view (RecordingWidgetView) and the recording sub-components (status badge, action buttons, center content, and menu panel), the recording controls, the current patient name and recording status, and the elapsed-recording-time readout. It dispatches operator actions — start and stop recording — to the recording view-model and holds no recording domain logic itself. The recorded duration shown in that readout is derived from the native recording engine's sample-accurate timing, pushed into the recording view-model as signal is captured rather than from a wall-clock timer, and is formatted as zero-padded HH:MM:SS by the recording widget state (RecordingWidgetState.formattedElapsedTime).

    RATIONALE:

    Keeping the recording widget as a thin provider-bound container, with rendering delegated to a separate view and sub-components, decouples the always-visible top region from recording domain logic. The widget is driven entirely by provider state, so its presentation can be exercised by pumping it with seeded provider values independently of how a recording is actually performed.

    REVIEWED_HASH:

    535519a4d087d4a5931deb257e7c48e7266ea4f7b96de89810a49f41b5c2685c

    REVIEWED_BY:

    @DougYoungberg

  • UT-001
    reviewedPassed 1. Recorded-duration HH:MM:SS formatter UID: UT-001 TEST_METHOD: automated TEST_TOOL: flutter_test STATUS: Approved RELATIONS (Parent): STATEMENT:

    Exercise the RecordingWidgetState.formattedElapsedTime getter with a range of recorded-duration values and assert the returned string is the zero-padded HH:MM:SS representation of that duration.

    ACCEPTANCE_CRITERIA:

    For a seeded elapsedTime the getter returns hours, minutes, and seconds, each zero-padded to two digits and joined by colons: Duration.zero yields "00:00:00"; 1 minute 5 seconds yields "00:01:05"; 1 hour 1 minute 1 second yields "01:01:01"; and hours are not wrapped at 24 (100 hours yields "100:00:00").

    REVIEWED_HASH:

    ae3855a7b171f5f34e0094b9b1a986dd607504e3737a532edf03b7bb50c97f57

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test file: test/unit/domain/entities/ui/recording_widget_state_test.dart, in the UT-001-prefixed test case (the test name carries the UID prefix for the Flutter/JUnit join channel). Verifies the SRS-013 recorded-duration format at the unit tier (Class-B UT-to-SRS asymmetry); the widget-render integration is covered by IT-008 and the running-application presentation by ST-009.

  • ST-009
    reviewedSkipped 9. Recorded duration shown in HH:MM:SS UID: ST-009 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched and a recording session active, the operator shall see the recorded-duration readout in the recording widget displayed in HH:MM:SS format.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched and a recording session is active, so the recording widget is in a non-idle state. Verification: a VisionTrace agent.verify(...) call confirms the recording widget shows a recorded-duration readout formatted as HH:MM:SS — two-digit hours, minutes, and seconds separated by colons (for example "00:00:07"). No error dialog appears.

    REVIEWED_HASH:

    c835f5c0a49fa0c891b7b173bff611254eeaf46b8f27d8c705369bede403c5a0

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st009/, decorated with @visiontrace_test_case("ST-009"). Verifies SRS-013 at the operator-facing altitude; UT-001 verifies the duration-to-HH:MM:SS formatting at the unit tier and IT-008 confirms the widget renders the readout from seeded state.

SRS-014
reviewed 14. Patient name in recording widget UID: SRS-014 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

While a patient is selected, the software shall display the selected patient's name in the recording control widget.

RATIONALE:

Refines SYS-005. Showing the selected patient's name in the always-visible recording widget lets the operator confirm at a glance which patient the session is being recorded for while keeping the live signal in view.

REVIEWED_HASH:

3e52266db5d5faf9cfd839c7b4b8808bea0f43f535ef0af241b4cb0e72ffe88f

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST-010 observes the selected patient's name shown in the recording widget in the running application; IT-008 confirms the widget renders the patient name from seeded state.

  • ARCH-008
    reviewed 8. Recording control widget UID: ARCH-008 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The recording control widget occupies the fixed top region of the main window. It is a provider-bound presentation container (RecordingWidget) that subscribes to the recording, selected-patient, and signal-engine application providers and renders, through its view (RecordingWidgetView) and the recording sub-components (status badge, action buttons, center content, and menu panel), the recording controls, the current patient name and recording status, and the elapsed-recording-time readout. It dispatches operator actions — start and stop recording — to the recording view-model and holds no recording domain logic itself. The recorded duration shown in that readout is derived from the native recording engine's sample-accurate timing, pushed into the recording view-model as signal is captured rather than from a wall-clock timer, and is formatted as zero-padded HH:MM:SS by the recording widget state (RecordingWidgetState.formattedElapsedTime).

    RATIONALE:

    Keeping the recording widget as a thin provider-bound container, with rendering delegated to a separate view and sub-components, decouples the always-visible top region from recording domain logic. The widget is driven entirely by provider state, so its presentation can be exercised by pumping it with seeded provider values independently of how a recording is actually performed.

    REVIEWED_HASH:

    535519a4d087d4a5931deb257e7c48e7266ea4f7b96de89810a49f41b5c2685c

    REVIEWED_BY:

    @DougYoungberg

  • ST-010
    reviewedSkipped 10. Patient name shown in recording widget UID: ST-010 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the operator shall select a patient and then see that patient's name displayed in the recording control widget.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible. Steps: open the Patients overlay (switch the bottom bar to menu mode) and select a patient from the list. Verification: a VisionTrace agent.verify(...) call confirms the recording control widget shows the selected patient's name. No error dialog appears.

    REVIEWED_HASH:

    a067526d3644efec1a8527ec7873c5863690f6abb9880ad13b74fa95d1afc0e4

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st010/, decorated with @visiontrace_test_case("ST-010"). Verifies SRS-014 at the operator-facing altitude; IT-008 confirms the widget renders the patient name from seeded state.

SRS-015
reviewed 15. Bottom bar default and resting mode UID: SRS-015 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The bottom bar shall be in signal mode when the application launches, and shall return to signal mode whenever the open navigation overlay is dismissed.

RATIONALE:

Refines SYS-005. Signal mode is the operator's working view, so the bottom bar opens there and falls back to it once a navigation overlay is closed, keeping the signal-parameter controls available by default.

REVIEWED_HASH:

9c6b9513d6834a87fc4441c8cea891e78a3add74b32609de21884fb0a816ea9e

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: IT-009 asserts signal mode at launch and IT-010 asserts the return to signal mode after the overlay is dismissed; ST-011 observes the launch-to-menu-to-signal cycle at the operator-facing tier.

  • ARCH-009
    reviewed 9. Bottom-bar mode controller UID: ARCH-009 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The bottom-bar mode controller owns the bottom bar's signal/menu mode. The mode is modelled as a domain value object (BottomBarMode) carrying the two modes and the pure toggle and per-mode content definitions; an application view-model (BottomBarNotifier) holds the current mode — signal mode at launch — and switches it via toggleMode(). The bottom bar widget (BottomBar) watches the mode provider and renders the controls for the current mode: the signal-parameter controls (high-pass, low-pass and notch filters, sensitivity, timebase, and montage) in signal mode, and the Patients/Montages/Settings/Activities navigation buttons in menu mode. A single toggle control invokes toggleMode() when the operator activates it; switching to menu mode opens the corresponding navigation overlay (the last-opened one, or Patients by default) and switching back to signal mode closes it. Dismissing the open overlay — by Escape, a click outside it, or re-selecting the active navigation item — clears the navigation selection, which resets the controller to signal mode.

    RATIONALE:

    Modelling the mode and its toggle as a pure domain value object, with the view-model holding only the current-mode state, keeps the mode-switch rule free of presentation and platform concerns so it can be verified at unit level, while the widget stays a thin renderer of whichever mode is current.

    REVIEWED_HASH:

    ea1afa48d51bd8a9eb5e14ecb9ebf753683c392a6412f641e1257291efd544ac

    REVIEWED_BY:

    @DougYoungberg

  • ST-011
    reviewedSkipped 11. Bottom bar rests in signal mode UID: ST-011 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the operator shall see the bottom bar in signal mode, switch it to menu mode, then dismiss the open overlay and see the bottom bar return to signal mode.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible. Steps: confirm the bottom bar shows the signal-parameter controls; switch the bottom bar to menu mode, which opens a navigation overlay; dismiss the overlay by pressing Escape. Verification: agent.verify(...) calls confirm the bottom bar shows the signal-parameter controls at launch and again after the overlay is dismissed, i.e. it has returned to signal mode. No error dialog appears.

    REVIEWED_HASH:

    018cf2cc5768863e4f86a4e19ca00bbfc3d111583babbe87b480fb78e362a8a5

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st011/, decorated with @visiontrace_test_case("ST-011"). Verifies SRS-015 at the operator-facing altitude; IT-009 asserts signal mode at launch and IT-010 asserts the return to signal mode after the overlay is dismissed.

SRS-016
reviewed 16. Minimum main window size UID: SRS-016 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall prevent the main application window from being resized smaller than 1024 by 768 pixels.

RATIONALE:

Refines SYS-005. 1024 by 768 is the minimum size at which the operator workstation remains usable; preventing the window from shrinking below it keeps the live signal display and recording controls legible on lower-resolution laptops.

REVIEWED_HASH:

4200fb2d0be3aee20b1455b9e0faba8eab18e82f2097544c2a0921230dd51767

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST-012 (planned) resizes the window below the minimum and asserts the reported window bounds are clamped to at least 1024 by 768 at the operator-facing tier. No flutter_test integration test is feasible — the minimum is enforced natively by the window_manager package, not in a widget tree.

  • ARCH-007
    reviewed 7. Application window launch and state subsystem UID: ARCH-007 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (File): STATEMENT:

    The application's top-level desktop window is shown maximised at launch by the native Windows runner: Win32Window::Show() (windows/runner/win32_window.cpp) calls ShowWindow with SW_SHOWMAXIMIZED, invoked from flutter_window.cpp during startup. The Dart application bootstrap additionally calls windowManager.maximize() after the window_manager package initialises, reinforcing the maximised state once the Flutter engine is running. Runtime window state — size, position, and maximised flag — is owned by the WindowStateNotifier (application layer), which applies changes through the window_manager package and persists them to SharedPreferences for restoration on the next launch. The window's minimum size is configured as 1024x768 through the window_manager package's WindowOptions in main.dart, which the package enforces against resize requests so the window cannot be made smaller than that floor.

    RATIONALE:

    Launching maximised is set at the native window layer so the window is already maximised the instant it first paints, before the Flutter engine and Dart layer are ready to act; the Dart bootstrap maximise call then keeps the state correct once window_manager owns the window. Window-state persistence is kept in the application-layer notifier so size and position survive across sessions independently of the launch behaviour.

    REVIEWED_HASH:

    59e14f00ae2b25d6492e269b9ff3fe6debc9ec0a0f261bd3eba952eb582fe3fa

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    coverage-plan: verified at system level by ST-004, which observes the maximised window in the running application. No flutter_test integration test is feasible for the launch maximise itself: it is performed by the native Win32 runner and by the window_manager package singleton at bootstrap, neither of which is injectable in a widget test. The minimum window size is verified the same way — at system level by ST-012 (planned), which resizes the window below the minimum and asserts the bounds are clamped — since it too is enforced by the window_manager singleton rather than in a widget tree.

  • ST-012
    reviewedSkipped 12. Minimum window size is enforced UID: ST-012 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, attempt to resize the main window below the 1024x768 minimum and confirm the window is clamped to at least 1024x768.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched. Steps: request a window size smaller than the minimum (800x600) through the window-geometry API. Verification: the resulting window bounds are at least 1024 pixels wide and 768 pixels tall, i.e. the request was clamped to the declared minimum. The window is restored to its maximized state afterwards.

    REVIEWED_HASH:

    fb85a16be79bc3682b6794803a37235605338f1042ffa054ac691aa09715008b

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Hand-written geometry-assertion test (not recorder-generated) at visiontrace_tests/bioflow/st012/st_012_minimum_window_size_enforced.py, decorated with @visiontrace_test_case("ST-012"). Asserts on the actual window bounds via the VisionTrace AppSession.resize_to / get_window_bounds API rather than a visual check. Verifies SRS-016 at the operator-facing tier; no flutter_test integration test is feasible (the minimum is enforced natively by the window_manager package).

SRS-017
reviewed 17. Selectable application themes UID: SRS-017 TYPE: ui STATUS: Approved RELATIONS (Parent): RELATIONS (Child): STATEMENT:

The software shall provide three selectable visual themes — Light, Dark, and Dark Glass — and shall apply the operator's selected theme across the application.

RATIONALE:

Refines SYS-005. Offering Light, Dark, and Dark Glass themes lets the operator pick the appearance that suits the room's lighting and their preference, while the selection applies consistently across the workstation.

REVIEWED_HASH:

5e1badbc2e307e77ef9e1d06d69e677c0706f21a32b6a1d144b64768213b4160

REVIEWED_BY:

@DougYoungberg

NOTES:

coverage-plan: ST-013 observes the three themes offered and a theme change taking effect in the running application; IT-012 verifies that each theme type drives its application theme at the integration tier.

  • ARCH-011
    reviewed 11. Theme subsystem UID: ARCH-011 TYPE: subsystem SAFETY_CLASS: B STATUS: Approved RELATIONS (Parent): RELATIONS (Child): RELATIONS (File): STATEMENT:

    The theme subsystem owns the application's visual theming. The available themes are modelled as a domain value object (ThemeType: minimalLight, minimal, and darkGlass — surfaced to the operator as Light, Dark, and Dark Glass). AppTheme.forPreset builds the Flutter ThemeData for a given type, and application providers expose the active selection: the UISettingsNotifier holds the selected ThemeType, currentThemeTypeProvider reads it, and the theme-data and theme-mode providers derive the rendered theme from it, so the whole application re-themes when the selection changes.

    RATIONALE:

    Modelling the theme set as a domain value object with a pure type-to-ThemeData builder keeps the available themes and their construction free of presentation state, while the active selection lives in one application provider so the entire widget tree reads a single source of truth for the current theme.

    REVIEWED_HASH:

    500e401aad99ac68139f2fceaebd95c62c8c7bf29f5c215054493b98de99333c

    REVIEWED_BY:

    @DougYoungberg

  • ST-013
    reviewedSkipped 13. Operator selects each visual theme UID: ST-013 TEST_METHOD: automated TEST_TOOL: VisionTrace STATUS: Approved RELATIONS (Parent): STATEMENT:

    With the application launched, the operator shall open the theme selector, see the three available themes (Light, Dark, Dark Glass), and select each of the three in turn, with the application's appearance changing to match each selected theme.

    ACCEPTANCE_CRITERIA:

    Preconditions: the application is launched; the main screen is visible. Steps: open the settings / theme selector; confirm the three themes Light, Dark, and Dark Glass are listed; then select each theme in turn (first, second, third). Verification: a VisionTrace agent.verify(...) confirms all three themes are offered in the selector, and after each selection a further agent.verify(...) confirms the application's appearance reflects the just-selected theme and differs from the previous one. No error dialog appears.

    REVIEWED_HASH:

    369cb469593e893924d66d1d50d7089e4754a2c91ecd93e769290e920f029396

    REVIEWED_BY:

    @DougYoungberg

    NOTES:

    Test code lives in this repo at visiontrace_tests/bioflow/st013/, decorated with @visiontrace_test_case("ST-013"). Verifies SRS-017 at the operator-facing altitude; IT-012 verifies the theme-type-to-theme mapping at the integration tier.

SRS-018
inactive 18. Live signal display frame rate UID: SRS-018 TYPE: performance STATUS: Draft RELATIONS (Parent): STATEMENT:

The software shall render the live EEG signal display at a sustained rate of at least 60 frames per second.

RATIONALE:

Refines SYS-005. A high, steady frame rate keeps the live signal readable without perceptible stutter during a recording session.

REVIEWED_HASH:

d6a0927e9b4a133f3ce35546a3661e34bc5f317ae66ba6df63ec5749b1393146

REVIEWED_BY:

@DougYoungberg

NOTES:

Pending: deferred per product decision (not required for now). Activating it needs a frame-timing measurement harness to verify the on-screen refresh rate, which does not yet exist. Revisit when that tooling is available.

SRS-019
inactive 19. Multi-monitor window position restore UID: SRS-019 TYPE: ui STATUS: Draft RELATIONS (Parent): STATEMENT:

The software shall remember the main window's position and restore it on the next launch, including when the window was placed on a secondary monitor.

RATIONALE:

Refines SYS-005. Restoring the window where the operator last placed it, across a multi-monitor workstation, avoids re-positioning the interface at the start of every session.

REVIEWED_HASH:

3cabfa2067b9f2552e762aa3cde45becd92844962e52f522e0c302304e7a402b

REVIEWED_BY:

@DougYoungberg

NOTES:

Pending: deferred per product decision (not required for now). Verification needs a multi-monitor test environment; the current CI/VisionTrace rig has a single virtual display. Revisit when that environment is available.

SRS-020
inactive 20. Display-scaling layout integrity UID: SRS-020 TYPE: ui STATUS: Draft RELATIONS (Parent): STATEMENT:

The software shall present the main interface without clipped or overlapping controls under Windows display-scaling settings of 100%, 125%, 150%, and 200%.

RATIONALE:

Refines SYS-005. Clinicians run BioFlow on laptops set to various display scales; the interface shall stay legible and fully laid out at each.

REVIEWED_HASH:

64012965b01b94657d7d12839d019de4def916e9e0282d8e6ac706380021a6bd

REVIEWED_BY:

@DougYoungberg

NOTES:

Pending: deferred per product decision (not required for now). End-to-end verification needs the ability to launch the app under different OS display- scaling levels, which is not set up. Revisit when that environment is available.