From an ethics approval to an enforced envelope: a procedure¶
This page is a procedure. A person or an AI agent (of any make) follows it to turn a research ethics approval into limits this toolbox enforces on an acquisition machine. It is written as steps, with stop conditions and an output for each step, so that two careful followers given the same approval produce the same result, and so that a reviewer can check the work without redoing it.
The toolbox side is the approval envelope: an entry in the site profile's governance.approval list that refuses to lock a session outside it (docs/SITE_PROFILE.md §3a, ssvep.runtime.approval). This page is about getting that entry right, keeping it right, and being honest about what an envelope cannot do.
Why a procedure, and not just a form¶
An envelope is a transcription. Three things go wrong with transcriptions, and each step below exists to stop one of them:
- A clause is lost. An approval says forty things that bear on software and the transcription captures twelve. Nothing complains, because an absent key restricts nothing. The clause register (step 3) makes every clause end somewhere.
- A clause is widened. "Between 8 and 30 Hz" read as exclusive, a percentage written as a fraction off by a factor of 100, a hardware list that names a family where the approval names one device. The transcription rules (step 4) and the probes (step 5) catch these.
- The envelope drifts from the approval. A renewal date passes, an amendment changes a limit, a toolbox upgrade changes what a key means, someone edits the profile. Binding, locking and the maintenance triggers (steps 7 and 8) catch these.
None of it replaces the person responsible for the approval reading the result. The procedure produces something short enough for them to read properly.
Roles and boundaries (read first)¶
- The responsible person (the principal investigator, or whoever the approval names) decides what is approved. The follower never infers that something was approved, from a file name, a folder, a draft or a date. The input to this procedure is documents the responsible person has designated in writing as the approved version.
- The follower transcribes, verifies and reports. It drafts; it does not decide.
- Nothing in the toolbox repository states an approval. The envelope, the approval documents and the clause register are deployment facts. They live in the deployment's own git-ignored profile folder, or in a lab's own private configuration repository (docs/SITE_PROFILE.md §10), never in the toolbox's tracked files. The toolbox's own tests refuse an institution's identifiers in shipped text.
- An approval covers a study, not the toolbox. An ethics approval is for one piece of research: one study, with its own question, population and procedures. It is not a licence for everything this toolbox can do. Transcribe only what that study does. A capability the toolbox has but the study does not use (another paradigm, another amplifier, a validation of the toolbox itself) is left out, and is refused under that envelope, even if the approval's wording could be stretched to fit it. Work that needs it needs its own approval, which becomes its own entry with its own
id. The operator chooses which approval a session runs under at each lock, and every recording names it. - The toolbox default stays permissive; the deployment restricts. With no envelope, the toolbox allows any parameters and only warns. Pilot sessions are warned, not refused, unless an approval says it covers them (
applies_to_pilots). A lab's own limits are switched on by that lab's profile on its acquisition machine. They are never made the default for everyone. - An envelope may only restrict. No step here may make the toolbox more permissive than it is without the envelope, weaken a shipped photosensitivity warning, or remove the abort.
Stop and ask the responsible person if any of these holds. Do not work around it.
- The documents are not designated as approved, or two designated documents disagree.
- A clause can be read two ways and the narrower reading would block work the responsible person evidently intends.
- Making a protocol pass would need the envelope to be wider than the approval.
- A clause belongs in the register but you cannot classify it (step 3).
Step 1. Collect and fingerprint the approved documents¶
Input: the documents the responsible person designated. Output: a list of file name — version label — SHA-256.
- List every designated file: the approval letter if there is one, the approved application or protocol, and its appendices (consent form, safety procedure, screening form).
- Compute each file's SHA-256 on the machine that holds it. On any platform with Python:
python -c "import hashlib,sys; print(hashlib.sha256(open(sys.argv[1],'rb').read()).hexdigest())" <file>. - Choose the binding document: the one that states the limits the envelope transcribes. It is usually the approved application, not the letter. Its hash goes into the envelope (step 4). Name the others in a
_documentsnote on the entry, so a reader can find them. - Find the approval's expiry: the approval letter, or the institution's renewal rule. If you cannot find one, it is a stop-and-ask, not a blank. An envelope with no
expiresnever lapses on its own.
Step 2. Extract every constraint¶
Output: a numbered list of clauses, each with a short verbatim quote and its location (section and page).
Read the whole binding document and every appendix that describes what happens in a session. Extract each sentence that constrains any of the following. When unsure, extract it: a clause classified N/A in step 3 costs one line.
- Who takes part: population, ages, inclusion and exclusion criteria, screening.
- What is presented: paradigms, frequencies, colours, sizes, patterns, spatial frequency, contrast, duty cycle, number of targets, durations, pauses, any adaptive procedure.
- Hardware: amplifiers, electrode carriers, electrode counts, eye-tracking and cameras.
- Session: order of steps, total length, stimulation time, breaks, what the participant is told and when (for example, how to stop the stimulation).
- Consent and data use: how consent is recorded, what choices the participant makes, what may be kept or shared.
- Data handling: dates, identifiers, storage, transfer, sharing, export contents.
- Safety: symptom monitoring, alert thresholds, adverse events, stopping rules.
- Pilots and testing: who may be piloted, and under which limits.
Step 3. Classify every clause (the clause register)¶
Output: the register, a table with one row per clause and exactly one class per row.
| Class | Meaning | What the row must name |
|---|---|---|
| ENVELOPE | An envelope key enforces it at lock (and Start, for hardware). | The key and the value written (step 4). |
| FEATURE | Another toolbox mechanism enforces it. | The mechanism, and the setting that turns it on: protocol data_use and consent wording, participant screens, protocol questionnaires and their alert thresholds, date shifting, export rules, the data-use matrix. |
| PROCEDURE | People keep it. The toolbox does not, today. | The standard operating procedure (SOP) step that keeps it, and who does it. |
| GAP | It should be enforced in software and is not, or the software contradicts it. | The tracker issue filed for it, and the interim procedure. |
| N/A | It does not bear on anything the toolbox does. | One phrase saying why. |
python -m ssvep.runtime.approval_verify prints a list headed NEVER CHECKED BY AN ENVELOPE. Every clause of those kinds is FEATURE, PROCEDURE or GAP, never ENVELOPE.
The common mappings:
| The approval says | Class and mechanism |
|---|---|
| Which paradigms or tasks are used | ENVELOPE paradigms. List only those the study uses, as the approval describes them. A paradigm the toolbox has but the study does not use is left out, even if a general phrase in the approval could be read to cover it. |
| A flicker frequency range | ENVELOPE flicker_hz. A contrast-reversing pattern is held at both f and 2f. |
| Colour restrictions, for example achromatic in a band, or no saturated red or red–blue | ENVELOPE colour (achromatic_hz, saturated_red, red_blue) |
| Maximum target size, possibly only in a band | ENVELOPE target_size (max_deg, band_hz) |
| Spatial frequency, or cycles across a pattern | ENVELOPE max_cpd, max_cycles_across_width (the width only), max_cycles_any_orientation (any orientation). Pick the one whose wording matches. |
| Number of targets (a maximum) | ENVELOPE max_targets. A minimum is PROCEDURE. |
| Stimulus duration per trial | ENVELOPE trial_stim_s. A pause after it is PROCEDURE. |
| Duty cycle | ENVELOPE duty_cycle, written as a fraction |
| Amplifiers, electrode carriers | ENVELOPE boards, headsets, using the toolbox's own identifiers (below). An electrode count is ENVELOPE only through the headsets listed, otherwise PROCEDURE. |
| Team members may pilot the protocol, within the same limits | ENVELOPE "applies_to_pilots": true. If the approval says nothing about pilots, leave the key out. This is the correct transcription, not a wider reading: an approval that is silent on pilots does not govern them. Leaving it out does not exempt pilots from the envelope, which still flags them (as a warning). A pilot session's recordings are labelled, never exported, and excluded from every analysis. Rule 4.4 (the narrower reading) applies to what the approval says. It does not invent a limit for something the approval does not cover. |
| Contrast range, or contrast that may only decrease | Ceiling: PROCEDURE (no key). Adaptive monotonicity: GAP only if the deployment uses an adaptive procedure. |
| Session length, total stimulation time | PROCEDURE (no key) |
| Population, age, inclusion and exclusion criteria | PROCEDURE (screening). Keep them as a _ note. |
| Consent on screen, a particular consent text, data-use options | FEATURE: protocol data_use (consent mode, wording, minimum tier) and the participant screens. Whether the text shown is the approved text is PROCEDURE until something binds it. |
| Safety statements before the session, and what ends it | FEATURE: the protocol's safety_screen. Check the statements and their order against the approval. |
| Symptom questionnaire and alert thresholds | FEATURE: a protocol questionnaire group with its thresholds. That it runs is PROCEDURE. |
| Dates shifted, no identifiers | FEATURE: always on (docs/DATA_GOVERNANCE.md) |
| What may be shared or exported | FEATURE: the data-use matrix and export rules |
| Adverse-event log, stopping rules | PROCEDURE |
| How the participant can stop the stimulation | FEATURE (Esc in every stimulus window) plus PROCEDURE (telling them) |
The toolbox's hardware identifiers are the ones an envelope matches. Print them on the install rather than copying a list from a document:
python -c "from ssvep.stim import builder; print(builder.headset_names()); print(sorted(d['board'] for d in builder.DEVICES.values()))"
A device the approval names that has no identifier of its own (for example, a home-built amplifier that presents itself as a supported board) is classified PROCEDURE, with a sentence saying which identifier it records under.
Step 4. Transcribe¶
Output: one governance.approval entry.
Write it with the Site profile dialog (Set up Session → Site profile… → Approvals → Add…) or by hand. The rules are the same either way.
- Identity. Set these from step 1:
id: short and stable. Every recording names it, so never reuse one for a different approval.version: the approval document's own version label.reference,authority,approved_on,expires.documentanddocument_sha256for the binding document, kept beside the profile.- Inclusive boundaries. Every range is inclusive at both ends. "Between 8 and 30 Hz" is
{"min": 8, "max": 30}. If the approval excludes a boundary, move it inward. - Units, explicitly. Frequencies in Hz, sizes in degrees of visual angle, durations in seconds. Duty cycle is a fraction: 10–90% is
{"min": 0.1, "max": 0.9}. The loader refuses a duty cycle above 1, but it cannot catch every unit slip. The probes in step 5 show what each limit actually admits. - The narrower reading. Where a clause can be read two ways, write the narrower one and record the choice in the register. Never the wider one.
- Nothing the approval does not say. Do not add a limit "to be safe" that the approval does not state. Record it as a recommendation in the register instead. The envelope is a transcription, and the register is where judgement goes.
- Limits with no key go in as
_notes ("_populations","_max_session_minutes"), so the profile carries them on record. The loader refuses them as real keys, by design.
Step 5. Verify by effect¶
Output: the full report of the verify command, run on the protocols the study will use, with exit status 0.
python -m ssvep.runtime.approval_verify --profile <profile.json> --protocol <study-protocol.json> --board <board> --headset "<headset>"
Choosing the protocols and the hardware:
- Protocols. Give each protocol the study will run with
--protocol(repeatable).--all-protocolschecks every protocol in the profile's ownpaths.designsfolders instead. The toolbox's shipped example protocols are never included in either. They are not the study's, and a tight envelope refuses most of them, which is expected. - Hardware. A protocol that carries no hardware of its own runs on whatever Set up Session chooses. To check that hardware here, give it with
--boardand--headset. Without them, the protocol's headset and board are left to the lock and to Start, and a warning says so.
Add --id <id> when the profile holds several approvals, and --json for a machine-readable report. The command writes nothing. It checks four things.
- The envelope's state. The profile kind is
lab(any other kind gates nothing), the envelope is not expired, and the bound document is present and matches its hash. - Probes. Each limit is tested alone, through the lock's own check, with a design just inside it, at an inclusive boundary, and just outside it. Every probe must pass. A failing probe means this install does not enforce what the envelope says. Do not deploy until it is explained.
- Protocols. Each protocol named is checked as a study session would be at lock. A refused protocol is fixed in the design, on Build run or Build Protocol. Never widen the envelope to make a protocol pass. If the protocol is what the researchers intend and the approval does not cover it, that is an amendment for the responsible person, not a transcription change.
- The summary. The command prints, in plain sentences, everything the envelope refuses, every
_note it does not enforce, and the list of things no envelope checks.
Step 6. Review and sign-off¶
Output: the responsible person's recorded sign-off, kept with the deployment's records (not in the toolbox repository).
Give the responsible person three things:
- the clause register;
- the verify report's WHAT THE TOOLBOX WILL REFUSE section, beside the binding document;
- every row classified PROCEDURE or GAP, with who keeps each one.
They read the summary against the approval. That reading is the check; everything before it only makes it short. A disagreement goes back to step 3 or 4.
Step 7. Deploy on the acquisition machine¶
Output: the verify report run on that machine, with exit status 0.
- Put the profile and the binding document in the machine's profile folder. That is either the toolbox's git-ignored
config/, or a lab configuration folder named bySSVEP_SITE_PROFILEset at machine scope (docs/SITE_PROFILE.md §10, §12). - Set
"profile": "lab". An envelope on any other kind is ignored. - Set
"locked": trueonce it is final. The Site profile dialog then refuses to change it. This guards against casual edits, not against someone determined; the bound hash and the stamp in every recording are what make a change visible afterwards. - Update the toolbox there first. A profile that uses a key the installed toolbox does not know is refused when the profile loads, and the machine will not start. That is deliberate (fail closed), but plan for it.
- Run the verify command on that machine. The probes test the code installed there, which is the point. Keep the report with the sign-off.
Step 8. Keep it in step¶
Redo the steps named whenever one of these happens:
| Trigger | Redo |
|---|---|
| An amendment is approved | 1–7. Bump version, rebind the document, keep the old id only if the approval is the same one. |
| A renewal | 1, 4 (expires), 5, 7 |
| The verify command warns that expiry is near | Tell the responsible person. Nothing else. |
| A toolbox upgrade on the acquisition machine | 5 and 7: probes catch a changed meaning |
| A new or changed session protocol | Check a protocol… in the Site profile dialog, or the verify command with --protocol (and --board and --headset if the protocol carries no hardware) |
| A GAP is fixed in the toolbox | 3 and 4 for that row: reclassify it, and add the key if it is one |
What a follower must never do¶
- Record in any repository, document or tracker that an approval was granted, unless the responsible person wrote it there.
- Commit an approval document, its reference number or the deployment's envelope to the toolbox repository.
- Widen an envelope, remove a limit, or reclassify a clause to make a protocol or a session go ahead.
- Mark a clause ENVELOPE or FEATURE without the mechanism that enforces it, or drop a clause because it has no mechanism.
- Edit a deployed, locked profile in place without going back through steps 5 to 7.