#!/usr/bin/env python3
from __future__ import annotations

import argparse
import csv
import json
import math
import re
import sys
import time
from functools import lru_cache
from pathlib import Path
from typing import Any, Iterable


sys.dont_write_bytecode = True
_ASSET_ROOT = Path(__file__).resolve().parent
if str(_ASSET_ROOT) not in sys.path:
    sys.path.insert(0, str(_ASSET_ROOT))

from model import PreparedSession, Source, Unit, Word
from session import plan_source_order


CONTRACT_VERSION = 1
PROFILE_VERSION = "semantic-rough-select-v1"
PAUSE_BOUNDARY_MS = 700
SIGNIFICANT_PAUSE_MS = 1500
MIN_CLAUSE_WORDS = 6
MAX_UNIT_WORDS = 32
DEFAULT_HANDLE_BEFORE_MS = 200
DEFAULT_HANDLE_AFTER_MS = 300
DEFAULT_BLOCK_GAP_MS = 750
DEFAULT_REVIEW_GAP_MS = 2000
ADVISORY_INPUT_BYTES = 100_000
RESPONSE_CAPTURE_CHARS = 200_000
PLACEMENT_COLUMNS = (
    "blockId",
    "variantId",
    "occurrenceId",
    "sourceId",
    "laneIndex",
    "videoTrackIndex",
    "audioTrackIndex",
    "sequenceStartSeconds",
    "sourceInSeconds",
    "sourceOutSeconds",
    "speechInSeconds",
    "speechOutSeconds",
    "durationSeconds",
)
MARKER_COLUMNS = (
    "markerId",
    "kind",
    "sequenceStartSeconds",
    "durationSeconds",
    "name",
    "comment",
)
SUMMARY_COLUMNS = (
    "blockCount",
    "variantCount",
    "occurrenceCount",
    "omittedUnitCount",
    "reusedUnitCount",
    "unassignedUnitCount",
    "technicalExclusionCount",
    "placementCount",
    "markerCount",
    "maxVideoLaneIndex",
    "maxAudioLaneIndex",
    "orderMode",
    "handleBeforeSeconds",
    "handleAfterSeconds",
    "blockGapSeconds",
    "reviewGapSeconds",
    "storyEndSeconds",
    "reviewStartSeconds",
    "sequenceEndSeconds",
)
COVERAGE_COLUMNS = (
    "sourceId",
    "unitId",
    "statuses",
    "placementUseCount",
    "technicalExclusionCount",
    "unassignedUseCount",
)
RELATION_TYPES = {
    "ALTERNATIVE_TO",
    "COMPLEMENTS",
    "QUALIFIES",
    "CONFLICTS_WITH",
}
CONFIDENCE_VALUES = {"HIGH", "MEDIUM", "LOW"}
REFINEMENT_VALUES = {"NONE", "START", "END", "BOTH"}
PREMIERE_REF_RE = re.compile(r"::(?:SEQ|PI|BIN|TRACK|ITEM|MARKER)\b", re.IGNORECASE)
ABSOLUTE_PATH_RE = re.compile(
    r"(?:^|[\s\"'])/(?:Users|Volumes|private|tmp|var)/|[A-Za-z]:[\\/]"
)
CLAUSE_END_RE = re.compile(r"[,;:]$")
SENTENCE_END_RE_LOCAL = re.compile(r"""[.!?]["')\]}]*$""")


def _toolkit_path(explicit: Path | None) -> Path:
    return explicit or (Path(__file__).resolve().parent.parent / "srt-caption-toolkit")


def require_srt_toolkit(path: Path) -> None:
    required = ("transcript.py", "caption_profile.py", "language.py", "timed_text.py")
    missing = [name for name in required if not (path / name).is_file()]
    if missing:
        raise RuntimeError(
            "Semantic rough select requires the complete sibling "
            f"'srt-caption-toolkit' asset; missing: {', '.join(missing)}."
        )


def _load_toolkit(path: Path) -> tuple[Any, Any]:
    require_srt_toolkit(path)
    if str(path) not in sys.path:
        sys.path.insert(0, str(path))
    from transcript import extract_transcript_words, iter_transcript_word_records

    return extract_transcript_words, iter_transcript_word_records


def _positive_int(value: Any, label: str, *, allow_zero: bool = False) -> int:
    if not isinstance(value, int) or value < (0 if allow_zero else 1):
        qualifier = "non-negative" if allow_zero else "positive"
        raise ValueError(f"{label} must be a {qualifier} integer.")
    return value


def _safe_text(value: Any, label: str, *, allow_empty: bool = False) -> str:
    if not isinstance(value, str) or (not allow_empty and not value.strip()):
        raise ValueError(f"{label} must be a string{', possibly empty' if allow_empty else ''}.")
    text = value.strip()
    if PREMIERE_REF_RE.search(text) or ABSOLUTE_PATH_RE.search(text):
        raise ValueError(f"{label} contains a Premiere ref or absolute filesystem path.")
    return text


def _source_language(transcript: dict[str, Any]) -> str:
    language = transcript.get("language")
    return language.strip() if isinstance(language, str) else ""


def _join_words(words: Iterable[Word]) -> str:
    output = ""
    for word in words:
        text = word.text.strip()
        if not output or re.fullmatch(r"[,.;:!?%)\]}]+", text):
            output += text
        elif output[-1] in "([{":
            output += text
        else:
            output += " " + text
    return output


def _segment_words(source_id: str, words: list[Word]) -> tuple[Unit, ...]:
    groups: list[list[Word]] = []
    current: list[Word] = []
    for word in words:
        if current and word.start_ms - current[-1].end_ms >= PAUSE_BOUNDARY_MS:
            groups.append(current)
            current = []
        current.append(word)
        punctuation_boundary = (
            len(current) >= MIN_CLAUSE_WORDS
            and bool(CLAUSE_END_RE.search(word.text))
        )
        if (
            SENTENCE_END_RE_LOCAL.search(word.text)
            or punctuation_boundary
            or len(current) >= MAX_UNIT_WORDS
        ):
            groups.append(current)
            current = []
    if current:
        groups.append(current)
    return tuple(
        Unit(
            unit_id=f"{source_id}.u{index:04d}",
            source_id=source_id,
            text=_join_words(group),
            start_word_id=group[0].word_id,
            end_word_id=group[-1].word_id,
            start_ms=group[0].start_ms,
            end_ms=group[-1].end_ms,
        )
        for index, group in enumerate(groups, start=1)
    )


