"""Freeze the fresh V15 runtime-authority deployment package."""

from __future__ import annotations

import hashlib
import json
import os
import shlex
import shutil
import stat
import subprocess
import sys
import zipfile
from pathlib import Path

from pydantic import JsonValue, TypeAdapter

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from gateway.platforms.task26_runtime_authority import (
    build_runtime_authority_pin,
    load_task26_production_authority,
)
from scripts.nutricoach_v150_live_upgrade_common import canonical
from scripts.nutricoach_v150_runtime_ops import dependency_snapshot_digest
from scripts.nutricoach_v150_r71b_maintenance_transaction import KNOWN_R70_CRON_JOB_ID
from scripts.nutricoach_v150_r71b_preparation import (
    collect_authoritative_r71b_preflight,
    prepare_r71b_maintenance,
)
from scripts.nutricoach_v150_r71b_preseal_arguments import parse_preseal_arguments

_OBJECT = TypeAdapter(dict[str, JsonValue])
SOURCE = Path("/home/cube/projects/richard/.worktrees/nutricoach-v150-combined")
BASE = Path("/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined")
PROFILE = Path("/home/cube/.hermes/profiles/dualcoachtest")
UNIT = Path.home() / ".config/systemd/user/hermes-gateway-dualcoachtest.service"
DROPIN = UNIT.parent / f"{UNIT.name}.d/task26-authority.conf"
PRESEAL = BASE / "live-transaction-preseal-v15-runtime-authority-r71b-maintenance"
PREFLIGHT = BASE / "preflight-v15-runtime-authority-r71b-maintenance"
AUTHORITY_ID = "nutricoach-v150-v15-runtime-authority-r71b-maintenance"
PRIOR_PRESEAL = BASE / "live-transaction-preseal-v15-runtime-authority-r63"
PRIOR_PREFLIGHT = BASE / "preflight-v15-runtime-authority-r63"

def _load(path: Path) -> dict[str, JsonValue]:
    return _OBJECT.validate_json(path.read_bytes())

def _write(path: Path, value: object) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    document = _OBJECT.validate_python(value)
    _ = path.write_bytes(canonical(document) + b"\n")

