feat(perception): publish immutable lab session instances
This commit is contained in:
@@ -17,7 +17,11 @@ 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.compute import (
|
||||
prepare_camera_compute_job,
|
||||
publish_e21_lab_instance,
|
||||
publish_integrated_lab_instance,
|
||||
)
|
||||
from k1link.device_plugins.xgrids_k1.analyze import (
|
||||
DEFAULT_STREAM_SUMMARY_MAX_PAYLOAD_BYTES,
|
||||
MAX_STREAM_SUMMARY_PAYLOAD_BYTES,
|
||||
@@ -70,12 +74,17 @@ compute_app = typer.Typer(
|
||||
help="Bounded, content-addressed handoffs to external compute workers.",
|
||||
no_args_is_help=True,
|
||||
)
|
||||
lab_app = typer.Typer(
|
||||
help="Append-only publication of reproducible laboratory session instances.",
|
||||
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")
|
||||
app.add_typer(lab_app, name="lab")
|
||||
|
||||
|
||||
class ToolStatus(TypedDict):
|
||||
@@ -304,6 +313,126 @@ def doctor(
|
||||
console.print(f"- {note}")
|
||||
|
||||
|
||||
@lab_app.command("publish-integrated")
|
||||
def publish_integrated_lab(
|
||||
result: Annotated[
|
||||
Path,
|
||||
typer.Option(
|
||||
exists=True,
|
||||
file_okay=False,
|
||||
readable=True,
|
||||
resolve_path=True,
|
||||
help="Accepted e10-integrated-perception result directory.",
|
||||
),
|
||||
],
|
||||
session_id: Annotated[
|
||||
str,
|
||||
typer.Option("--session-id", help="New immutable LAB session id."),
|
||||
],
|
||||
lab_id: Annotated[
|
||||
str,
|
||||
typer.Option("--lab-id", help="LAB marker, for example 'LAB E19'."),
|
||||
],
|
||||
display_name: Annotated[
|
||||
str,
|
||||
typer.Option("--display-name", help="Operator-facing saved-session title."),
|
||||
],
|
||||
) -> None:
|
||||
"""Publish one exact accepted visual run without copying raw sensor bytes."""
|
||||
|
||||
repository_root = Path(__file__).resolve().parents[4]
|
||||
try:
|
||||
published = publish_integrated_lab_instance(
|
||||
repository_root=repository_root,
|
||||
source_result_root=result,
|
||||
lab_session_id=session_id,
|
||||
lab_id=lab_id,
|
||||
display_name=display_name,
|
||||
)
|
||||
except (OSError, SessionIntegrityError, ValueError) as exc:
|
||||
console.print(f"[red]LAB publication failed:[/red] {exc}")
|
||||
raise typer.Exit(code=2) from exc
|
||||
console.print(
|
||||
"[green]LAB instance published.[/green] "
|
||||
f"session={published.binding.session_id}; "
|
||||
f"source={published.binding.source_session_id}; "
|
||||
f"result={published.binding.result_id}; "
|
||||
"raw_sensor_payloads_copied=false"
|
||||
)
|
||||
|
||||
|
||||
@lab_app.command("publish-e21")
|
||||
def publish_e21_lab(
|
||||
result: Annotated[
|
||||
Path,
|
||||
typer.Option(
|
||||
exists=True,
|
||||
file_okay=False,
|
||||
readable=True,
|
||||
resolve_path=True,
|
||||
help="Accepted E21 realtime-envelope result directory.",
|
||||
),
|
||||
],
|
||||
worker_result: Annotated[
|
||||
Path,
|
||||
typer.Option(
|
||||
"--worker-result",
|
||||
exists=True,
|
||||
file_okay=False,
|
||||
readable=True,
|
||||
resolve_path=True,
|
||||
help="Exact E15 shadow-worker result referenced by E21.",
|
||||
),
|
||||
],
|
||||
semantic_reference: Annotated[
|
||||
Path,
|
||||
typer.Option(
|
||||
"--semantic-reference",
|
||||
exists=True,
|
||||
file_okay=False,
|
||||
readable=True,
|
||||
resolve_path=True,
|
||||
help="Accepted E10 result containing the SHA-matched semantic masks.",
|
||||
),
|
||||
],
|
||||
session_id: Annotated[
|
||||
str,
|
||||
typer.Option("--session-id", help="New immutable LAB session id."),
|
||||
],
|
||||
lab_id: Annotated[
|
||||
str,
|
||||
typer.Option("--lab-id", help="LAB marker, for example 'LAB E21'."),
|
||||
],
|
||||
display_name: Annotated[
|
||||
str,
|
||||
typer.Option("--display-name", help="Operator-facing saved-session title."),
|
||||
],
|
||||
) -> None:
|
||||
"""Publish the exact accepted E21 envelope as a visual 60-second LAB run."""
|
||||
|
||||
repository_root = Path(__file__).resolve().parents[4]
|
||||
try:
|
||||
published = publish_e21_lab_instance(
|
||||
repository_root=repository_root,
|
||||
e21_result_root=result,
|
||||
worker_result_root=worker_result,
|
||||
semantic_reference_result_root=semantic_reference,
|
||||
lab_session_id=session_id,
|
||||
lab_id=lab_id,
|
||||
display_name=display_name,
|
||||
)
|
||||
except (OSError, SessionIntegrityError, ValueError) as exc:
|
||||
console.print(f"[red]E21 LAB publication failed:[/red] {exc}")
|
||||
raise typer.Exit(code=2) from exc
|
||||
console.print(
|
||||
"[green]E21 LAB instance published.[/green] "
|
||||
f"session={published.binding.session_id}; "
|
||||
f"source={published.binding.source_session_id}; "
|
||||
f"result={published.binding.result_id}; "
|
||||
"source_payloads_mutated=false"
|
||||
)
|
||||
|
||||
|
||||
@app.command("serve")
|
||||
def serve_console(
|
||||
port: Annotated[
|
||||
|
||||
Reference in New Issue
Block a user