def prepare_session(
    manifest: dict[str, Any],
    *,
    base_dir: Path,
    srt_toolkit_dir: Path | None = None,
) -> PreparedSession:
    if manifest.get("contractVersion") != CONTRACT_VERSION:
        raise ValueError("Session contractVersion is unsupported.")
    raw_sources = manifest.get("sources")
    if not isinstance(raw_sources, list):
        raise ValueError("Session sources must be a list.")
    ordered_indices, order_mode, order_warnings = plan_source_order(raw_sources)
    extract_words, iter_records = _load_toolkit(_toolkit_path(srt_toolkit_dir))
    editor_context = _safe_text(
        manifest.get("editorContext", ""),
        "editorContext",
        allow_empty=True,
    )
    sources: list[Source] = []
    for source_order, input_index in enumerate(ordered_indices):
        raw_source = raw_sources[input_index]
        source_id = _safe_text(raw_source.get("sourceId"), "sourceId")
        transcript_value = raw_source.get("transcriptPath")
        if not isinstance(transcript_value, str) or not transcript_value.strip():
            raise ValueError(f"Source {source_id} has no transcriptPath.")
        transcript_path = Path(transcript_value)
        if not transcript_path.is_absolute():
            transcript_path = (base_dir / transcript_path).resolve()
        transcript = json.loads(transcript_path.read_text(encoding="utf-8"))
        timed = extract_words(transcript)
        raw_records = [record for _, _, record in iter_records(transcript)]
        if len(timed) != len(raw_records):
            raise ValueError(f"Transcript word mapping is inconsistent for {source_id}.")
        words = [
            Word(
                word_id=f"{source_id}.w{index:06d}",
                source_id=source_id,
                text=item.text,
                start_ms=item.start_ms,
                end_ms=item.end_ms,
            )
            for index, item in enumerate(timed, start=1)
        ]
        units = _segment_words(source_id, words)
        declared_duration = raw_source.get("durationMs")
        duration_ms = (
            _positive_int(declared_duration, f"{source_id}.durationMs")
            if declared_duration is not None
            else words[-1].end_ms
        )
        if duration_ms < words[-1].end_ms:
            raise ValueError(f"Source {source_id} duration ends before its transcript.")
        has_video = raw_source.get("hasVideo", True)
        has_audio = raw_source.get("hasAudio", True)
        if not isinstance(has_video, bool) or not isinstance(has_audio, bool):
            raise ValueError(f"Source {source_id} media flags must be booleans.")
        if not has_video and not has_audio:
            raise ValueError(f"Source {source_id} has neither video nor audio.")
        sources.append(
            Source(
                source_id=source_id,
                source_order=source_order,
                selection_index=input_index,
                language=_source_language(transcript),
                duration_ms=duration_ms,
                has_video=has_video,
                has_audio=has_audio,
                words=tuple(words),
                units=units,
            )
        )
    return PreparedSession(
        contract_version=CONTRACT_VERSION,
        order_mode=order_mode,
        order_warnings=tuple(order_warnings),
        editor_context=editor_context,
        sources=tuple(sources),
    )


def request_payload(session: PreparedSession) -> dict[str, Any]:
    sources = []
    for source in session.sources:
        request_units = []
        previous_unit: Unit | None = None
        for unit in source.units:
            request_unit: dict[str, Any] = {
                "unitId": unit.unit_id,
                "text": unit.text,
            }
            if previous_unit is not None:
                pause_before_ms = max(0, unit.start_ms - previous_unit.end_ms)
                if pause_before_ms >= SIGNIFICANT_PAUSE_MS:
                    request_unit["pauseBeforeSeconds"] = round(
                        pause_before_ms / 1000,
                        3,
                    )
            request_units.append(request_unit)
            previous_unit = unit
        sources.append(
            {
                "sourceId": source.source_id,
                "sourceOrder": source.source_order,
                "language": source.language,
                "units": request_units,
            }
        )
    return {
        "contractVersion": CONTRACT_VERSION,
        "profileVersion": PROFILE_VERSION,
        "editorContext": session.editor_context,
        "instructions": {
            "goal": (
                "Arrange relevant material into ordered story blocks with local "
                "alternative variants. Preserve useful alternatives instead of "
                "choosing one winner."
            ),
            "coverage": (
                "Use relevant material comprehensively, but omit false starts, "
                "slates, corrections, and unusable asides when editorially sensible."
            ),
            "timing": "Return source/unit IDs only. Never invent timestamps.",
            "pauses": (
                "pauseBeforeSeconds appears only after at least 1.5 seconds of "
                "silence. It is editorial evidence, not a mandatory boundary. "
                "Interpret it with wording, context, and editor instructions."
            ),
        },
        "sources": sources,
    }


def canonical_json(value: Any) -> str:
    return json.dumps(
        value,
        ensure_ascii=False,
        sort_keys=True,
        separators=(",", ":"),
    )


def profile_request(payload: dict[str, Any]) -> dict[str, Any]:
    encoded = canonical_json(payload).encode("utf-8")
    unit_count = sum(len(source.get("units", [])) for source in payload["sources"])
    source_count = len(payload["sources"])
    response_forecast = 4096 + source_count * 256 + unit_count * 240
    warnings: list[dict[str, Any]] = []
    estimated_tokens = len(encoded)
    if len(encoded) > ADVISORY_INPUT_BYTES:
        warnings.append(
            {
                "reasonCode": "INPUT_ABOVE_TESTED_PROFILE",
                "actualUtf8Bytes": len(encoded),
                "actualEstimatedTokens": estimated_tokens,
                "testedUtf8Bytes": ADVISORY_INPUT_BYTES,
                "testedEstimatedTokens": ADVISORY_INPUT_BYTES,
            }
        )
    if response_forecast > int(RESPONSE_CAPTURE_CHARS * 0.8):
        warnings.append(
            {
                "reasonCode": "OUTPUT_FORECAST_NEAR_CAPTURE_LIMIT",
                "actual": response_forecast,
                "tested": RESPONSE_CAPTURE_CHARS,
            }
        )
    return {
        "profileVersion": PROFILE_VERSION,
        "requestUtf8Bytes": len(encoded),
        "estimatedInputTokens": estimated_tokens,
        "tokenEstimateMethod": "ONE_TOKEN_PER_UTF8_BYTE_CONSERVATIVE_FALLBACK",
        "responseForecastChars": response_forecast,
        "responseCaptureChars": RESPONSE_CAPTURE_CHARS,
        "aboveTestedProfile": bool(warnings),
        "warnings": warnings,
        "executionPolicy": "WARN_AND_CONTINUE",
    }


def _strict_object(properties: dict[str, Any], required: list[str]) -> dict[str, Any]:
    return {
        "type": "object",
        "additionalProperties": False,
        "properties": properties,
        "required": required,
    }