def _sha(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()

def _record_sha(path: Path) -> str:
    with zipfile.ZipFile(path) as wheel:
        record = next(name for name in wheel.namelist() if name.endswith("/RECORD"))
        return hashlib.sha256(wheel.read(record)).hexdigest()

def _service_state() -> dict[str, JsonValue]:
    fields = ("ActiveState", "SubState", "MainPID", "ExecStart", "NRestarts")
    result = subprocess.run(
        (
            "/usr/bin/systemctl",
            "--user",
            "show",
            "hermes-gateway-dualcoachtest.service",
            *(f"--property={field}" for field in fields),
        ),
        check=True,
        capture_output=True,
        text=True,
    )
    rows = dict(
        line.split("=", 1) for line in result.stdout.splitlines() if "=" in line
    )
    return {field: rows.get(field, "") for field in fields}

def _current_runtime() -> Path:
    line = next(
        (
            value
            for value in UNIT.read_text(encoding="utf-8").splitlines()
            if value.startswith("ExecStart=")
        ),
        "",
    )
    command = shlex.split(line.removeprefix("ExecStart="))
    if not command:
        raise RuntimeError("current_runtime")
    runtime = Path(command[0]).parent.parent
    expected_parent = PROFILE / ".strict-runtime"
    if (
        runtime.name != "venv"
        or runtime.parent.parent != expected_parent
        or not (runtime / "bin/python").is_file()
    ):
        raise RuntimeError("current_runtime")
    return runtime

def _credential_paths() -> tuple[Path, Path]:
    values: dict[str, Path] = {}
    for line in DROPIN.read_text(encoding="utf-8").splitlines():
        if not line.startswith("LoadCredential=") or ":" not in line:
            continue
        name, raw_path = line.split("=", 1)[1].split(":", 1)
        values[name] = Path(raw_path)
    return (
        values["task26-authority-pin.json"],
        values["task26-candidate-digest"],
    )

def _authority_baseline() -> dict[str, JsonValue]:
    pin_path, candidate_path = _credential_paths()
    old_pin = os.environ.get("TASK26_AUTHORITY_PIN")
    old_candidate = os.environ.get("TASK26_CANDIDATE_DIGEST_FILE")
    os.environ["TASK26_AUTHORITY_PIN"] = str(pin_path)
    os.environ["TASK26_CANDIDATE_DIGEST_FILE"] = str(candidate_path)
    try:
        source, candidate = load_task26_production_authority(
            profile_root=PROFILE,
            package_root=BASE,
        )
    finally:
        if old_pin is None:
            _ = os.environ.pop("TASK26_AUTHORITY_PIN", None)
        else:
            os.environ["TASK26_AUTHORITY_PIN"] = old_pin
        if old_candidate is None:
            _ = os.environ.pop("TASK26_CANDIDATE_DIGEST_FILE", None)
        else:
            os.environ["TASK26_CANDIDATE_DIGEST_FILE"] = old_candidate
    registry = source.root / "candidate-authority/registry.json"
    ledger = source.root / "candidate-authority/qualification-ledger.json"
    pin = build_runtime_authority_pin(source.root)
    registry_document = _load(registry)
    events = registry_document.get("events")
    if not isinstance(events, list) or not events:
        raise RuntimeError("authority_events")
    latest = events[-1]
    if not isinstance(latest, dict):
        raise RuntimeError("authority_event")
    historical_pass = latest.get("historical_pass_digest")
    if not isinstance(historical_pass, str):
        raise RuntimeError("authority_historical_pass")
    return _OBJECT.validate_python({
        "authority_root": str(source.root),
        "candidate_digest": candidate,
        "candidate_path": str(candidate_path),
        "candidate_file_sha256": _sha(candidate_path),
        "event_count": pin["event_count"],
        "genesis_sha256": pin["genesis_sha256"],
        "historical_pass_digest": historical_pass,
        "ledger_file_sha256": _sha(ledger),
        "ledger_head_sha256": pin["ledger_head_sha256"],
        "pin_path": str(pin_path),
        "pin_file_sha256": _sha(pin_path),
        "registry_file_sha256": _sha(registry),
        "registry_head_sha256": pin["registry_head_sha256"],
        "source_id": pin["source_id"],
    })

def _controller_files(candidate: dict[str, JsonValue]) -> dict[str, JsonValue]:
    rows = candidate.get("source_inventory")
    if not isinstance(rows, list):
        raise RuntimeError("candidate_source_inventory")
    files: dict[str, JsonValue] = {}
    for row in rows:
        if not isinstance(row, dict) or not isinstance(row.get("path"), str):
            raise RuntimeError("candidate_source_entry")
        relative = Path(str(row["path"]))
        product = Path(*relative.parts[2:])
        if (SOURCE / product).is_file():
            files[product.as_posix()] = _sha(SOURCE / product)
    for relative in (
        "scripts/execute_nutricoach_v150_sealed_live.py",
        "scripts/nutricoach_v150_controller_worker.py",
        "scripts/nutricoach_v150_detached_bootstrap.py",
        "scripts/prepare_nutricoach_v150_v15_preseal.py",
        "scripts/nutricoach_v150_r71b_preseal_arguments.py",
        "scripts/nutricoach_v150_r71b_preparation.py",
        "scripts/nutricoach_v150_r71b_preseal_verifier.py",
        "scripts/verify_nutricoach_v150_preseal_v15.py",
    ):
        files[relative] = _sha(SOURCE / relative)
    return dict(sorted(files.items()))

def main() -> int:
    arguments = parse_preseal_arguments(sys.argv[1:])
    candidate_root = arguments.candidate_root
    hermes_wheel = arguments.hermes_wheel
    profile_wheel = arguments.profile_wheel
    if PRESEAL.exists() or PREFLIGHT.exists():
        raise RuntimeError("v15_paths_exist")
    candidate = _load(candidate_root / "manifest.json")
    digest = candidate.get("candidate_digest")
    if not isinstance(digest, str):
        raise RuntimeError("candidate_digest")
    for wheel in (hermes_wheel, profile_wheel):
        info = wheel.stat(follow_symlinks=False)
        if (
            wheel.is_symlink()
            or not stat.S_ISREG(info.st_mode)
            or info.st_uid != os.geteuid()
            or info.st_nlink != 1
            or stat.S_IMODE(info.st_mode) & 0o222
        ):
            raise RuntimeError("wheel_integrity")
    PREFLIGHT.mkdir(parents=True)
    PRESEAL.mkdir(parents=True)
    protected = PREFLIGHT / "snapshot-before.json"
    _ = shutil.copy2(PRIOR_PREFLIGHT / "snapshot-before.json", protected)
    dependency_root = PRESEAL / "dependencies/site-packages"
    current_runtime = _current_runtime()
    predecessor_site = next(
        (current_runtime / "lib").glob("python*/site-packages")
    )
    for name in (
        "croniter",
        "croniter-6.0.0.dist-info",
        "python_telegram_bot-22.6.dist-info",
        "telegram",
    ):
        _ = shutil.copytree(
            predecessor_site / name,
            dependency_root / name,
            ignore=shutil.ignore_patterns("__pycache__", "*.pyc", "*.pyo"),
        )
    controller_files = _controller_files(candidate)
    controller_root = PRESEAL / "controller-source"
    for relative in controller_files:
        destination = controller_root / relative
        destination.parent.mkdir(parents=True, exist_ok=True)
        _ = shutil.copy2(SOURCE / relative, destination)
    _write(
        PRESEAL / "controller-source-manifest.json",
        {
            "schema": "nutricoach-v150-controller-source-manifest-v15",
            "files": controller_files,
        },
    )
    baseline = _authority_baseline()
    target_root = PROFILE / f".strict-runtime/{digest[:8]}-v150"
    wheels = [
        {"path": str(path), "sha256": _sha(path), "record_sha256": _record_sha(path)}
        for path in (hermes_wheel, profile_wheel)
    ]
    target_binding = {
        "authority_id": AUTHORITY_ID,
        "profile_root": str(PROFILE),
        "current_runtime": str(current_runtime),
        "successor_runtime": str(target_root / "venv"),
        "service_name": "hermes-gateway-dualcoachtest.service",
        "unit": str(UNIT),
        "dropin": str(DROPIN),
        "execution_root": str(BASE / "live-executions-v15" / AUTHORITY_ID),
        "global_approval_ledger": str(BASE / "live-authorization-v15" / AUTHORITY_ID),
        "protected_inventory": str(protected),
        "protected_inventory_sha256": _sha(protected),
        "dependency_snapshot": str(dependency_root),
        "dependency_snapshot_sha256": dependency_snapshot_digest(dependency_root),
        "registry_sha256": _sha(PROFILE / "customers/registry.json"),
    }
    collected = collect_authoritative_r71b_preflight(
        candidate_root, PROFILE, arguments.window
    )
    service = _service_state()
    controller_derivation = hashlib.sha256(canonical(controller_files)).hexdigest()
    binding_seed = _OBJECT.validate_python({
        "schema": "nutricoach-v150-r71b-package-binding-inputs-v1",
        "product_generation": "r71",
        "package_namespace": "r71b-maintenance",
        "authority_id": AUTHORITY_ID,
        "paths": {"preseal_root": str(PRESEAL)},
        "candidate": {
            "candidate_digest": digest,
            "manifest": str(candidate_root / "manifest.json"),
            "manifest_sha256": _sha(candidate_root / "manifest.json"),
        },
        "wheels": wheels,
        "controller": {
            "files": controller_files,
            "derivation_sha256": controller_derivation,
        },
        "protected_inventory": {
            "path": str(protected), "sha256": _sha(protected),
            "explicit_maintenance_volatile_paths": [],
        },
        "dependency_snapshot": {
            "path": str(dependency_root),
            "dependency_snapshot_sha256": dependency_snapshot_digest(dependency_root),
        },
        "authority_baseline": baseline,
        "target_binding_base": target_binding,
        "service_preparation": service,
        "diagnosed_blocker_evidence": [
            collected.evidence["observer_evidence"],
            collected.evidence["fixed_collector_evidence"],
        ],
        **collected.evidence,
    })
    prepared = prepare_r71b_maintenance(
        collected.preflight, arguments.window, collected.facts, binding_seed
    )
    maintenance = PRESEAL / "maintenance"
    _write(
        maintenance / "maintenance-scope.json",
        prepared.scope.model_dump(mode="json", by_alias=True),
    )
    _write(maintenance / "no-send-oracle.json", prepared.oracle)
    binding_inputs = _OBJECT.validate_json(prepared.artifacts.binding_inputs_bytes)
    _write(maintenance / "package-binding-inputs.json", binding_inputs)
    authority = PRESEAL / "maintenance-authority/nutricoach-topic59-maintenance-r71b.json"
    authority.parent.mkdir(parents=True, exist_ok=True)
    _ = authority.write_bytes(prepared.artifacts.authority_bytes)
    _write(PREFLIGHT / "package.json", prepared.artifacts.permission_package)
    package_digest = prepared.artifacts.final_package_digest
    phrase = str(prepared.artifacts.permission_package["approval_phrase"])
    target = {
        **target_binding,
        "schema": "nutricoach-v150-sealed-live-target-r71b",
        "approval_phrase": phrase,
        "package_digest": package_digest,
        "candidate_digest": digest,
        "candidate_manifest": str(candidate_root / "manifest.json"),
        "candidate_manifest_sha256": _sha(candidate_root / "manifest.json"),
        "controller_derivation_sha256": controller_derivation,
        "permission_package": str(PREFLIGHT / "package.json"),
        "permission_package_sha256": _sha(PREFLIGHT / "package.json"),
        "authority_baseline": baseline,
        "wheels": wheels,
        "service_preparation": service,
        "package_binding_digest": prepared.artifacts.package_binding_digest,
        "maintenance_authority_path": str(authority),
        "maintenance_authority_sha256": prepared.artifacts.authority_sha256,
        "maintenance_hold_id": prepared.artifacts.hold.hold_id,
        "maintenance_hold_sha256": prepared.artifacts.hold_sha256,
        "maintenance_scope_path": str(maintenance / "maintenance-scope.json"),
        "maintenance_scope_sha256": _sha(maintenance / "maintenance-scope.json"),
        "maintenance_ledger_path": str(PROFILE / "data/weekly-operations-topic59.jsonl"),
        "maintenance_ledger_sha256": collected.preflight.publication_ledger_sha256,
        "maintenance_output_directory": str(PROFILE / "cron/output" / KNOWN_R70_CRON_JOB_ID),
        "r70_error_evidence_path": collected.evidence["r70_error_evidence_path"],
        "r70_error_evidence_sha256": collected.evidence["r70_error_evidence_sha256"],
        "maintenance_window": {
            "kst_day": arguments.window.kst_day.isoformat(),
            "not_before": arguments.window.not_before.isoformat(),
            "expires_at": arguments.window.expires_at.isoformat(),
        },
    }
    _write(PRESEAL / "sealed-target.json", target)
    prior = _load(PRIOR_PRESEAL / "package-supersession.json")
    rows = prior.get("superseded")
    if not isinstance(rows, list):
        raise RuntimeError("supersession")
    rows.append({
        "package_digest": prior["active_package_digest"],
        "approval_phrase_reusable": False,
        "reason": "r43 wheel UX audit found internal normal and no_workout markers in customer copy",
    })
    _write(
        PRESEAL / "package-supersession.json",
        {
            "schema": "nutricoach-v150-package-supersession-v15",
            "active_package_digest": package_digest,
            "active_package_sha256": _sha(PREFLIGHT / "package.json"),
            "active_approval_phrase": phrase,
            "superseded": rows,
        },
    )
    entries = {
        path.relative_to(PRESEAL).as_posix(): _sha(path)
        for path in PRESEAL.rglob("*")
        if path.is_file() and path.name != "package-manifest.json"
    }
    _write(
        PRESEAL / "package-manifest.json",
        {
            "schema": "nutricoach-v150-detached-preseal-package-v15",
            "status": "FROZEN_AWAITING_AUDIT",
            "self_exclusion": "package-manifest.json only",
            "new_package_digest": package_digest,
            "new_approval_phrase": phrase,
            "approval_consumed": False,
            "entries": dict(sorted(entries.items())),
        },
    )
    for path in PRESEAL.rglob("*"):
        if path.is_file() and not path.is_symlink():
            path.chmod(0o444)
    for path in sorted(
        (item for item in PRESEAL.rglob("*") if item.is_dir()), reverse=True
    ):
        path.chmod(0o555)
    PRESEAL.chmod(0o555)
    if any(
        stat.S_IMODE(path.stat(follow_symlinks=False).st_mode) & 0o222
        for path in (PRESEAL, *PRESEAL.rglob("*"))
    ):
        raise RuntimeError("immutable_mode")
    print(json.dumps({"candidate_digest": digest, "package_digest": package_digest}))
    return 0

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


"""Run the fresh V15 transaction against faithful disposable authority clones."""

from __future__ import annotations

import hashlib
import json
import os
import shutil
import sys
from pathlib import Path

from pydantic import JsonValue, TypeAdapter

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "dualcoach/profile"))

