feat(perception): publish immutable lab session instances

This commit is contained in:
DCCONSTRUCTIONS
2026-07-23 20:13:40 +03:00
parent f1f8e21b78
commit 10019a454a
16 changed files with 1970 additions and 30 deletions
+130 -1
View File
@@ -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[