def global_response_schema() -> dict[str, Any]:
    relation = _strict_object(
        {
            "type": {"type": "string", "enum": sorted(RELATION_TYPES)},
            "targetVariantId": {"type": "string", "minLength": 1, "maxLength": 160},
            "reason": {"type": "string", "minLength": 1, "maxLength": 1000},
        },
        ["type", "targetVariantId", "reason"],
    )
    occurrence = _strict_object(
        {
            "occurrenceId": {"type": "string", "minLength": 1, "maxLength": 160},
            "sourceId": {"type": "string", "minLength": 1, "maxLength": 160},
            "startUnitId": {"type": "string", "minLength": 1, "maxLength": 160},
            "endUnitId": {"type": "string", "minLength": 1, "maxLength": 160},
            "boundaryRefinement": {
                "type": "string",
                "enum": sorted(REFINEMENT_VALUES),
            },
        },
        [
            "occurrenceId",
            "sourceId",
            "startUnitId",
            "endUnitId",
            "boundaryRefinement",
        ],
    )
    variant = _strict_object(
        {
            "variantId": {"type": "string", "minLength": 1, "maxLength": 160},
            "label": {"type": "string", "minLength": 1, "maxLength": 240},
            "confidence": {"type": "string", "enum": sorted(CONFIDENCE_VALUES)},
            "reason": {"type": "string", "minLength": 1, "maxLength": 1000},
            "relations": {"type": "array", "items": relation, "maxItems": 100},
            "occurrences": {
                "type": "array",
                "items": occurrence,
                "minItems": 1,
                "maxItems": 10000,
            },
        },
        ["variantId", "label", "confidence", "reason", "relations", "occurrences"],
    )
    block = _strict_object(
        {
            "blockId": {"type": "string", "minLength": 1, "maxLength": 160},
            "label": {"type": "string", "minLength": 1, "maxLength": 240},
            "variants": {
                "type": "array",
                "items": variant,
                "minItems": 1,
                "maxItems": 1000,
            },
        },
        ["blockId", "label", "variants"],
    )
    range_properties = {
        "sourceId": {"type": "string", "minLength": 1, "maxLength": 160},
        "startUnitId": {"type": "string", "minLength": 1, "maxLength": 160},
        "endUnitId": {"type": "string", "minLength": 1, "maxLength": 160},
        "reason": {"type": "string", "minLength": 1, "maxLength": 1000},
    }
    exclusion = _strict_object(
        range_properties,
        ["sourceId", "startUnitId", "endUnitId", "reason"],
    )
    unassigned = _strict_object(
        {
            "unassignedId": {"type": "string", "minLength": 1, "maxLength": 160},
            **range_properties,
            "confidence": {"type": "string", "enum": sorted(CONFIDENCE_VALUES)},
        },
        [
            "unassignedId",
            "sourceId",
            "startUnitId",
            "endUnitId",
            "reason",
            "confidence",
        ],
    )
    return _strict_object(
        {
            "contractVersion": {"type": "integer", "const": CONTRACT_VERSION},
            "blocks": {"type": "array", "items": block, "maxItems": 10000},
            "technicalExclusions": {
                "type": "array",
                "items": exclusion,
                "maxItems": 10000,
            },
            "unassignedReview": {
                "type": "array",
                "items": unassigned,
                "maxItems": 10000,
            },
        },
        ["contractVersion", "blocks", "technicalExclusions", "unassignedReview"],
    )


def boundary_response_schema() -> dict[str, Any]:
    item = _strict_object(
        {
            "occurrenceId": {"type": "string", "minLength": 1, "maxLength": 160},
            "startWordId": {"type": "string", "minLength": 1, "maxLength": 160},
            "endWordId": {"type": "string", "minLength": 1, "maxLength": 160},
        },
        ["occurrenceId", "startWordId", "endWordId"],
    )
    return _strict_object(
        {
            "contractVersion": {"type": "integer", "const": CONTRACT_VERSION},
            "boundaries": {
                "type": "array",
                "items": item,
                "minItems": 1,
                "maxItems": 200000,
            },
        },
        ["contractVersion", "boundaries"],
    )


def global_agent_request(session: PreparedSession) -> dict[str, Any]:
    payload = request_payload(session)
    return {
        "contractVersion": CONTRACT_VERSION,
        "systemPrompt": (
            "You are an expert Premiere Pro story editor. Return one structured "
            "comparison proposal, not a winner-only cut. Use only issued IDs. "
            "Track alternatives are local to each block. Reuse is allowed when it "
            "improves a construction. Omissions are allowed for false starts, "
            "slates, corrections, or material that does not help the proposal. "
            "Do not exclude a passage only because it is short: keep brief starts "
            "or fragments when they can connect cleanly to another occurrence or "
            "strengthen a useful construction. Exclude only clearly abandoned or "
            "editorially unusable starts, and put ambiguous fragments in "
            "unassignedReview. "
            "Honor editorContext when it provides project-specific pacing or "
            "take-handling guidance. A unit may include pauseBeforeSeconds when "
            "there was significant silence before it. Treat that pause as "
            "evidence, never as a mandatory cut: it may indicate a restart, "
            "correction, separate take, reflection, or an intentional dramatic "
            "pause. Pay particular attention when similar wording appears on "
            "both sides of a significant pause. Do not place an abandoned attempt "
            "followed by its restarted version consecutively in one variant unless "
            "the repetition is clearly intentional. Prioritize editorial coherence, "
            "completeness, and clean connections when ordering a block's variants. "
            "When variants are otherwise similarly useful, return the construction "
            "using the later recorded take first so it appears on the lowest track. "
            "Treat recency only as a practical review tie-breaker, never as proof of "
            "higher quality, and honor contrary guidance in editorContext. "
            "Never return timestamps, paths, Premiere references, or rewritten "
            "transcript text. Mark START, END, or BOTH boundary refinement only "
            "when a full issued unit would include unwanted neighboring speech."
        ),
        "userPrompt": (
            "Analyze the complete session globally and return JSON matching the "
            "provided schema.\n\nSESSION:\n" + canonical_json(payload)
        ),
        "outputSchemaJson": canonical_json(global_response_schema()),
        "providerProfile": profile_request(payload),
    }


def boundary_agent_request(
    session: PreparedSession,
    validated: dict[str, Any],
) -> dict[str, Any] | None:
    requests = validated["boundaryRefinementRequests"]
    if not requests:
        return None
    sources, _, _ = _indices(session)
    issued = []
    for request in requests:
        source = sources[request["sourceId"]]
        units = _range(
            source.source_id,
            request["startUnitId"],
            request["endUnitId"],
            source,
        )
        source_word_ids = [word.word_id for word in source.words]
        start = source_word_ids.index(units[0].start_word_id)
        end = source_word_ids.index(units[-1].end_word_id)
        issued.append(
            {
                **request,
                "words": [
                    {"wordId": word.word_id, "text": word.text}
                    for word in source.words[start : end + 1]
                ],
            }
        )
    return {
        "contractVersion": CONTRACT_VERSION,
        "systemPrompt": (
            "Resolve only the requested inclusive word boundaries. Return every "
            "issued occurrence exactly once. Use only its issued word IDs, keep "
            "source order, and do not change an edge that was not requested."
        ),
        "userPrompt": "BOUNDARY REQUESTS:\n" + canonical_json(issued),
        "outputSchemaJson": canonical_json(boundary_response_schema()),
    }


def timing_sidecar(session: PreparedSession) -> dict[str, Any]:
    return {
        "contractVersion": CONTRACT_VERSION,
        "orderMode": session.order_mode,
        "orderWarnings": list(session.order_warnings),
        "sources": [
            {
                "sourceId": source.source_id,
                "sourceOrder": source.source_order,
                "selectionIndex": source.selection_index,
                "language": source.language,
                "durationMs": source.duration_ms,
                "hasVideo": source.has_video,
                "hasAudio": source.has_audio,
                "words": [
                    {
                        "wordId": word.word_id,
                        "text": word.text,
                        "startMs": word.start_ms,
                        "endMs": word.end_ms,
                    }
                    for word in source.words
                ],
                "units": [
                    {
                        "unitId": unit.unit_id,
                        "text": unit.text,
                        "startWordId": unit.start_word_id,
                        "endWordId": unit.end_word_id,
                        "startMs": unit.start_ms,
                        "endMs": unit.end_ms,
                    }
                    for unit in source.units
                ],
            }
            for source in session.sources
        ],
    }


