# Acquisition Log

Canonical scan-level logging for this BIDS dataset. These TSV files are the
single source of truth for session metadata, scan annotations, and participant
tracking. Public subsets are automatically published to `rawdata/` as
BIDS-compliant TSVs.

## Files

| File | Description |
|---|---|
| `participants.tsv` | One row per participant. Public + private columns. |
| `sessions.tsv` | One row per scanning session. Public + private columns. |
| `scans.tsv` | One row per NIfTI file. Public + private columns. |

## Workflow

1. **Initialise** (once): `python libs/scan_log.py init`
2. **After each session**: Fill in participant/session rows manually.
3. **After BIDS conversion**: `python libs/scan_log.py discover --bids-dir rawdata/`
   discovers new `.nii.gz` files and adds them to canonical scans.
4. **Annotate**: Open `scans.tsv` in a spreadsheet and fill in `scan_status`,
   `anomaly_type`, `anomaly_detail`, etc.
5. **Publish**: `python libs/scan_log.py publish --bids-dir rawdata/` writes
   BIDS-compliant public TSVs (strips private columns).
6. **Validate**: `python libs/scan_log.py validate` checks for missing
   annotations and cross-referencing errors.
7. **Full sync**: `python libs/scan_log.py sync --bids-dir rawdata/` runs
   discover + publish + validate in one pass.

## Column Reference

### Participants

**Public columns** (shared in `rawdata/participants.tsv`):

| Column | Description |
|---|---|
| `participant_id` | BIDS subject label (e.g., `sub-UCI01`) |
| `site` | Acquisition site identifier |
| `age` | Age at first session |
| `sex` | Biological sex (M/F/O) |
| `handedness` | R/L/A (ambidextrous) |
| `group` | Experimental group assignment |
| `vision_correction` | None / glasses / contacts / corrected-to-normal |
| `data_quality` | Overall data quality code |
| `participant_notes` | Public-safe notes |

**Private columns** (never shared):

| Column | Description |
|---|---|
| `name` | Full legal name |
| `email` | Contact email |
| `iri_id` | Institutional/IRB identifier |
| `sessions_completed` | Count of completed sessions |
| `earned_total` | Total compensation earned |
| `booking_code` | Scheduling system code |
| `private_notes` | Internal notes |
| `exclusion_reason` | Why participant was excluded (if applicable) |

### Sessions

**Public columns** (shared in `rawdata/<sub>/sessions.tsv`):

| Column | Description |
|---|---|
| `participant_id` | BIDS subject label |
| `session_id` | BIDS session label (e.g., `ses-fmri1`) |
| `acq_date` | Acquisition date (YYYY-MM-DD) |
| `site` | Acquisition site |
| `scanner` | Scanner identifier |
| `session_status` | Overall session status |
| `session_notes` | Public-safe notes |
| `tasks_completed` | Comma-separated list of completed tasks |

**Private columns**:

| Column | Description |
|---|---|
| `acq_datetime` | Full datetime of acquisition |
| `arrived` | Time participant arrived |
| `start_time` | Time scanning started |
| `finish_time` | Time scanning finished |
| `subject_duration` | Total time in scanner (minutes) |
| `experimenter` | Name of experimenter |
| `payment_amount` | Amount paid |
| `payment_status` | paid / pending / waived |
| `eyetracking` | Whether eye tracking was used |
| `private_notes` | Internal notes |

### Scans

**Public columns** (shared in `rawdata/<sub>/<ses>/scans.tsv`):

| Column | Description |
|---|---|
| `filename` | Relative path to NIfTI (from session dir) |
| `acq_time` | Acquisition time from sidecar JSON |
| `modality` | BIDS modality folder (func/anat/dwi/fmap) |
| `task` | Task label |
| `run` | Run number |
| `scan_status` | Status code (see below) |
| `quality_notes` | Public-safe quality notes |

**Private columns**:

| Column | Description |
|---|---|
| `participant_id` | BIDS subject label (for cross-referencing) |
| `session_id` | BIDS session label (for cross-referencing) |
| `source_filename` | Original DICOM series name |
| `scan_order` | Order in which scan was acquired |
| `intended_protocol` | What protocol was planned |
| `actual_protocol` | What protocol was actually run |
| `anomaly_type` | Anomaly code (see below) |
| `anomaly_detail` | Free-text description of anomaly |
| `excluded` | Whether scan is excluded (true/false) |
| `exclusion_reason` | Why scan was excluded |
| `private_notes` | Internal notes |

## Status and Anomaly Codes

### `scan_status`

| Code | Meaning |
|---|---|
| `pass` | Scan completed normally, usable |
| `caution` | Completed but reviewer should inspect |
| `partial` | Scan partially completed |
| `interrupted` | Scan was interrupted mid-acquisition |
| `excluded` | Scan excluded from analysis |
| `rerun` | Scan was repeated (this is the failed attempt) |

### `anomaly_type`

| Code | Meaning |
|---|---|
| `none` | No anomaly |
| `interrupted` | Participant pressed stop, scanner error, etc. |
| `rerun` | Scan was repeated |
| `reordered` | Scan acquired out of protocol order |
| `wrong_params` | Incorrect scan parameters used |
| `equipment` | Equipment malfunction |
| `subject` | Subject-related issue (motion, fell asleep, etc.) |
| `other` | Other anomaly (describe in anomaly_detail) |

### `data_quality` (participants level)

| Code | Meaning |
|---|---|
| `pass` | Data meets quality standards |
| `pilot` | Pilot/test data, not for analysis |
| `excluded` | Participant excluded from study |

## Extending the Schema

Add project-specific codes or columns in `config/scan_log_schema.toml`.
See `libs/scan_log_schema.py` for the programmatic definitions.