from gateway.platforms.task26_candidate_authority import (
    verify_candidate_authority,
)
from gateway.platforms.task26_runtime_authority import (
    build_runtime_authority_pin,
    publish_runtime_authority_pin,
)
from scripts.nutricoach_v150_concrete_host import ConcreteLiveHost
from scripts.nutricoach_v150_live_upgrade_common import canonical
from scripts.nutricoach_v150_sealed_controller import (
    SealedControllerError,
    execute_disposable,
)
from scripts.nutricoach_v150_sealed_target import DisposableService, HostPaths

_OBJECT = TypeAdapter(dict[str, JsonValue])
LIVE = Path("/home/cube/.hermes/profiles/dualcoachtest")
BASE = Path("/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined")
PRESEAL = BASE / "live-transaction-preseal-v15-runtime-authority-r71b-maintenance"
EVIDENCE = Path(
    "/home/cube/projects/richard/traning coach/.omo/evidence/"
    + "nutricoach-v150-combined/task-v15r71-rehearsal"
)
UNIT = Path.home() / ".config/systemd/user/hermes-gateway-dualcoachtest.service"
DROPIN = UNIT.parent / f"{UNIT.name}.d/task26-authority.conf"
FAULTS = (
    "stop",
    "post_stop_snapshot",
    "stopped_probe",
    "install_exact_wheels",
    "off_smoke_channel_inbox_off",
    "capacity_dry_run",
    "weekly_and_capacity_apply",
    "weekly_startup_smoke",
    "switch_unit_dropin",
    "reload",
    "start",
    "post_fence",
)

