# Use Hard Symlinks for Dataset

**Task**: AZ-169_refactor_hard_symlinks
**Name**: Use hard symlinks instead of file copies for dataset formation
**Description**: Replace shutil.copy() with os.link() in dataset split creation to save disk space
**Complexity**: 2 points
**Dependencies**: AZ-168_refactor_remove_processed_dir
**Component**: Training Pipeline
**Tracker**: AZ-169
**Epic**: AZ-164

## Problem

`copy_annotations()` in `train.py` uses `shutil.copy()` to duplicate images and labels into train/valid/test splits. For large datasets this wastes significant disk space.

## Outcome

- Dataset formation uses `os.link()` (hard links) instead of `shutil.copy()`
- Fallback to `shutil.copy()` when hard links fail (cross-filesystem)
- No change in training behavior — YOLO reads hard-linked files identically

## Scope

### Included
- Replace `shutil.copy()` with `os.link()` in `copy_annotations()` inner `copy_image()` function
- Add try/except fallback to `shutil.copy()` for `OSError` (cross-filesystem)

### Excluded
- Changing `form_data_sample()` in exports.py (separate utility, lower priority)
- Changing corrupted file handling

## Acceptance Criteria

**AC-1: Hard links used**
Given images and labels in the data directory
When `copy_annotations()` creates train/valid/test splits
Then files are hard-linked via `os.link()`, not copied

**AC-2: Fallback on failure**
Given a cross-filesystem scenario where `os.link()` raises `OSError`
When `copy_annotations()` encounters the error
Then it falls back to `shutil.copy()` transparently