def session_from_sidecar(sidecar: dict[str, Any]) -> PreparedSession:
    if sidecar.get("contractVersion") != CONTRACT_VERSION:
        raise ValueError("Timing sidecar contractVersion is unsupported.")
    sources: list[Source] = []
    for source in sidecar.get("sources", []):
        source_id = source["sourceId"]
        words = tuple(
            Word(
                word_id=item["wordId"],
                source_id=source_id,
                text=item["text"],
                start_ms=item["startMs"],
                end_ms=item["endMs"],
            )
            for item in source["words"]
        )
        units = tuple(
            Unit(
                unit_id=item["unitId"],
                source_id=source_id,
                text=item["text"],
                start_word_id=item["startWordId"],
                end_word_id=item["endWordId"],
                start_ms=item["startMs"],
                end_ms=item["endMs"],
            )
            for item in source["units"]
        )
        sources.append(
            Source(
                source_id=source_id,
                source_order=source["sourceOrder"],
                selection_index=source["selectionIndex"],
                language=source.get("language", ""),
                duration_ms=source["durationMs"],
                has_video=source["hasVideo"],
                has_audio=source["hasAudio"],
                words=words,
                units=units,
            )
        )
    return PreparedSession(
        contract_version=CONTRACT_VERSION,
        order_mode=sidecar["orderMode"],
        order_warnings=tuple(sidecar.get("orderWarnings", [])),
        editor_context="",
        sources=tuple(sources),
    )


def _indices(session: PreparedSession) -> tuple[dict[str, Source], dict[str, Unit], dict[str, Word]]:
    sources = {item.source_id: item for item in session.sources}
    units = {item.unit_id: item for source in session.sources for item in source.units}
    words = {item.word_id: item for source in session.sources for item in source.words}
    return sources, units, words


@lru_cache(maxsize=None)
def _unit_positions(source: Source) -> dict[str, int]:
    return {unit.unit_id: index for index, unit in enumerate(source.units)}


def _range(
    source_id: str,
    start_unit_id: str,
    end_unit_id: str,
    source: Source,
) -> tuple[Unit, ...]:
    if source_id != source.source_id:
        raise ValueError("Range source does not match its sourceId.")
    positions = _unit_positions(source)
    if start_unit_id not in positions or end_unit_id not in positions:
        raise ValueError(f"Unknown unit ID in range {start_unit_id}..{end_unit_id}.")
    start = positions[start_unit_id]
    end = positions[end_unit_id]
    if end < start:
        raise ValueError(f"Reversed unit range {start_unit_id}..{end_unit_id}.")
    return source.units[start : end + 1]


def _range_record(
    value: Any,
    label: str,
    sources: dict[str, Source],
) -> tuple[str, tuple[Unit, ...]]:
    if not isinstance(value, dict):
        raise ValueError(f"{label} must be an object.")
    source_id = value.get("sourceId")
    if source_id not in sources:
        raise ValueError(f"{label} references unknown sourceId {source_id!r}.")
    return source_id, _range(
        source_id,
        value.get("startUnitId"),
        value.get("endUnitId"),
        sources[source_id],
    )


def validate_response(session: PreparedSession, response: dict[str, Any]) -> dict[str, Any]:
    if response.get("contractVersion") != CONTRACT_VERSION:
        raise ValueError("Semantic response contractVersion is unsupported.")
    sources, _, _ = _indices(session)
    blocks = response.get("blocks")
    if not isinstance(blocks, list):
        raise ValueError("Semantic response blocks must be a list.")
    if len(blocks) > 10_000:
        raise ValueError("Semantic response exceeds the structural block limit.")
    seen_blocks: set[str] = set()
    seen_variants: set[str] = set()
    seen_occurrences: set[str] = set()
    occurrence_uses: dict[str, list[dict[str, str]]] = {
        unit.unit_id: [] for source in session.sources for unit in source.units
    }
    total_variants = 0
    total_occurrences = 0
    refinement_requests: list[dict[str, Any]] = []
    for block_index, block in enumerate(blocks):
        if not isinstance(block, dict):
            raise ValueError(f"Block {block_index} must be an object.")
        block_id = _safe_text(block.get("blockId"), "blockId")
        if block_id in seen_blocks:
            raise ValueError(f"Duplicate blockId: {block_id}.")
        seen_blocks.add(block_id)
        _safe_text(block.get("label"), f"{block_id}.label")
        variants = block.get("variants")
        if not isinstance(variants, list) or not variants:
            raise ValueError(f"Block {block_id} must contain variants.")
        block_variant_ids: set[str] = set()
        for variant_index, variant in enumerate(variants):
            if not isinstance(variant, dict):
                raise ValueError(f"Variant {block_id}[{variant_index}] must be an object.")
            variant_id = _safe_text(variant.get("variantId"), "variantId")
            if variant_id in seen_variants:
                raise ValueError(f"Duplicate variantId: {variant_id}.")
            seen_variants.add(variant_id)
            block_variant_ids.add(variant_id)
            total_variants += 1
            _safe_text(variant.get("label"), f"{variant_id}.label")
            if variant.get("confidence") not in CONFIDENCE_VALUES:
                raise ValueError(f"Variant {variant_id} has invalid confidence.")
            _safe_text(variant.get("reason"), f"{variant_id}.reason")
            occurrences = variant.get("occurrences")
            if not isinstance(occurrences, list) or not occurrences:
                raise ValueError(f"Variant {variant_id} must contain occurrences.")
            for occurrence in occurrences:
                occurrence_id = _safe_text(occurrence.get("occurrenceId"), "occurrenceId")
                if occurrence_id in seen_occurrences:
                    raise ValueError(f"Duplicate occurrenceId: {occurrence_id}.")
                seen_occurrences.add(occurrence_id)
                total_occurrences += 1
                source_id, units = _range_record(
                    occurrence, occurrence_id, sources
                )
                refinement = occurrence.get("boundaryRefinement", "NONE")
                if refinement not in REFINEMENT_VALUES:
                    raise ValueError(
                        f"Occurrence {occurrence_id} has invalid boundaryRefinement."
                    )
                if refinement != "NONE":
                    refinement_requests.append(
                        {
                            "occurrenceId": occurrence_id,
                            "sourceId": source_id,
                            "startUnitId": units[0].unit_id,
                            "endUnitId": units[-1].unit_id,
                            "boundaryRefinement": refinement,
                        }
                    )
                for unit in units:
                    occurrence_uses[unit.unit_id].append(
                        {
                            "blockId": block_id,
                            "variantId": variant_id,
                            "occurrenceId": occurrence_id,
                        }
                    )
        for variant in variants:
            relations = variant.get("relations", [])
            if not isinstance(relations, list):
                raise ValueError(f"Variant {variant['variantId']} relations must be a list.")
            for relation in relations:
                if not isinstance(relation, dict) or relation.get("type") not in RELATION_TYPES:
                    raise ValueError(f"Variant {variant['variantId']} has an invalid relation.")
                target = relation.get("targetVariantId")
                if target not in block_variant_ids:
                    raise ValueError(
                        f"Relation target {target!r} is not in block {block_id}."
                    )
                _safe_text(relation.get("reason"), "relation.reason")
    if total_variants > 50_000 or total_occurrences > 200_000:
        raise ValueError("Semantic response exceeds structural resource-safety limits.")

    exclusions: dict[str, list[str]] = {
        unit_id: [] for unit_id in occurrence_uses
    }
    technical_exclusions = response.get("technicalExclusions", [])
    if not isinstance(technical_exclusions, list):
        raise ValueError("technicalExclusions must be a list.")
    for index, item in enumerate(technical_exclusions):
        source_id, units = _range_record(item, f"technicalExclusions[{index}]", sources)
        reason = _safe_text(item.get("reason"), "technicalExclusion.reason")
        for unit in units:
            exclusions[unit.unit_id].append(f"{source_id}:{reason}")
    unassigned: dict[str, list[str]] = {
        unit_id: [] for unit_id in occurrence_uses
    }
    unassigned_items = response.get("unassignedReview", [])
    if not isinstance(unassigned_items, list):
        raise ValueError("unassignedReview must be a list.")
    seen_unassigned: set[str] = set()
    for index, item in enumerate(unassigned_items):
        unassigned_id = _safe_text(item.get("unassignedId"), "unassignedId")
        if unassigned_id in seen_unassigned:
            raise ValueError(f"Duplicate unassignedId: {unassigned_id}.")
        seen_unassigned.add(unassigned_id)
        _, units = _range_record(item, f"unassignedReview[{index}]", sources)
        _safe_text(item.get("reason"), "unassignedReview.reason")
        if item.get("confidence") not in CONFIDENCE_VALUES:
            raise ValueError(f"Unassigned item {unassigned_id} has invalid confidence.")
        for unit in units:
            unassigned[unit.unit_id].append(unassigned_id)

    coverage = []
    for source in session.sources:
        for unit in source.units:
            statuses: list[str] = []
            if occurrence_uses[unit.unit_id]:
                statuses.append("PLACED")
            if exclusions[unit.unit_id]:
                statuses.append("TECHNICAL_EXCLUDE")
            if unassigned[unit.unit_id]:
                statuses.append("UNASSIGNED_REVIEW")
            if not statuses:
                statuses.append("NOT_SELECTED_BY_AGENT")
            coverage.append(
                {
                    "sourceId": source.source_id,
                    "unitId": unit.unit_id,
                    "statuses": statuses,
                    "placementUses": occurrence_uses[unit.unit_id],
                    "technicalExclusions": exclusions[unit.unit_id],
                    "unassignedUses": unassigned[unit.unit_id],
                }
            )
    return {
        "contractVersion": CONTRACT_VERSION,
        "response": response,
        "coverage": coverage,
        "boundaryRefinementRequests": refinement_requests,
        "counts": {
            "blockCount": len(blocks),
            "variantCount": total_variants,
            "occurrenceCount": total_occurrences,
            "omittedUnitCount": sum(
                item["statuses"] == ["NOT_SELECTED_BY_AGENT"] for item in coverage
            ),
            "reusedUnitCount": sum(
                len(item["placementUses"]) > 1 for item in coverage
            ),
            "unassignedUnitCount": sum(
                bool(item["unassignedUses"]) for item in coverage
            ),
            "technicalExclusionCount": len(technical_exclusions),
        },
    }