def _load(path: Path) -> dict[str, JsonValue]:
    return _OBJECT.validate_json(path.read_bytes())

def _sha(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()

def _tree(root: Path) -> str:
    rows = [
        f"{path.relative_to(root)}:{_sha(path)}"
        for path in root.rglob("*")
        if path.is_file() and not path.is_symlink()
    ]
    return hashlib.sha256("\n".join(sorted(rows)).encode()).hexdigest()

def _remove_tree(root: Path) -> None:
    for directory, _subdirectories, filenames in os.walk(root):
        Path(directory).chmod(0o700)
        for filename in filenames:
            path = Path(directory) / filename
            if not path.is_symlink():
                path.chmod(0o600)
    shutil.rmtree(root)

def _rebind_activation_authority(profile: Path) -> None:
    journal_path = profile / "data/customer-activation-journal.json"
    audit_path = profile / "data/customer-activation-audit.jsonl"
    journal = _load(journal_path)
    audit = _load(audit_path)
    for field in (
        "registry_path",
        "data_root",
        "audit_path",
        "staff_membership_evidence_path",
    ):
        value = journal.get(field)
        if isinstance(value, str) and Path(value).is_relative_to(LIVE):
            journal[field] = str(profile / Path(value).relative_to(LIVE))
        value = audit.get(field)
        if isinstance(value, str) and Path(value).is_relative_to(LIVE):
            audit[field] = str(profile / Path(value).relative_to(LIVE))
    journal["audit_record_sha256"] = hashlib.sha256(canonical(audit)).hexdigest()
    audit_digest = str(journal["audit_record_sha256"])
    _ = journal_path.write_text(
        json.dumps(journal, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )
    _ = audit_path.write_bytes(canonical(audit) + b"\n")
    receipt_root = profile / "data/customer-activation-receipts"
    for receipt_path in receipt_root.glob("*.json"):
        receipt = _load(receipt_path)
        for field in (
            "registry_path",
            "data_root",
            "audit_path",
            "staff_membership_evidence_path",
        ):
            value = receipt.get(field)
            if isinstance(value, str) and Path(value).is_relative_to(LIVE):
                receipt[field] = str(profile / Path(value).relative_to(LIVE))
        receipt["audit_record_sha256"] = audit_digest
        _ = receipt_path.write_text(
            json.dumps(receipt, ensure_ascii=False, indent=2) + "\n",
            encoding="utf-8",
        )

def _clone(root: Path, fault: str | None) -> ConcreteLiveHost:
    target = _load(PRESEAL / "sealed-target.json")
    baseline = target["authority_baseline"]
    wheels = target["wheels"]
    if not isinstance(baseline, dict) or not isinstance(wheels, list):
        raise RuntimeError("target")
    profile = root / "profile"
    profile.mkdir(parents=True)
    _ = shutil.copytree(LIVE / "data", profile / "data")
    _ = shutil.copytree(LIVE / "customers", profile / "customers")
    _ = shutil.copy2(LIVE / "config.yaml", profile / "config.yaml")
    _rebind_activation_authority(profile)
    current = profile / ".strict-runtime/current/venv"
    (current / "bin").mkdir(parents=True)
    _ = (current / "bin/python").write_text("predecessor\n")
    authority = root / "external-authority"
    _ = shutil.copytree(Path(str(baseline["authority_root"])), authority)
    credentials = root / "predecessor-credentials"
    credentials.mkdir(mode=0o700)
    pin = credentials / "task26-authority-pin.json"
    publish_runtime_authority_pin(pin, build_runtime_authority_pin(authority))
    candidate_file = credentials / "task26-candidate-digest"
    _ = candidate_file.write_text(str(baseline["candidate_digest"]) + "\n")
    candidate_file.chmod(0o600)
    unit = root / "gateway.service"
    live_current = Path(str(target["current_runtime"]))
    _ = unit.write_bytes(
        UNIT.read_bytes().replace(str(live_current).encode(), str(current).encode())
    )
    dropin = root / "authority.conf"
    lines: list[str] = []
    for line in DROPIN.read_text(encoding="utf-8").splitlines():
        line = line.replace(str(live_current), str(current))
        if line.startswith("LoadCredential=") and ":" in line:
            name, raw_source = line.split("=", 1)[1].split(":", 1)
            if name == "task26-authority-pin.json":
                source = pin
            elif name == "task26-candidate-digest":
                source = candidate_file
            else:
                source = credentials / name
                _ = shutil.copy2(Path(raw_source), source)
                source.chmod(0o600)
            line = f"LoadCredential={name}:{source}"
        lines.append(line)
    _ = dropin.write_text("\n".join(lines) + "\n")
    successor_name = Path(str(target["successor_runtime"])).parent.name
    paths = HostPaths(
        profile,
        profile / "customers/registry.json",
        profile / "config.yaml",
        unit,
        dropin,
        current,
        profile / ".strict-runtime" / successor_name / "venv",
        root / "execution",
        root / "ledger",
    )
    hermes, package = wheels
    if not isinstance(hermes, dict) or not isinstance(package, dict):
        raise RuntimeError("wheels")
    return ConcreteLiveHost(
        paths,
        DisposableService(),
        live=True,
        candidate_digest=str(target["candidate_digest"]),
        hermes_wheel=Path(str(hermes["path"])),
        hermes_wheel_sha256=str(hermes["sha256"]),
        profile_wheel=Path(str(package["path"])),
        profile_wheel_sha256=str(package["sha256"]),
        dependency_snapshot=Path(str(target["dependency_snapshot"])),
        dependency_snapshot_sha256=str(target["dependency_snapshot_sha256"]),
        fault=ValueError(fault) if fault is not None else None,
        fault_stage=fault or "install_exact_wheels",
    )

def main() -> int:
    if EVIDENCE.exists():
        raise RuntimeError("rehearsal_exists")
    EVIDENCE.mkdir(parents=True)
    target = _load(PRESEAL / "sealed-target.json")
    approval = str(target["approval_phrase"])
    candidate = str(target["candidate_digest"])
    raw_baseline = target.get("authority_baseline")
    if not isinstance(raw_baseline, dict):
        raise RuntimeError("authority_baseline")
    baseline = raw_baseline
    live_before = {
        "registry": _sha(LIVE / "customers/registry.json"),
        "config": _sha(LIVE / "config.yaml"),
        "data": _tree(LIVE / "data"),
        "unit": _sha(UNIT),
        "dropin": _sha(DROPIN),
    }
    rows: list[JsonValue] = []
    success_root = EVIDENCE / "success"
    success = _clone(success_root, None)
    receipt = execute_disposable(
        approval, success_root, success, expected_approval=approval
    )
    source = verify_candidate_authority(Path(str(baseline["authority_root"])), None)
    if (
        not success.service.running
        or success.network_events
        or success.telegram_events
        or success.provider_events
    ):
        raise RuntimeError("success")
    rows.append({"case": "success", "receipt": receipt, "status": "PASS"})
    for fault in FAULTS:
        case_root = EVIDENCE / f"rollback-{fault}"
        host = _clone(case_root, fault)
        before = tuple(path.read_bytes() for path in host.paths.mutable)
        try:
            _ = execute_disposable(
                approval, case_root, host, expected_approval=approval
            )
        except ValueError as error:
            if str(error) != fault:
                raise
        else:
            raise RuntimeError(f"fault_missing:{fault}")
        if (
            tuple(path.read_bytes() for path in host.paths.mutable) != before
            or not host.service.running
            or host.successor_root.exists()
            or host.weekly_authority.exists()
            or host.network_events
            or host.telegram_events
            or host.provider_events
        ):
            raise RuntimeError(f"rollback:{fault}")

[41 more lines in file. Use offset=261 to continue.]


"""Task10 evidence authenticity contracts at the candidate boundary."""

from __future__ import annotations

import os
from pathlib import Path

import pytest

from scripts.nutricoach_v150_candidate_cli import CliNamespace
from scripts.nutricoach_v150_r71b_task10_evidence import (
    R71B_TASK10_EVIDENCE,
    Task10EvidenceError,
    load_candidate_task10_evidence,
    task10_evidence_spec,
    validate_fixed_task10_evidence_sources,
    verify_candidate_task10_evidence,
)
from scripts.seal_nutricoach_v150_candidate import copy_r71b_evidence

_INPUTS = {
    "r70_error": "inputs/r70-canonical-authority-drift.json",
    "observer": "inputs/r71b-observer-final.json",
    "health_recovery": "inputs/r71b-fixed-collector.json",
}

def _arguments() -> CliNamespace:
    arguments = CliNamespace()
    arguments.r70_error_evidence = task10_evidence_spec("r70_error").source_path
    arguments.observer_evidence = task10_evidence_spec("observer").source_path
    arguments.fixed_collector_evidence = task10_evidence_spec(
        "health_recovery"
    ).source_path
    return arguments

def _seal_task10_copies(tmp_path: Path) -> Path:
    candidate = tmp_path / "candidate"
    copied = copy_r71b_evidence(_arguments(), candidate)
    for path in copied:
        path.chmod(0o444)
    return candidate

def test_candidate_sealer_accepts_only_the_exact_resolved_task10_sources(
    tmp_path: Path,
) -> None:
    # Given / When
    candidate = _seal_task10_copies(tmp_path)
    copies = verify_candidate_task10_evidence(candidate, _INPUTS)

    # Then
    assert tuple(copy.input_name for copy in copies) == (
        "r70_error",
        "observer",
        "health_recovery",
    )
    assert tuple(copy.source_path for copy in copies) == tuple(
        str(spec.source_path) for spec in R71B_TASK10_EVIDENCE
    )
    assert tuple(copy.source_sha256 for copy in copies) == tuple(
        spec.source_sha256 for spec in R71B_TASK10_EVIDENCE
    )
    assert tuple(copy.source_schema for copy in copies) == tuple(
        spec.source_schema for spec in R71B_TASK10_EVIDENCE
    )
    assert tuple(copy.source_status for copy in copies) == tuple(
        spec.status for spec in R71B_TASK10_EVIDENCE
    )

def test_candidate_sealer_rejects_a_same_basename_source_outside_the_plan_root(
    tmp_path: Path,
) -> None:
    # Given
    arguments = _arguments()
    arguments.r70_error_evidence = tmp_path / "task-10-cron-no-send-recovery-analysis.json"
    _ = arguments.r70_error_evidence.write_text("{}\n", encoding="utf-8")

    # When / Then
    with pytest.raises(Task10EvidenceError, match="task10_evidence_path"):
        _ = copy_r71b_evidence(arguments, tmp_path / "candidate")
    assert not (tmp_path / "candidate").exists()

@pytest.mark.parametrize("mutation", ("noncanonical", "symlink", "hardlink", "mode"))
def test_candidate_verifier_rejects_malformed_or_substituted_task10_copies(
    tmp_path: Path,
    mutation: str,
) -> None:
    # Given
    candidate = _seal_task10_copies(tmp_path)
    path = candidate / _INPUTS["observer"]
    if mutation == "noncanonical":
        payload = path.read_bytes()
        path.chmod(0o644)
        _ = path.write_bytes(payload + b"\n")
        path.chmod(0o444)
    elif mutation == "symlink":
        target = tmp_path / "source.json"
        _ = target.write_bytes(path.read_bytes())
        path.unlink()
        path.symlink_to(target)
    elif mutation == "hardlink":
        linked = tmp_path / "linked.json"
        os.link(path, linked)
    else:
        path.chmod(0o644)

    # When / Then
    with pytest.raises(Task10EvidenceError):
        _ = load_candidate_task10_evidence(
            candidate,
            _INPUTS["observer"],
            task10_evidence_spec("observer"),
        )

def test_exact_task10_sources_enforce_the_expected_source_metadata() -> None:
    # Given / When
    evidence = validate_fixed_task10_evidence_sources(
        task10_evidence_spec("r70_error").source_path,
        task10_evidence_spec("observer").source_path,
        task10_evidence_spec("health_recovery").source_path,
    )

    # Then
    assert tuple(item.spec.source_sha256 for item in evidence) == tuple(
        spec.source_sha256 for spec in R71B_TASK10_EVIDENCE
    )


**Inspecting session file for task evidence**

bash

find .omo/senpi-task -path '*st_01a05c97*' -type f -printf '%p\n' 2>/dev/null | sort; find .omo/senpi-task -type f -name '*.jsonl' -printf '%p\n' | tail -30

ROOT='/home/cube/projects/richard/.worktrees/nutricoach-v150-combined'; find "$ROOT/.omo/evidence/nutricoach-v150-combined/task-1-candidate" -maxdepth 3 -type f -printf '%P\n' | sort; printf '\nBase/v17 candidates in main evidence:\n'; find '/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined' -maxdepth 2 -type f \( -name manifest.json -o -name '*overlay*' -o -name 'authority-verification.json' \) -printf '%p\n' | tail -100

ROOT='/home/cube/projects/richard/.worktrees/nutricoach-v150-combined'; rg -n "python -m build|SOURCE_DATE_EPOCH|authority-verification.json|successor-overlay" "$ROOT" -g '*.py' -g '*.sh' | grep -E 'v150|candidate|wheel|build' | head -300


.omo/senpi-task/children/st_01a05c97/sessions/st_01a05c97/2026-09-01T10-50-39-589Z_01a05c97-ae65-7953-9dcc-df8063eb2542.jsonl
.omo/senpi-task/logs/st_01a05c97.jsonl
.omo/senpi-task/tasks/st_01a05c97.json
.omo/senpi-task/logs/st_01a01565.jsonl
.omo/senpi-task/logs/st_01a02879.jsonl
.omo/senpi-task/logs/st_01a0484c.jsonl
.omo/senpi-task/logs/st_01a05a78.jsonl
.omo/senpi-task/logs/st_01a04e3b.jsonl
.omo/senpi-task/logs/st_01a04071.jsonl
.omo/senpi-task/logs/st_01a019bc.jsonl
.omo/senpi-task/logs/st_01a01a0c.jsonl
.omo/senpi-task/logs/st_01a05a9d.jsonl
.omo/senpi-task/logs/st_01a03d24.jsonl
.omo/senpi-task/logs/st_01a01300.jsonl
.omo/senpi-task/logs/st_01a00a87.jsonl
.omo/senpi-task/logs/st_01a02851.jsonl
.omo/senpi-task/logs/st_01a02272.jsonl
.omo/senpi-task/logs/st_01a05afa.jsonl
.omo/senpi-task/logs/st_019fe19c.jsonl
.omo/senpi-task/logs/st_01a01a10.jsonl
.omo/senpi-task/logs/st_01a041f5.jsonl
.omo/senpi-task/logs/st_01a019e3.jsonl
.omo/senpi-task/logs/st_019ffa71.jsonl
.omo/senpi-task/logs/st_01a0038c.jsonl
.omo/senpi-task/logs/st_01a03378.jsonl
.omo/senpi-task/logs/st_01a05bc2.jsonl
.omo/senpi-task/logs/st_01a05898.jsonl
.omo/senpi-task/logs/st_01a036b9.jsonl
.omo/senpi-task/logs/st_01a003e2.jsonl
.omo/senpi-task/logs/st_01a01778.jsonl
.omo/senpi-task/logs/st_01a0287d.jsonl
.omo/senpi-task/logs/st_01a01fa1.jsonl
.omo/senpi-task/logs/st_01a0577c.jsonl


"""Typed CLI boundary for NutriCoach candidate sealing."""

from __future__ import annotations

import argparse
from pathlib import Path

def candidate_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description=__doc__)
    _ = parser.add_argument("--base", required=True, type=Path)
    _ = parser.add_argument("--v17-evidence", required=True, type=Path)
    _ = parser.add_argument("--successor", required=True, type=Path)
    _ = parser.add_argument("--build-1-hermes", required=True, type=Path)
    _ = parser.add_argument("--build-1-profile", required=True, type=Path)
    _ = parser.add_argument("--build-2-hermes", required=True, type=Path)
    _ = parser.add_argument("--build-2-profile", required=True, type=Path)
    _ = parser.add_argument("--receipts-root", required=True, type=Path)
    _ = parser.add_argument("--successor-overlay", required=True, type=Path)
    _ = parser.add_argument("--r70-error-evidence", required=True, type=Path)
    _ = parser.add_argument("--observer-evidence", required=True, type=Path)
    _ = parser.add_argument("--fixed-collector-evidence", required=True, type=Path)
    return parser

class CliNamespace(argparse.Namespace):
    """Mutable argparse destination with statically known path fields."""

    def __init__(self) -> None:
        super().__init__()
        self.base: Path = Path()
        self.v17_evidence: Path = Path()
        self.successor: Path = Path()
        self.build_1_hermes: Path = Path()
        self.build_1_profile: Path = Path()
        self.build_2_hermes: Path = Path()
        self.build_2_profile: Path = Path()
        self.receipts_root: Path = Path()
        self.successor_overlay: Path = Path()
        self.r70_error_evidence: Path = Path()
        self.observer_evidence: Path = Path()
        self.fixed_collector_evidence: Path = Path()


"""Required explicit CLI values for a one-use r71b maintenance preseal."""

from __future__ import annotations

from collections.abc import Sequence
from dataclasses import dataclass
from pathlib import Path

from scripts.nutricoach_v150_r71b_preparation import (
    MaintenanceWindow,
    parse_maintenance_window,
)

@dataclass(frozen=True, slots=True)
class R71bPresealArguments:
    """All caller-supplied paths plus the mandatory bounded KST maintenance window."""

    candidate_root: Path
    hermes_wheel: Path
    profile_wheel: Path
    window: MaintenanceWindow

def parse_preseal_arguments(arguments: Sequence[str]) -> R71bPresealArguments:
    """Parse exactly three paths and three explicit KST window flags."""
    values = tuple(arguments)
    if len(values) != 9:
        raise ValueError(" ".join((
            "usage: preparer CANDIDATE_ROOT HERMES_WHEEL PROFILE_WHEEL",
            "--maintenance-kst-day DAY --maintenance-not-before INSTANT",
            "--maintenance-expires-at INSTANT",
        )))
    candidate_root, hermes_wheel, profile_wheel = values[:3]
    flags = values[3:]
    expected = (
        "--maintenance-kst-day",
        "--maintenance-not-before",
        "--maintenance-expires-at",
    )
    if tuple(flags[::2]) != expected or any(not value for value in flags[1::2]):
        raise ValueError("maintenance_window_arguments")
    return R71bPresealArguments(
        Path(candidate_root),
        Path(hermes_wheel),
        Path(profile_wheel),
        parse_maintenance_window(flags[1], flags[3], flags[5]),
    )


artifacts/build-1/hermes_agent-0.17.0-py3-none-any.whl
artifacts/build-1/physique_checkin_cli-0.1.0-py3-none-any.whl
artifacts/build-2/hermes_agent-0.17.0-py3-none-any.whl
artifacts/build-2/physique_checkin_cli-0.1.0-py3-none-any.whl
inputs/base-manifest.json
inputs/v17-evidence-files.sha256
inputs/v17-exact-source-set.sha256
inputs/v17-patch-tree.sha256
inputs/v17-sandbox.diff
manifest.json
qualification.json
receipts/behavior-summary.json
receipts/composition.json
receipts/formatting-only-justification.json
receipts/input-provenance.json
receipts/logs/formatted-static.log
receipts/logs/installed-wheel.log
receipts/logs/v140-weekly-gateway-isolated.log
receipts/logs/v140-weekly-profile.log
receipts/logs/v17-gateway.log
receipts/logs/v17-profile.log
receipts/reproducible-builds.json
receipts/safety-boundary.json
receipts/static-summary.json

Base/v17 candidates in main evidence:
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r53-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r32-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r39-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r58-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r50-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-candidate-r3/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r33-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r54-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r5-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r67-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r3-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r48-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r27-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r11-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r54-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r44-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r31-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r13-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r55-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r36-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r56-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r69-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r28-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r41-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14b-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r62-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r60-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r35-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14c-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r9-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-candidate-r2/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r62-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r24-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r70-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r42-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r70-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r16-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14d-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r8-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15-receipts/authority-verification.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r52-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r4-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r52-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r38-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r19-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r34-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r56-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r67-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r14-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r59-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r53-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r22-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r6-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r65-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r50-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r23-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r37-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r17-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r66-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r12-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r25-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r40-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r49-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r30-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r43-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r60-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r16-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r61-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r51-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r26-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r15-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r68-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r59-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r29-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r18-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r57-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r63-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r69-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r20-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v14r10-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r61-candidate/manifest.json
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r32-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r36-inputs/successor-overlay.sha256
/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r63-candidate/manifest.json


/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/nutricoach_v150_candidate_cli.py:18:    _ = parser.add_argument("--successor-overlay", required=True, type=Path)
/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/verify_nutricoach_v150_candidate_inputs.py:157:        (root / "inputs/successor-overlay.sha256")
/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/verify_nutricoach_v150_candidate.py:125:        load_json(root / "receipts/authority-verification.json"),
/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/verify_nutricoach_v150_candidate.py:194:            root / "inputs/successor-overlay.sha256"
/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/seal_nutricoach_v150_candidate.py:169:        "inputs/successor-overlay.sha256": args.successor_overlay,
/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/release.py:1758:    ``python -m build`` if uv is unavailable.
/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/release.py:1763:    # Prefer uv build (matches CI workflow), fall back to python -m build.
/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/tests/test_nutricoach_v150_v15_closure.py:106:    _ = (inputs / "successor-overlay.sha256").write_text(
/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/tests/test_nutricoach_v150_v15_closure.py:166:            "--successor-overlay",


**Parsing session commands with jq**

python - <<'PY'
import json, pathlib
p=pathlib.Path('.omo/senpi-task/children/st_01a05c97/sessions/st_01a05c97/2026-09-01T10-50-39-589Z_01a05c97-ae65-7953-9dcc-df8063eb2542.jsonl')
for i,line in enumerate(p.read_text(errors='replace').splitlines(),1):
 try:o=json.loads(line)
 except:continue
 s=json.dumps(o,ensure_ascii=False)
 if any(x in s for x in ['functions.bash','DISPOSABLE_PACKAGE_PASS','authority-verification','SOURCE_DATE_EPOCH','pytest','preseal']):
  # extract command/content not full giant
  print('\nLINE',i)
  print(s[:12000])
PY


**Planning session command extraction**

python - <<'PY'
import json,pathlib
p=pathlib.Path('.omo/senpi-task/children/st_01a05c97/sessions/st_01a05c97/2026-09-01T10-50-39-589Z_01a05c97-ae65-7953-9dcc-df8063eb2542.jsonl')
for i,line in enumerate(p.read_text().splitlines(),1):
 try:o=json.loads(line)
 except:continue
 m=o.get('message',{})
 for c in m.get('content',[]):
  if c.get('type')=='toolCall' and c.get('name')=='bash':
   cmd=c.get('arguments',{}).get('command','')
   print(f'\n### LINE {i}\n{cmd}\n')
PY