feat(compute): add bounded camera job contract

This commit is contained in:
DCCONSTRUCTIONS
2026-07-19 16:46:32 +03:00
parent 75d2e5da4b
commit 648d5bced4
6 changed files with 715 additions and 8 deletions
@@ -17,11 +17,13 @@ from rich.table import Table
from k1link import __version__
from k1link.artifacts import write_json_atomic
from k1link.compute import prepare_camera_compute_job
from k1link.device_plugins.xgrids_k1.analyze import (
DEFAULT_STREAM_SUMMARY_MAX_PAYLOAD_BYTES,
MAX_STREAM_SUMMARY_PAYLOAD_BYTES,
summarize_mqtt_streams,
)
from k1link.device_plugins.xgrids_k1.archive import discover_legacy_viewer_sessions
from k1link.device_plugins.xgrids_k1.ble.gatt import dump_metadata
from k1link.device_plugins.xgrids_k1.ble.scanner import scan
from k1link.device_plugins.xgrids_k1.ble.wifi_provisioning import (
@@ -42,6 +44,7 @@ from k1link.device_plugins.xgrids_k1.protocol.application_authority import (
)
from k1link.device_plugins.xgrids_k1.usb.snapshot import snapshot as usb_snapshot
from k1link.macos_credentials import CredentialDialogError, prompt_wifi_credentials
from k1link.sessions import SessionIntegrityError
app = typer.Typer(
name="k1link",
@@ -57,11 +60,16 @@ authority_app = typer.Typer(
help="One-time local authority administration; never sends a K1 command.",
no_args_is_help=True,
)
compute_app = typer.Typer(
help="Bounded, content-addressed handoffs to external compute workers.",
no_args_is_help=True,
)
app.add_typer(ble_app, name="ble")
app.add_typer(net_app, name="net")
app.add_typer(usb_app, name="usb")
app.add_typer(analyze_app, name="analyze")
app.add_typer(authority_app, name="authority")
app.add_typer(compute_app, name="compute")
class ToolStatus(TypedDict):
@@ -579,5 +587,71 @@ def analyze_mqtt_streams(
console.print(f"Saved: {out}")
@compute_app.command("prepare-camera-job")
def prepare_camera_job(
session_root: Annotated[
Path,
typer.Option(
"--session-root",
exists=True,
file_okay=False,
dir_okay=True,
readable=True,
help="Sealed observation session containing the canonical camera epoch.",
),
],
source_id: Annotated[
str,
typer.Option("--source", help="Canonical archived camera source id."),
],
codec_epoch: Annotated[
int,
typer.Option("--epoch", min=1, help="Physical camera codec epoch number."),
],
out_root: Annotated[
Path,
typer.Option(
"--out-root",
help="Ignored private root where the immutable job directory is published.",
),
],
) -> None:
"""Validate and package one archived camera epoch without touching the K1."""
session = session_root.expanduser().resolve()
candidates = {
candidate.session_id: candidate
for candidate in discover_legacy_viewer_sessions(session.parent)
}
candidate = candidates.get(session.name)
if candidate is None or candidate.session_root != session:
console.print("[red]Compute job failed:[/red] session is not a sealed archive")
raise typer.Exit(code=2)
if all(media.source_id != source_id for media in candidate.media_sources):
console.print("[red]Compute job failed:[/red] camera source is not cataloged")
raise typer.Exit(code=2)
try:
job = prepare_camera_compute_job(
session_root=session,
source_id=source_id,
codec_epoch=codec_epoch,
origin_epoch_ns=candidate.timeline_origin_epoch_ns,
origin_monotonic_ns=candidate.timeline_origin_monotonic_ns,
output_root=out_root,
)
except (OSError, SessionIntegrityError, ValueError) as exc:
console.print(f"[red]Compute job failed:[/red] {type(exc).__name__}: {exc}")
raise typer.Exit(code=2) from exc
console.print(f"[green]Compute job ready:[/green] {job.job_id}")
console.print(
f"Segments: {job.segment_count}; bytes: {job.input_byte_length}; "
f"session time: {job.timeline_start_seconds:.6f}"
f"{job.timeline_end_seconds:.6f} s"
)
console.print(f"Input SHA-256: {job.input_sha256}")
console.print(f"Saved: {job.job_root}")
if __name__ == "__main__":
app()