def validate_boundary_response(
    session: PreparedSession,
    validated: dict[str, Any],
    response: dict[str, Any] | None,
) -> dict[str, tuple[str, str]]:
    requests = {
        item["occurrenceId"]: item
        for item in validated["boundaryRefinementRequests"]
    }
    if not requests:
        if response not in (None, {}, {"contractVersion": CONTRACT_VERSION, "boundaries": []}):
            raise ValueError("Boundary response was supplied without refinement requests.")
        return {}
    if not isinstance(response, dict) or response.get("contractVersion") != CONTRACT_VERSION:
        raise ValueError("Boundary response contractVersion is unsupported.")
    boundaries = response.get("boundaries")
    if not isinstance(boundaries, list):
        raise ValueError("Boundary response boundaries must be a list.")
    _, units, words = _indices(session)
    resolved: dict[str, tuple[str, str]] = {}
    for item in boundaries:
        occurrence_id = item.get("occurrenceId")
        if occurrence_id not in requests or occurrence_id in resolved:
            raise ValueError(f"Unexpected or duplicate boundary result: {occurrence_id!r}.")
        request = requests[occurrence_id]
        source = next(source for source in session.sources if source.source_id == request["sourceId"])
        selected_units = _range(
            source.source_id,
            request["startUnitId"],
            request["endUnitId"],
            source,
        )
        source_word_ids = [word.word_id for word in source.words]
        allowed_start = source_word_ids.index(selected_units[0].start_word_id)
        allowed_end = source_word_ids.index(selected_units[-1].end_word_id)
        start_word_id = item.get("startWordId")
        end_word_id = item.get("endWordId")
        if start_word_id not in words or end_word_id not in words:
            raise ValueError(f"Boundary result {occurrence_id} contains unknown word IDs.")
        start = source_word_ids.index(start_word_id) if start_word_id in source_word_ids else -1
        end = source_word_ids.index(end_word_id) if end_word_id in source_word_ids else -1
        if start < allowed_start or end > allowed_end or end < start:
            raise ValueError(f"Boundary result {occurrence_id} escapes its issued unit range.")
        mode = request["boundaryRefinement"]
        if mode not in {"START", "BOTH"} and start != allowed_start:
            raise ValueError(f"Boundary result {occurrence_id} changed an unrequested start.")
        if mode not in {"END", "BOTH"} and end != allowed_end:
            raise ValueError(f"Boundary result {occurrence_id} changed an unrequested end.")
        resolved[occurrence_id] = (start_word_id, end_word_id)
    if set(resolved) != set(requests):
        missing = sorted(set(requests) - set(resolved))
        raise ValueError(f"Boundary response omitted requested occurrences: {missing}.")
    return resolved


def build_timeline(
    session: PreparedSession,
    validated: dict[str, Any],
    *,
    boundary_response: dict[str, Any] | None = None,
    handle_before_ms: int = DEFAULT_HANDLE_BEFORE_MS,
    handle_after_ms: int = DEFAULT_HANDLE_AFTER_MS,
    block_gap_ms: int = DEFAULT_BLOCK_GAP_MS,
    review_gap_ms: int = DEFAULT_REVIEW_GAP_MS,
) -> dict[str, Any]:
    for value, label in (
        (handle_before_ms, "handleBeforeMs"),
        (handle_after_ms, "handleAfterMs"),
        (block_gap_ms, "blockGapMs"),
        (review_gap_ms, "reviewGapMs"),
    ):
        _positive_int(value, label, allow_zero=True)
    sources, _, words = _indices(session)
    resolved = validate_boundary_response(session, validated, boundary_response)
    response = validated["response"]
    placements: list[dict[str, Any]] = []
    markers: list[dict[str, Any]] = []
    blocks_out: list[dict[str, Any]] = []
    cursor = 0
    max_video_lane = -1
    max_audio_lane = -1
    for block_index, block in enumerate(response["blocks"]):
        block_start = cursor if block_index == 0 else cursor + block_gap_ms
        variant_rows: list[dict[str, Any]] = []
        block_duration = 0
        video_lanes: dict[str, int] = {}
        audio_lanes: dict[str, int] = {}
        for variant in block["variants"]:
            variant_sources = [
                sources[occurrence["sourceId"]]
                for occurrence in variant["occurrences"]
            ]
            if any(source.has_video for source in variant_sources):
                video_lanes[variant["variantId"]] = len(video_lanes)
            if any(source.has_audio for source in variant_sources):
                audio_lanes[variant["variantId"]] = len(audio_lanes)
        for lane_index, variant in enumerate(block["variants"]):
            video_lane = video_lanes.get(variant["variantId"])
            audio_lane = audio_lanes.get(variant["variantId"])
            variant_cursor = 0
            occurrence_rows: list[dict[str, Any]] = []
            for occurrence in variant["occurrences"]:
                source = sources[occurrence["sourceId"]]
                selected_units = _range(
                    source.source_id,
                    occurrence["startUnitId"],
                    occurrence["endUnitId"],
                    source,
                )
                start_word_id, end_word_id = resolved.get(
                    occurrence["occurrenceId"],
                    (selected_units[0].start_word_id, selected_units[-1].end_word_id),
                )
                speech_in = words[start_word_id].start_ms
                speech_out = words[end_word_id].end_ms
                source_in = max(0, speech_in - handle_before_ms)
                source_out = min(source.duration_ms, speech_out + handle_after_ms)
                duration = source_out - source_in
                sequence_start = block_start + variant_cursor
                row = {
                    "blockId": block["blockId"],
                    "variantId": variant["variantId"],
                    "occurrenceId": occurrence["occurrenceId"],
                    "sourceId": source.source_id,
                    "laneIndex": lane_index,
                    "videoTrackIndex": video_lane if source.has_video else None,
                    "audioTrackIndex": audio_lane if source.has_audio else None,
                    "sequenceStartMs": sequence_start,
                    "sourceInMs": source_in,
                    "sourceOutMs": source_out,
                    "speechInMs": speech_in,
                    "speechOutMs": speech_out,
                    "durationMs": duration,
                }
                occurrence_rows.append(row)
                placements.append(row)
                if occurrence["occurrenceId"] in resolved:
                    markers.append(
                        {
                            "markerId": f"marker.boundary.{occurrence['occurrenceId']}",
                            "kind": "REFINED_BOUNDARY",
                            "sequenceStartMs": sequence_start,
                            "durationMs": max(duration, 1),
                            "name": "AA-SRS · Refined transcript boundary",
                            "comment": (
                                "Workflow AI selected a partial-unit word boundary; "
                                "review the edit point."
                            ),
                        }
                    )
                if source.has_video:
                    assert video_lane is not None
                    max_video_lane = max(max_video_lane, video_lane)
                if source.has_audio:
                    assert audio_lane is not None
                    max_audio_lane = max(max_audio_lane, audio_lane)
                variant_cursor += duration
            variant_rows.append(
                {
                    "variantId": variant["variantId"],
                    "laneIndex": lane_index,
                    "durationMs": variant_cursor,
                    "occurrences": occurrence_rows,
                }
            )
            block_duration = max(block_duration, variant_cursor)
            for relation_index, relation in enumerate(variant.get("relations", [])):
                if relation["type"] not in {"QUALIFIES", "CONFLICTS_WITH"}:
                    continue
                markers.append(
                    {
                        "markerId": (
                            f"marker.relation.{variant['variantId']}.{relation_index}"
                        ),
                        "kind": relation["type"],
                        "sequenceStartMs": block_start,
                        "durationMs": max(variant_cursor, 1),
                        "name": f"AA-SRS · {relation['type'].replace('_', ' ').title()}",
                        "comment": relation["reason"],
                    }
                )
            if variant["confidence"] == "LOW":
                markers.append(
                    {
                        "markerId": f"marker.variant.{variant['variantId']}",
                        "kind": "LOW_CONFIDENCE_VARIANT",
                        "sequenceStartMs": block_start,
                        "durationMs": max(variant_cursor, 1),
                        "name": f"AA-SRS · Review {variant['label']}",
                        "comment": variant["reason"],
                    }
                )
        blocks_out.append(
            {
                "blockId": block["blockId"],
                "timelineStartMs": block_start,
                "durationMs": block_duration,
                "timelineEndMs": block_start + block_duration,
                "variants": variant_rows,
            }
        )
        cursor = block_start + block_duration

    unassigned_start = cursor + review_gap_ms if response.get("unassignedReview") else cursor
    review_cursor = unassigned_start
    for item in response.get("unassignedReview", []):
        source = sources[item["sourceId"]]
        selected_units = _range(
            source.source_id,
            item["startUnitId"],
            item["endUnitId"],
            source,
        )
        speech_in = selected_units[0].start_ms
        speech_out = selected_units[-1].end_ms
        source_in = max(0, speech_in - handle_before_ms)
        source_out = min(source.duration_ms, speech_out + handle_after_ms)
        duration = source_out - source_in
        row = {
            "blockId": "unassigned-review",
            "variantId": "unassigned-review.v1",
            "occurrenceId": item["unassignedId"],
            "sourceId": source.source_id,
            "laneIndex": 0,
            "videoTrackIndex": 0 if source.has_video else None,
            "audioTrackIndex": 0 if source.has_audio else None,
            "sequenceStartMs": review_cursor,
            "sourceInMs": source_in,
            "sourceOutMs": source_out,
            "speechInMs": speech_in,
            "speechOutMs": speech_out,
            "durationMs": duration,
        }
        placements.append(row)
        max_video_lane = max(max_video_lane, 0 if source.has_video else -1)
        max_audio_lane = max(max_audio_lane, 0 if source.has_audio else -1)
        markers.append(
            {
                "markerId": f"marker.unassigned.{item['unassignedId']}",
                "kind": "UNASSIGNED_REVIEW",
                "sequenceStartMs": review_cursor,
                "durationMs": max(duration, 1),
                "name": "AA-SRS · Unassigned review",
                "comment": item["reason"],
            }
        )
        review_cursor += duration

    _validate_track_non_overlap(placements, "videoTrackIndex")
    _validate_track_non_overlap(placements, "audioTrackIndex")
    _validate_track_contiguity(placements, "videoTrackIndex")
    _validate_track_contiguity(placements, "audioTrackIndex")
    placements.sort(
        key=lambda row: (
            row["sequenceStartMs"],
            row["laneIndex"],
            row["occurrenceId"],
        )
    )
    return {
        "contractVersion": CONTRACT_VERSION,
        "blocks": blocks_out,
        "placements": placements,
        "markers": markers,
        "coverage": validated["coverage"],
        "summary": {
            **validated["counts"],
            "placementCount": len(placements),
            "markerCount": len(markers),
            "maxVideoLaneIndex": max_video_lane,
            "maxAudioLaneIndex": max_audio_lane,
            "orderMode": session.order_mode,
            "handleBeforeMs": handle_before_ms,
            "handleAfterMs": handle_after_ms,
            "blockGapMs": block_gap_ms,
            "reviewGapMs": review_gap_ms,
            "storyEndMs": cursor,
            "reviewStartMs": unassigned_start,
            "sequenceEndMs": max(cursor, review_cursor),
        },
    }


def _validate_track_non_overlap(rows: list[dict[str, Any]], field: str) -> None:
    by_track: dict[int, list[tuple[int, int, str]]] = {}
    for row in rows:
        track = row[field]
        if track is None:
            continue
        by_track.setdefault(track, []).append(
            (
                row["sequenceStartMs"],
                row["sequenceStartMs"] + row["durationMs"],
                row["occurrenceId"],
            )
        )
    for track, intervals in by_track.items():
        intervals.sort()
        for previous, current in zip(intervals, intervals[1:]):
            if current[0] < previous[1]:
                raise ValueError(
                    f"Same-track overlap on {field} {track}: "
                    f"{previous[2]} and {current[2]}."
                )


def _validate_track_contiguity(rows: list[dict[str, Any]], field: str) -> None:
    by_block: dict[str, set[int]] = {}
    for row in rows:
        track = row[field]
        if track is not None:
            by_block.setdefault(row["blockId"], set()).add(track)
    for block_id, tracks in by_block.items():
        expected = set(range(max(tracks) + 1))
        if tracks != expected:
            raise ValueError(
                f"{field} values for {block_id} must be contiguous from zero; "
                f"received {sorted(tracks)}."
            )


def _write_json(path: Path, value: Any) -> None:
    path.write_text(canonical_json(value) + "\n", encoding="utf-8")


def _placement_control_rows(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
    return [
        {
            "blockId": row["blockId"],
            "variantId": row["variantId"],
            "occurrenceId": row["occurrenceId"],
            "sourceId": row["sourceId"],
            "laneIndex": row["laneIndex"],
            "videoTrackIndex": row["videoTrackIndex"],
            "audioTrackIndex": row["audioTrackIndex"],
            "sequenceStartSeconds": f"{row['sequenceStartMs'] / 1000:.3f}",
            "sourceInSeconds": f"{row['sourceInMs'] / 1000:.3f}",
            "sourceOutSeconds": f"{row['sourceOutMs'] / 1000:.3f}",
            "speechInSeconds": f"{row['speechInMs'] / 1000:.3f}",
            "speechOutSeconds": f"{row['speechOutMs'] / 1000:.3f}",
            "durationSeconds": f"{row['durationMs'] / 1000:.3f}",
        }
        for row in rows
    ]


def _marker_control_rows(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
    return [
        {
            "markerId": row["markerId"],
            "kind": row["kind"],
            "sequenceStartSeconds": f"{row['sequenceStartMs'] / 1000:.3f}",
            "durationSeconds": f"{row['durationMs'] / 1000:.3f}",
            "name": row["name"],
            "comment": row["comment"],
        }
        for row in rows
    ]


def _summary_control_rows(summary: dict[str, Any]) -> list[dict[str, Any]]:
    return [
        {
            "blockCount": summary["blockCount"],
            "variantCount": summary["variantCount"],
            "occurrenceCount": summary["occurrenceCount"],
            "omittedUnitCount": summary["omittedUnitCount"],
            "reusedUnitCount": summary["reusedUnitCount"],
            "unassignedUnitCount": summary["unassignedUnitCount"],
            "technicalExclusionCount": summary["technicalExclusionCount"],
            "placementCount": summary["placementCount"],
            "markerCount": summary["markerCount"],
            "maxVideoLaneIndex": summary["maxVideoLaneIndex"],
            "maxAudioLaneIndex": summary["maxAudioLaneIndex"],
            "orderMode": summary["orderMode"],
            "handleBeforeSeconds": f"{summary['handleBeforeMs'] / 1000:.3f}",
            "handleAfterSeconds": f"{summary['handleAfterMs'] / 1000:.3f}",
            "blockGapSeconds": f"{summary['blockGapMs'] / 1000:.3f}",
            "reviewGapSeconds": f"{summary['reviewGapMs'] / 1000:.3f}",
            "storyEndSeconds": f"{summary['storyEndMs'] / 1000:.3f}",
            "reviewStartSeconds": f"{summary['reviewStartMs'] / 1000:.3f}",
            "sequenceEndSeconds": f"{summary['sequenceEndMs'] / 1000:.3f}",
        }
    ]


def _manifest_from_tsv(path: Path, editor_context: str) -> dict[str, Any]:
    expected = (
        "sourceId",
        "selectionIndex",
        "captureDateRaw",
        "durationSeconds",
        "hasVideo",
        "hasAudio",
        "transcriptPath",
    )
    with path.open(encoding="utf-8", newline="") as handle:
        reader = csv.DictReader(handle, dialect="excel-tab")
        rows = list(reader)
    if tuple(reader.fieldnames or ()) != expected or not rows:
        raise ValueError("Session TSV header is invalid or contains no sources.")
    sources = []
    for index, row in enumerate(rows):
        try:
            duration_ms = int(round(float(row["durationSeconds"]) * 1000))
        except ValueError as error:
            raise ValueError(f"Session TSV row {index + 2} duration is invalid.") from error
        sources.append(
            {
                "sourceId": row["sourceId"],
                "selectionIndex": int(row["selectionIndex"]),
                "captureDateRaw": row["captureDateRaw"],
                "durationMs": duration_ms,
                "hasVideo": row["hasVideo"].strip().lower() == "true",
                "hasAudio": row["hasAudio"].strip().lower() == "true",
                "transcriptPath": row["transcriptPath"],
            }
        )
    return {
        "contractVersion": CONTRACT_VERSION,
        "editorContext": editor_context,
        "sources": sources,
    }


def _tsv_value(field: str, value: Any, none_as_minus_one: set[str]) -> str:
    if value is None:
        return "-1" if field in none_as_minus_one else ""
    return str(value)


def _write_tsv(
    path: Path,
    rows: list[dict[str, Any]],
    fields: tuple[str, ...],
    *,
    none_as_minus_one: set[str] | None = None,
) -> None:
    minus_one_fields = none_as_minus_one or set()
    with path.open("w", encoding="utf-8", newline="") as handle:
        writer = csv.DictWriter(handle, fieldnames=fields, dialect="excel-tab")
        writer.writeheader()
        for row in rows:
            if set(row) != set(fields):
                raise ValueError(f"TSV row fields do not match {path.name} contract.")
            writer.writerow(
                {
                    field: _tsv_value(field, row[field], minus_one_fields)
                    for field in fields
                }
            )
    _validate_tsv(path, rows, fields, none_as_minus_one=minus_one_fields)


def _validate_tsv(
    path: Path,
    expected_rows: list[dict[str, Any]],
    fields: tuple[str, ...],
    *,
    none_as_minus_one: set[str],
) -> None:
    with path.open(encoding="utf-8", newline="") as handle:
        reader = csv.DictReader(handle, dialect="excel-tab")
        actual_rows = list(reader)
    if tuple(reader.fieldnames or ()) != fields:
        raise ValueError(f"{path.name} header does not match its frozen contract.")
    expected = [
        {
            field: _tsv_value(field, row[field], none_as_minus_one)
            for field in fields
        }
        for row in expected_rows
    ]
    if actual_rows != expected:
        raise ValueError(f"{path.name} rows do not match the validated analysis.")


def _prepare_command(args: argparse.Namespace) -> None:
    session_path = Path(args.session or args.session_tsv).resolve()
    editor_context = (
        Path(args.editor_context_file)
        .resolve()
        .read_text(encoding="utf-8")
        .strip()
        if args.editor_context_file
        else args.editor_context or ""
    )
    manifest = (
        json.loads(session_path.read_text(encoding="utf-8"))
        if args.session
        else _manifest_from_tsv(session_path, editor_context)
    )
    session = prepare_session(
        manifest,
        base_dir=session_path.parent,
        srt_toolkit_dir=Path(args.srt_toolkit_dir).resolve() if args.srt_toolkit_dir else None,
    )
    output = Path(args.output_dir).resolve()
    output.mkdir(parents=True, exist_ok=True)
    payload = request_payload(session)
    agent_request = global_agent_request(session)
    _write_json(output / "request.json", payload)
    _write_json(output / "global-agent-request.json", agent_request)
    _write_json(output / "global-output-schema.json", global_response_schema())
    (output / "global-system-prompt.txt").write_text(
        agent_request["systemPrompt"], encoding="utf-8"
    )
    (output / "global-user-prompt.txt").write_text(
        agent_request["userPrompt"], encoding="utf-8"
    )
    _write_json(output / "timing-sidecar.json", timing_sidecar(session))
    _write_json(output / "provider-profile.json", profile_request(payload))


def _validate_command(args: argparse.Namespace) -> None:
    sidecar = json.loads(Path(args.sidecar).read_text(encoding="utf-8"))
    response = json.loads(Path(args.response).read_text(encoding="utf-8"))
    session = session_from_sidecar(sidecar)
    validated = validate_response(session, response)
    output = Path(args.output_dir).resolve()
    output.mkdir(parents=True, exist_ok=True)
    _write_json(output / "validated-global-response.json", validated)
    boundary_request = boundary_agent_request(session, validated)
    if boundary_request is not None:
        _write_json(output / "boundary-agent-request.json", boundary_request)
        _write_json(output / "boundary-output-schema.json", boundary_response_schema())
        (output / "boundary-system-prompt.txt").write_text(
            boundary_request["systemPrompt"], encoding="utf-8"
        )
        (output / "boundary-user-prompt.txt").write_text(
            boundary_request["userPrompt"], encoding="utf-8"
        )


def _seconds_to_ms(value: float, label: str) -> int:
    if not math.isfinite(value) or value < 0:
        raise ValueError(f"{label} must be a finite non-negative number.")
    return round(value * 1000)


def _plan_command(args: argparse.Namespace) -> None:
    sidecar = json.loads(Path(args.sidecar).read_text(encoding="utf-8"))
    response = json.loads(Path(args.response).read_text(encoding="utf-8"))
    session = session_from_sidecar(sidecar)
    validated = validate_response(session, response)
    boundary = (
        json.loads(Path(args.boundary_response).read_text(encoding="utf-8"))
        if args.boundary_response
        else None
    )
    analysis = build_timeline(
        session,
        validated,
        boundary_response=boundary,
        handle_before_ms=_seconds_to_ms(
            args.handle_before_seconds,
            "handleBeforeSeconds",
        ),
        handle_after_ms=_seconds_to_ms(
            args.handle_after_seconds,
            "handleAfterSeconds",
        ),
        block_gap_ms=_seconds_to_ms(
            args.block_gap_seconds,
            "blockGapSeconds",
        ),
    )
    output = Path(args.output_dir).resolve()
    output.mkdir(parents=True, exist_ok=True)
    _write_json(output / "analysis.json", analysis)
    _write_json(output / "coverage.json", analysis["coverage"])
    _write_json(output / "summary.json", analysis["summary"])
    placement_rows = _placement_control_rows(analysis["placements"])
    _write_tsv(
        output / "placements.tsv",
        placement_rows,
        PLACEMENT_COLUMNS,
        none_as_minus_one={"videoTrackIndex", "audioTrackIndex"},
    )
    _write_tsv(
        output / "markers.tsv",
        _marker_control_rows(analysis["markers"]),
        MARKER_COLUMNS,
    )
    _write_tsv(
        output / "coverage.tsv",
        [
            {
                "sourceId": item["sourceId"],
                "unitId": item["unitId"],
                "statuses": ",".join(item["statuses"]),
                "placementUseCount": len(item["placementUses"]),
                "technicalExclusionCount": len(item["technicalExclusions"]),
                "unassignedUseCount": len(item["unassignedUses"]),
            }
            for item in analysis["coverage"]
        ],
        COVERAGE_COLUMNS,
    )
    _write_tsv(
        output / "summary.tsv",
        _summary_control_rows(analysis["summary"]),
        SUMMARY_COLUMNS,
    )


def _start_timer_command(args: argparse.Namespace) -> None:
    output = Path(args.output).resolve()
    output.parent.mkdir(parents=True, exist_ok=True)
    output.write_text(str(time.time_ns() // 1_000_000), encoding="utf-8")


def _elapsed_timer_command(args: argparse.Namespace) -> None:
    started_ms = int(Path(args.start).read_text(encoding="utf-8").strip())
    elapsed_ms = max(0, (time.time_ns() // 1_000_000) - started_ms)
    sys.stdout.write(str(elapsed_ms))


def main() -> int:
    parser = argparse.ArgumentParser(description="Semantic rough-select deterministic helper.")
    subparsers = parser.add_subparsers(dest="command", required=True)
    prepare = subparsers.add_parser("prepare")
    session_group = prepare.add_mutually_exclusive_group(required=True)
    session_group.add_argument("--session")
    session_group.add_argument("--session-tsv")
    context_group = prepare.add_mutually_exclusive_group()
    context_group.add_argument("--editor-context", default="")
    context_group.add_argument("--editor-context-file")
    prepare.add_argument("--output-dir", required=True)
    prepare.add_argument("--srt-toolkit-dir")
    prepare.set_defaults(run=_prepare_command)
    validate = subparsers.add_parser("validate-global")
    validate.add_argument("--sidecar", required=True)
    validate.add_argument("--response", required=True)
    validate.add_argument("--output-dir", required=True)
    validate.set_defaults(run=_validate_command)
    plan = subparsers.add_parser("plan")
    plan.add_argument("--sidecar", required=True)
    plan.add_argument("--response", required=True)
    plan.add_argument("--boundary-response")
    plan.add_argument(
        "--handle-before-seconds",
        type=float,
        default=DEFAULT_HANDLE_BEFORE_MS / 1000,
    )
    plan.add_argument(
        "--handle-after-seconds",
        type=float,
        default=DEFAULT_HANDLE_AFTER_MS / 1000,
    )
    plan.add_argument(
        "--block-gap-seconds",
        type=float,
        default=DEFAULT_BLOCK_GAP_MS / 1000,
    )
    plan.add_argument("--output-dir", required=True)
    plan.set_defaults(run=_plan_command)
    start_timer = subparsers.add_parser("start-timer")
    start_timer.add_argument("--output", required=True)
    start_timer.set_defaults(run=_start_timer_command)
    elapsed_timer = subparsers.add_parser("elapsed-timer")
    elapsed_timer.add_argument("--start", required=True)
    elapsed_timer.set_defaults(run=_elapsed_timer_command)
    args = parser.parse_args()
    args.run(args)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
