Robotics Cell: Conveyor Sorting with Deterministic State
A single robot tracks items on a moving conveyor, reconciles sensor updates, and performs pick/place into grid bins with deterministic replay.
If you are reading this cold, this is a deterministic pick-and-place workflow with sensor correction and conflict recovery. Every step is an auditable commit with metadata and idempotency keys so you can replay or diagnose runs without guesswork.
The Problem: When Sensors and Planners Disagree
In production robotics, your vision system reports one position, your encoder says another, and your planner assumes a third. When a pick fails, you have three conflicting logs and no single source of truth. Was it:
- Sensor drift during the conveyor move?
- A stale position in the motion planner?
- A race condition between the vision update and the pick command?
Without deterministic state, debugging becomes archaeology. With AssetCore, every state change is a timestamped, auditable commit. Sensor corrections, planner updates, and execution commands all flow through one authoritative log. When something fails, you replay the exact sequence and see what happened - no guesswork.
This scenario demonstrates production-grade patterns: continuous conveyor tracking, vision-based sensor reconciliation, conflict detection with automatic replanning, and deterministic replay for debugging.
Why this matters
Robotics stacks fail when planners, sensors, and execution disagree about ground truth. Asset Core makes state authoritative by treating every change as a deterministic, replayable transaction.
System model
- Conveyor: continuous 1D placements with fixed-point coordinates.
- Bins: grid container that enforces occupancy rules.
- Gripper: slot container so picks are deterministic slot moves.
- Robot pose: continuous 2D container for position and rotation.
- Classes and shapes: registered so collision and placement rules are enforced.
- Units: mm (fixed_point_scale=1000).
Workflow at a glance
- Setup - Register classes/shapes and create containers.
- Seed - Create robot pose, inbound item, and blocked bin.
- Conveyor Advance - Move item based on conveyor speed and encoder ticks.
- Conveyor Reconcile - Apply sensor correction to item position.
- Robot Move - Update the robot pose in continuous 2D.
- Pick - Move item from conveyor into the gripper.
- Place Blocked - Blocked bin returns POSITION_OCCUPIED.
- Grid Free - Find the next available grid anchor.
- Place - Place item into free grid anchor.
- Place Replay - Replay the placement to confirm idempotency.
System Design: What We Chose and Why
This scenario makes specific design choices that reflect AssetCore’s deterministic state model. Here’s what we optimized for and what we traded off.
Choice: Fixed-Point Coordinates
The Choice: All positions use fixed-point integers (fixed_point_scale=1000 means 1 unit = 1mm).
- Why: Floating-point arithmetic is non-deterministic across CPUs - replay could diverge due to rounding differences. Fixed-point guarantees byte-identical replay.
- Trade-off: You must choose precision upfront (1000 = 0.001mm resolution). For most robotics, millimeter precision is sufficient.
- When it matters: Time-travel debugging, disaster recovery, compliance audits all depend on deterministic replay.
Choice: Sensor Reconciliation as Separate Commits
The Choice: Step 3 (encoder update) and Step 4 (vision correction) are separate commits.
- Why: Each state change is an explicit decision with its own metadata. If vision confidence is low, you can query which corrections were applied and replay without them.
- Trade-off: Two commits instead of one (minor latency overhead, typically <1ms per commit).
- When it matters: Debugging sensor drift, validating vision system accuracy, proving compliance.
Choice: Conflict Detection Before State Change
The Choice: Step 7 detects POSITION_OCCUPIED at validation time (L2), before any state mutation.
- Why: No partial commits, no cleanup, no “compensating transactions.” Validation failures are cheap (no I/O), and state stays clean.
- Trade-off: Planner must query for free positions (Step 8) after conflict. Optimistic locking would fail less often but would require rollback logic.
- When it matters: Multi-robot cells with concurrent picks/places. AssetCore’s single-writer per namespace guarantees conflicts are detected deterministically.
Choice: Idempotency Keys for Network Resilience
The Choice: Idempotency keys are optional but, when present, deduplicate retries based on a canonical hash of the full request payload.
- Why: Same key + same payload returns the cached response; same key + different payload is rejected. This prevents duplicate motion commits under retry.
- Trade-off: The authoritative service must generate or derive stable keys per interaction and must not forward untrusted client keys.
- When it matters: At-least-once delivery, retries across flaky links, queue workers, and multi-region failover.
What We Don’t Handle (and Why)
- Motion planning: AssetCore records pose updates, but does not compute trajectories. Integrate with your motion planner (MoveIt, OMPL, custom) and commit the planned poses.
- Real-time control: AssetCore is for state authority, not 1kHz control loops. Use it to coordinate high-level plans and record execution outcomes.
- Sensor fusion: AssetCore stores sensor corrections (Step 4), but does not compute them. Your vision system provides the correction; AssetCore makes it authoritative and replayable.
These are deliberate scope boundaries: AssetCore provides deterministic state management and leaves domain-specific algorithms (motion planning, sensor fusion) to specialized tools.
Idempotency semantics
Idempotency keys are optional and only control retry de-duplication. When a key is present, Asset Core hashes the full request payload and uses (namespace, key, hash) to decide:
- Same key + same payload: return the cached response (no re-execution).
- Same key + different payload: reject with 409 Conflict.
- Failed validation does not reserve the key; reuse after correction is valid.
- No key: request executes normally, retries re-run. In robotics deployments, the orchestration service generates or derives keys and should not forward untrusted client keys.
How to read the walkthrough
- Validation reads/streams are listed separately after the steps.
- Single-operation steps use action helpers for readability.
- Multi-operation steps stay as commit calls to preserve atomicity.
- Rust HTTP always uses the commit endpoint with one or more operations.
Scenario artifacts
- manifest.json - Scenario metadata and IDs.
- robotics_cell_actions.json - Action-first walkthrough payloads.
- robotics_cell_transcript.json - Full request/response log.
- http_snapshot.json - Condensed commit outcomes.
- robotics_cell_steps.json - Deterministic step index.
Latest verification
- Run ID:
2026-01-19T18-43-00Z-robotics_cell - Status: Passed
- Integrity root hash:
53624642c9af8f6caf0e4138541c948e0f5bd09b95d480e5e9e233d7416c3d32 - Checks:
{'kind': 'structural_invariants'}: passed{'kind': 'world_seq_monotonic'}: passed{'kind': 'global_seq_monotonic'}: passed{'kind': 'replay_idempotent'}: passed{'kind': 'commit_log_integrity', 'expected_chain_hash': 'db3c030f7451ac6b5c4abfe5af7f08f3df463f6991cd19adb0beeb643781f455', 'expected_prev_chain_hash': '402bf8dde049d865bc48a2af2d9d5d9ab1e996b6da0dad5bb56118adccd5c1a2', 'expected_start_offset': 1, 'expected_end_offset': 7, 'expected_entry_count': 7, 'expected_last_global_seq': 23}: passed{'kind': 'runpack_integrity'}: passed
Runpack downloads
Scenario snapshot
{
"scenario_id": "robotics_cell",
"version": "0.1.0",
"namespace_id": 1,
"containers": {
"conveyor": "container-31001",
"grid": "container-31002",
"gripper": "container-31003",
"robot_pose": "container-31004"
},
"classes": {
"item": "class-41001",
"robot_pose": "class-41002"
},
"units": {
"fixed_point_scale": 1000,
"length_unit": "mm",
"time_unit": "ms"
}
}
Failure branch
POSITION_OCCUPIED -> grid_free -> retry with same idempotency key
Audit trail (optional)
The transcript captures the exact request and response pairs emitted during the run. Here is a compact excerpt you can use to validate determinism and metadata propagation:
{
"kind": "commit",
"name": "conveyor-reconcile",
"request": {
"path": "/v1/write/namespaces/1/commit",
"idempotency_key": "robotics-cell-reconcile",
"actor_id": "robotics-cell",
"metadata": {
"job_id": "job-robotics-001",
"sensor_ts_ms": 1725000001250,
"step": "conveyor-reconcile",
"trace_id": "trace-robotics-001",
"vision_confidence": 0.78
},
"operations": [
"MoveInstance"
]
},
"response": {
"commit_id": "00000000000000000000000000000002",
"world_seq_start": 15,
"world_seq_end": 16,
"event_count": 2
}
}
Preflight note
- Action calls submit commits by default.
- Set ActionOptions(preflight=True) or call assetcore_commit_preflight for validation.
SDK setup
from assetcore_sdk import AssetCoreClient
from assetcore_sdk.actions import ActionOptions
from assetcore_sdk.operations import (
AddInstance,
CreateContainer,
MoveInstance,
RegisterClass,
RegisterClassContinuousShape1d,
RegisterClassContinuousShape2d,
RegisterClassShape,
)
# Snippets assume an async context (e.g., inside async def main()).
write_client = AssetCoreClient(
base_url="http://localhost:8080",
api_key="WRITE_API_KEY",
)
read_client = AssetCoreClient(
base_url="http://localhost:8081",
api_key="READ_API_KEY",
)#include "asset_core.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
static void check_ok(int32_t code, const char* label) {
if (code == ERROR_SUCCESS) {
return;
}
fprintf(stderr, "%s failed: %d\n", label, code);
abort();
}
OpaqueRuntime* runtime = NULL;
AssetRuntimeConfig config = {0};
config.struct_size = sizeof(AssetRuntimeConfig);
config.clock_type = AssetClockType_System;
check_ok(asset_runtime_create(&config, &runtime), "asset_runtime_create");use reqwest::Client;
use serde_json::json;
let client = Client::new();
let write_base_url = "http://localhost:8080";
let read_base_url = "http://localhost:8081";
let write_api_key = "WRITE_API_KEY";
let read_api_key = "READ_API_KEY";Walkthrough
Step 1: Setup
Register classes/shapes and create containers.
Why this step matters: Robotics workflows need container geometry and class shapes defined before any placement or motion can be validated.
Preconditions:
- None. This is the bootstrap commit.
What this commit creates:
- Conveyor (continuous 1D), bins (grid), gripper (slots), robot pose (continuous 2D).
- Item and robot classes with grid and continuous shapes.
Expected state change:
- Containers and shapes are registered so future MoveInstance operations can be validated.
Operations
CreateContainer(x4) - Creates a container (structured memory region) with the requested kind.RegisterClass(x2) - Registers a class definition so future operations can reference it.RegisterClassShape- Registers a grid shape footprint for a class or class variant.RegisterClassContinuousShape1d- Registers a continuous 1D span for a class or class variant.RegisterClassContinuousShape2d- Registers a continuous 2D rectangle for a class or class variant.
await write_client.commit_operations(
[
CreateContainer(
kind={
"bucket_cell_size": 1000,
"max_x": 39999,
"min_x": 0,
"quantization_inv": 1000,
"type": "continuous_line_1d",
},
policies=None,
external_id="container-31001",
owner_external_id="owner-77",
),
CreateContainer(
kind={"capacity": 16, "grid_width": 4, "type": "grid"},
policies=None,
external_id="container-31002",
owner_external_id="owner-77",
),
CreateContainer(
kind={"count": 2, "type": "slots"},
policies=None,
external_id="container-31003",
owner_external_id="owner-77",
),
CreateContainer(
kind={
"bucket_cell_size": 1000,
"max_x": 9999,
"max_y": 9999,
"min_x": 0,
"min_y": 0,
"quantization_inv": 1000,
"type": "continuous_grid_2d",
},
policies=None,
external_id="container-31004",
owner_external_id="owner-77",
),
RegisterClass(
request={
"behavior": {"balance_scale": 1},
"class_id": "class-41001",
"flags": 0,
"name": "robotics-item-41001",
},
),
RegisterClass(
request={
"behavior": {"balance_scale": 1},
"class_id": "class-41002",
"flags": 0,
"name": "robotics-robot-41002",
},
),
RegisterClassShape(
request={"class_id": "class-41001", "shape": {"height": 1, "width": 1}},
),
RegisterClassContinuousShape1d(
request={"class_id": "class-41001", "span": {"length": 2000}},
),
RegisterClassContinuousShape2d(
request={
"class_id": "class-41002",
"rect": {"height": 1000, "width": 1000},
},
),
],
namespace_id=1,
idempotency_key="robotics-cell-setup",
actor_id="robotics-cell",
metadata={
"job_id": "job-robotics-001",
"step": "setup",
"trace_id": "trace-robotics-001",
},
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
{
AssetContainerKind kind = {0};
kind.kind = AssetContainerKindTag_ContinuousLine1d;
kind.min_x = 0;
kind.max_x = 39999;
kind.quantization_inv = 1000;
kind.bucket_cell_size = 1000;
uint32_t out_container_id = 0;
check_ok(
asset_tx_create_container(runtime, tx, 31001, kind, 77, NULL, &out_container_id),
"asset_tx_create_container[0]");
}
{
AssetContainerKind kind = {0};
kind.kind = AssetContainerKindTag_Grid;
kind.capacity = 16;
kind.grid_width = 4;
uint32_t out_container_id = 0;
check_ok(
asset_tx_create_container(runtime, tx, 31002, kind, 77, NULL, &out_container_id),
"asset_tx_create_container[1]");
}
{
AssetContainerKind kind = {0};
kind.kind = AssetContainerKindTag_Slots;
kind.slots = 2;
uint32_t out_container_id = 0;
check_ok(
asset_tx_create_container(runtime, tx, 31003, kind, 77, NULL, &out_container_id),
"asset_tx_create_container[2]");
}
{
AssetContainerKind kind = {0};
kind.kind = AssetContainerKindTag_ContinuousGrid2d;
kind.min_x = 0;
kind.min_y = 0;
kind.max_x = 9999;
kind.max_y = 9999;
kind.quantization_inv = 1000;
kind.bucket_cell_size = 1000;
uint32_t out_container_id = 0;
check_ok(
asset_tx_create_container(runtime, tx, 31004, kind, 77, NULL, &out_container_id),
"asset_tx_create_container[3]");
}
{
AssetClassBehavior behavior = {0};
behavior.has_balance_scale = 1;
behavior.balance_scale = 1;
uint32_t out_class_id = 0;
check_ok(asset_tx_register_class(runtime,
tx,
41001,
0,
&behavior,
(const uint8_t*)"robotics-item-41001",
19,
&out_class_id),
"asset_tx_register_class[4]");
}
{
AssetClassBehavior behavior = {0};
behavior.has_balance_scale = 1;
behavior.balance_scale = 1;
uint32_t out_class_id = 0;
check_ok(asset_tx_register_class(runtime,
tx,
41002,
0,
&behavior,
(const uint8_t*)"robotics-robot-41002",
20,
&out_class_id),
"asset_tx_register_class[5]");
}
{
AssetItemShape shape = {.width = 1, .height = 1};
uint32_t inserted = 0;
check_ok(asset_tx_register_class_shape(runtime, tx, 41001, 0, shape, &inserted),
"asset_tx_register_class_shape[6]");
}
{
AssetContinuousSpan span = {.length = 2000};
uint32_t inserted = 0;
check_ok(asset_tx_register_class_continuous_shape_1d(
runtime, tx, 41001, 0, span, &inserted),
"asset_tx_register_class_continuous_shape_1d[7]");
}
{
AssetContinuousRect rect = {.width = 1000, .height = 1000};
uint32_t inserted = 0;
check_ok(
asset_tx_register_class_continuous_shape(runtime, tx, 41002, 0, rect, &inserted),
"asset_tx_register_class_continuous_shape[8]");
}
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_commit",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-setup",
"metadata": {
"job_id": "job-robotics-001",
"step": "setup",
"trace_id": "trace-robotics-001"
},
"namespace_id": 1,
"operations": [
{
"args": {
"external_id": "container-31001",
"kind": {
"bucket_cell_size": 1000,
"max_x": 39999,
"min_x": 0,
"quantization_inv": 1000,
"type": "continuous_line_1d"
},
"owner_external_id": "owner-77",
"policies": null
},
"op": "CreateContainer"
},
{
"args": {
"external_id": "container-31002",
"kind": {
"capacity": 16,
"grid_width": 4,
"type": "grid"
},
"owner_external_id": "owner-77",
"policies": null
},
"op": "CreateContainer"
},
{
"args": {
"external_id": "container-31003",
"kind": {
"count": 2,
"type": "slots"
},
"owner_external_id": "owner-77",
"policies": null
},
"op": "CreateContainer"
},
{
"args": {
"external_id": "container-31004",
"kind": {
"bucket_cell_size": 1000,
"max_x": 9999,
"max_y": 9999,
"min_x": 0,
"min_y": 0,
"quantization_inv": 1000,
"type": "continuous_grid_2d"
},
"owner_external_id": "owner-77",
"policies": null
},
"op": "CreateContainer"
},
{
"args": {
"request": {
"behavior": {
"balance_scale": 1
},
"class_id": "class-41001",
"flags": 0,
"name": "robotics-item-41001"
}
},
"op": "RegisterClass"
},
{
"args": {
"request": {
"behavior": {
"balance_scale": 1
},
"class_id": "class-41002",
"flags": 0,
"name": "robotics-robot-41002"
}
},
"op": "RegisterClass"
},
{
"args": {
"request": {
"class_id": "class-41001",
"shape": {
"height": 1,
"width": 1
}
}
},
"op": "RegisterClassShape"
},
{
"args": {
"request": {
"class_id": "class-41001",
"span": {
"length": 2000
}
}
},
"op": "RegisterClassContinuousShape1d"
},
{
"args": {
"request": {
"class_id": "class-41002",
"rect": {
"height": 1000,
"width": 1000
}
}
},
"op": "RegisterClassContinuousShape2d"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-setup",
"metadata": {
"job_id": "job-robotics-001",
"step": "setup",
"trace_id": "trace-robotics-001"
},
"operations": [
{
"args": {
"external_id": "container-31001",
"kind": {
"bucket_cell_size": 1000,
"max_x": 39999,
"min_x": 0,
"quantization_inv": 1000,
"type": "continuous_line_1d"
},
"owner_external_id": "owner-77",
"policies": null
},
"op": "CreateContainer"
},
{
"args": {
"external_id": "container-31002",
"kind": {
"capacity": 16,
"grid_width": 4,
"type": "grid"
},
"owner_external_id": "owner-77",
"policies": null
},
"op": "CreateContainer"
},
{
"args": {
"external_id": "container-31003",
"kind": {
"count": 2,
"type": "slots"
},
"owner_external_id": "owner-77",
"policies": null
},
"op": "CreateContainer"
},
{
"args": {
"external_id": "container-31004",
"kind": {
"bucket_cell_size": 1000,
"max_x": 9999,
"max_y": 9999,
"min_x": 0,
"min_y": 0,
"quantization_inv": 1000,
"type": "continuous_grid_2d"
},
"owner_external_id": "owner-77",
"policies": null
},
"op": "CreateContainer"
},
{
"args": {
"request": {
"behavior": {
"balance_scale": 1
},
"class_id": "class-41001",
"flags": 0,
"name": "robotics-item-41001"
}
},
"op": "RegisterClass"
},
{
"args": {
"request": {
"behavior": {
"balance_scale": 1
},
"class_id": "class-41002",
"flags": 0,
"name": "robotics-robot-41002"
}
},
"op": "RegisterClass"
},
{
"args": {
"request": {
"class_id": "class-41001",
"shape": {
"height": 1,
"width": 1
}
}
},
"op": "RegisterClassShape"
},
{
"args": {
"request": {
"class_id": "class-41001",
"span": {
"length": 2000
}
}
},
"op": "RegisterClassContinuousShape1d"
},
{
"args": {
"request": {
"class_id": "class-41002",
"rect": {
"height": 1000,
"width": 1000
}
}
},
"op": "RegisterClassContinuousShape2d"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Step 2: Seed
Create robot pose, inbound item, and blocked bin.
Why this step matters: Seeding gives the workflow concrete instances to move: a robot pose, an inbound item, and a deliberately blocked bin.
Preconditions:
- Setup commit has created containers and registered classes/shapes.
What to notice in the code:
- Robot pose is placed in continuous 2D.
- Inbound item is placed on the conveyor line.
- Blocked bin item occupies the target grid cell.
Expected state change:
- Robot, inbound item, and blocker instances exist at their starting locations.
Operations
AddInstance(x3) - Mints a new instance and places it at a target location.
await write_client.commit_operations(
[
AddInstance(
class_id="class-41002",
client_tag="robot-arm-1",
key=None,
location={
"container_id": "container-31004",
"coord": {"x": 2000, "y": 3000},
"kind": "continuous_2d",
"rotation_millideg": 0,
},
),
AddInstance(
class_id="class-41001",
client_tag="inbound-item",
key=None,
location={
"container_id": "container-31001",
"coord": {"x": 4000},
"kind": "continuous_1d",
},
),
AddInstance(
class_id="class-41001",
client_tag="blocked-bin",
key=None,
location={
"container_id": "container-31002",
"kind": "grid_cell",
"position": 6,
"rotation": None,
},
),
],
namespace_id=1,
idempotency_key="robotics-cell-seed",
actor_id="robotics-cell",
metadata={
"job_id": "job-robotics-001",
"sensor_ts_ms": 1725000000000,
"step": "seed",
"trace_id": "trace-robotics-001",
"vision_confidence": 0.82,
},
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
AssetInstanceLocation location_0 = {0};
location_0.kind = AssetInstanceLocationKind_Continuous2d;
location_0.container = 31004;
location_0.coord_x = 2000;
location_0.coord_y = 3000;
location_0.rotation_millideg = 0;
{
uint64_t instance_id = 0;
check_ok(
asset_tx_add_instance_semantic(runtime, tx, 41002, 0, location_0, &instance_id),
"asset_tx_add_instance_semantic[0]");
}
AssetInstanceLocation location_1 = {0};
location_1.kind = AssetInstanceLocationKind_Continuous1d;
location_1.container = 31001;
location_1.coord_x = 4000;
{
uint64_t instance_id = 0;
check_ok(
asset_tx_add_instance_semantic(runtime, tx, 41001, 0, location_1, &instance_id),
"asset_tx_add_instance_semantic[1]");
}
AssetInstanceLocation location_2 = {0};
location_2.kind = AssetInstanceLocationKind_GridCell;
location_2.container = 31002;
location_2.position = 6;
location_2.rotation = AssetRotation_None;
{
uint64_t instance_id = 0;
check_ok(
asset_tx_add_instance_semantic(runtime, tx, 41001, 0, location_2, &instance_id),
"asset_tx_add_instance_semantic[2]");
}
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_commit",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-seed",
"metadata": {
"job_id": "job-robotics-001",
"sensor_ts_ms": 1725000000000,
"step": "seed",
"trace_id": "trace-robotics-001",
"vision_confidence": 0.82
},
"namespace_id": 1,
"operations": [
{
"args": {
"class_id": "class-41002",
"client_tag": "robot-arm-1",
"key": null,
"location": {
"container_id": "container-31004",
"coord": {
"x": 2000,
"y": 3000
},
"kind": "continuous_2d",
"rotation_millideg": 0
}
},
"op": "AddInstance"
},
{
"args": {
"class_id": "class-41001",
"client_tag": "inbound-item",
"key": null,
"location": {
"container_id": "container-31001",
"coord": {
"x": 4000
},
"kind": "continuous_1d"
}
},
"op": "AddInstance"
},
{
"args": {
"class_id": "class-41001",
"client_tag": "blocked-bin",
"key": null,
"location": {
"container_id": "container-31002",
"kind": "grid_cell",
"position": 6,
"rotation": null
}
},
"op": "AddInstance"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-seed",
"metadata": {
"job_id": "job-robotics-001",
"sensor_ts_ms": 1725000000000,
"step": "seed",
"trace_id": "trace-robotics-001",
"vision_confidence": 0.82
},
"operations": [
{
"args": {
"class_id": "class-41002",
"client_tag": "robot-arm-1",
"key": null,
"location": {
"container_id": "container-31004",
"coord": {
"x": 2000,
"y": 3000
},
"kind": "continuous_2d",
"rotation_millideg": 0
}
},
"op": "AddInstance"
},
{
"args": {
"class_id": "class-41001",
"client_tag": "inbound-item",
"key": null,
"location": {
"container_id": "container-31001",
"coord": {
"x": 4000
},
"kind": "continuous_1d"
}
},
"op": "AddInstance"
},
{
"args": {
"class_id": "class-41001",
"client_tag": "blocked-bin",
"key": null,
"location": {
"container_id": "container-31002",
"kind": "grid_cell",
"position": 6,
"rotation": null
}
},
"op": "AddInstance"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Step 3: Conveyor Advance
Move item based on conveyor speed and encoder ticks.
Why this step matters: The conveyor belt moves items based on encoder ticks. In a non-deterministic system, you’d trust the encoder’s tick count and hope it matches reality. AssetCore records the exact position as a commit - timestamped, with encoder metadata - so if a pick fails later, you can replay from this point and see whether the encoder position was correct or if sensor drift occurred.
Preconditions:
- The inbound item exists on the conveyor from the seed commit.
What AssetCore provides:
- Position updates are atomic commits (no partial moves)
- Metadata captures encoder ticks and speed for forensic analysis
- Idempotency key ensures replaying this commit produces the same state
What to notice in the code:
encoder_ticks: 1825andspeed_mm_s: 450in metadata - captured for audit- Continuous 1D coordinate
x: 10000(10mm with fixed_point_scale=1000) - Idempotency key
robotics-cell-advanceprevents duplicate moves on retry
Expected state change:
- The inbound item moves to the new conveyor coordinate.
Operations
MoveInstance- Moves an existing instance to a new location.
await write_client.actions.move_instance(
instance="inst-2",
to={
"container_id": "container-31001",
"coord": {"x": 10000},
"kind": "continuous_1d",
},
options=ActionOptions(
namespace_id=1,
idempotency_key="robotics-cell-advance",
actor_id="robotics-cell",
metadata={
"encoder_ticks": 1825,
"job_id": "job-robotics-001",
"speed_mm_s": 450,
"step": "conveyor-advance",
"trace_id": "trace-robotics-001",
},
),
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
AssetInstanceLocation location_0 = {0};
location_0.kind = AssetInstanceLocationKind_Continuous1d;
location_0.container = 31001;
location_0.coord_x = 10000;
check_ok(asset_tx_move_instance_semantic(runtime, tx, 2, location_0),
"asset_tx_move_instance_semantic[0]");
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_move_instance",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-advance",
"metadata": {
"encoder_ticks": 1825,
"job_id": "job-robotics-001",
"speed_mm_s": 450,
"step": "conveyor-advance",
"trace_id": "trace-robotics-001"
},
"namespace_id": 1,
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31001",
"coord": {
"x": 10000
},
"kind": "continuous_1d"
}
},
"op": "MoveInstance"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-advance",
"metadata": {
"encoder_ticks": 1825,
"job_id": "job-robotics-001",
"speed_mm_s": 450,
"step": "conveyor-advance",
"trace_id": "trace-robotics-001"
},
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31001",
"coord": {
"x": 10000
},
"kind": "continuous_1d"
}
},
"op": "MoveInstance"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Step 4: Conveyor Reconcile
Apply sensor correction to item position.
Why this step matters:
Vision system detects actual position differs from encoder estimate (10000mm encoder vs 11250mm vision). AssetCore applies the correction as a separate commit with vision_confidence: 0.78 metadata. If you replay from this point, you see the exact sensor correction that was applied.
Preconditions:
- The inbound item remains on the conveyor after the advance step.
What AssetCore provides:
- Sensor corrections are first-class commits with metadata
- Low-confidence corrections are recorded for later analysis
- Replay shows exact delta between encoder and vision estimates
What to notice in the code:
- Delta of 1250mm (12.5% drift from encoder estimate)
- Vision confidence 0.78 captured in metadata
- Separate commit allows querying “which corrections were applied”
Expected state change:
- The inbound item moves to the corrected coordinate.
Operations
MoveInstance- Moves an existing instance to a new location.
await write_client.actions.move_instance(
instance="inst-2",
to={
"container_id": "container-31001",
"coord": {"x": 11250},
"kind": "continuous_1d",
},
options=ActionOptions(
namespace_id=1,
idempotency_key="robotics-cell-reconcile",
actor_id="robotics-cell",
metadata={
"job_id": "job-robotics-001",
"sensor_ts_ms": 1725000001250,
"step": "conveyor-reconcile",
"trace_id": "trace-robotics-001",
"vision_confidence": 0.78,
},
),
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
AssetInstanceLocation location_0 = {0};
location_0.kind = AssetInstanceLocationKind_Continuous1d;
location_0.container = 31001;
location_0.coord_x = 11250;
check_ok(asset_tx_move_instance_semantic(runtime, tx, 2, location_0),
"asset_tx_move_instance_semantic[0]");
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_move_instance",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-reconcile",
"metadata": {
"job_id": "job-robotics-001",
"sensor_ts_ms": 1725000001250,
"step": "conveyor-reconcile",
"trace_id": "trace-robotics-001",
"vision_confidence": 0.78
},
"namespace_id": 1,
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31001",
"coord": {
"x": 11250
},
"kind": "continuous_1d"
}
},
"op": "MoveInstance"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-reconcile",
"metadata": {
"job_id": "job-robotics-001",
"sensor_ts_ms": 1725000001250,
"step": "conveyor-reconcile",
"trace_id": "trace-robotics-001",
"vision_confidence": 0.78
},
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31001",
"coord": {
"x": 11250
},
"kind": "continuous_1d"
}
},
"op": "MoveInstance"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Step 5: Robot Move
Update the robot pose in continuous 2D.
Why this step matters: Robot pose updates are authoritative state changes, not planner suggestions. Recording them as commits makes motion audit-ready.
Preconditions:
- The robot instance exists in the pose container from the seed commit.
What to notice in the code:
- MoveInstance targets a continuous 2D container with fixed-point coordinates.
Expected state change:
- The robot pose updates to the new X/Y coordinate.
Operations
MoveInstance- Moves an existing instance to a new location.
await write_client.actions.move_instance(
instance="inst-1",
to={
"container_id": "container-31004",
"coord": {"x": 3500, "y": 4000},
"kind": "continuous_2d",
"rotation_millideg": 0,
},
options=ActionOptions(
namespace_id=1,
idempotency_key="robotics-cell-robot-move",
actor_id="robotics-cell",
metadata={
"job_id": "job-robotics-001",
"step": "robot-move",
"trace_id": "trace-robotics-001",
},
),
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
AssetInstanceLocation location_0 = {0};
location_0.kind = AssetInstanceLocationKind_Continuous2d;
location_0.container = 31004;
location_0.coord_x = 3500;
location_0.coord_y = 4000;
location_0.rotation_millideg = 0;
check_ok(asset_tx_move_instance_semantic(runtime, tx, 1, location_0),
"asset_tx_move_instance_semantic[0]");
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_move_instance",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-robot-move",
"metadata": {
"job_id": "job-robotics-001",
"step": "robot-move",
"trace_id": "trace-robotics-001"
},
"namespace_id": 1,
"operations": [
{
"args": {
"instance": "inst-1",
"to": {
"container_id": "container-31004",
"coord": {
"x": 3500,
"y": 4000
},
"kind": "continuous_2d",
"rotation_millideg": 0
}
},
"op": "MoveInstance"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-robot-move",
"metadata": {
"job_id": "job-robotics-001",
"step": "robot-move",
"trace_id": "trace-robotics-001"
},
"operations": [
{
"args": {
"instance": "inst-1",
"to": {
"container_id": "container-31004",
"coord": {
"x": 3500,
"y": 4000
},
"kind": "continuous_2d",
"rotation_millideg": 0
}
},
"op": "MoveInstance"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Step 6: Pick
Move item from conveyor into the gripper.
Why this step matters: Picking is a deterministic move from conveyor to gripper. There is no hidden state - the item leaves one container and enters another.
Preconditions:
- The inbound item is on the conveyor.
- The target gripper slot is empty.
What to notice in the code:
- MoveInstance targets a slot container (gripper).
Expected state change:
- The item leaves the conveyor container and occupies the gripper slot.
Operations
MoveInstance- Moves an existing instance to a new location.
await write_client.actions.move_instance(
instance="inst-2",
to={"container_id": "container-31003", "kind": "slot", "slot_index": 1},
options=ActionOptions(
namespace_id=1,
idempotency_key="robotics-cell-pick",
actor_id="robotics-cell",
metadata={
"job_id": "job-robotics-001",
"step": "pick",
"trace_id": "trace-robotics-001",
},
),
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
AssetInstanceLocation location_0 = {0};
location_0.kind = AssetInstanceLocationKind_Slot;
location_0.container = 31003;
location_0.slot = 1;
check_ok(asset_tx_move_instance_semantic(runtime, tx, 2, location_0),
"asset_tx_move_instance_semantic[0]");
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_move_instance",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-pick",
"metadata": {
"job_id": "job-robotics-001",
"step": "pick",
"trace_id": "trace-robotics-001"
},
"namespace_id": 1,
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31003",
"kind": "slot",
"slot_index": 1
}
},
"op": "MoveInstance"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-pick",
"metadata": {
"job_id": "job-robotics-001",
"step": "pick",
"trace_id": "trace-robotics-001"
},
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31003",
"kind": "slot",
"slot_index": 1
}
},
"op": "MoveInstance"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Step 7: Place Blocked (Expected error)
Blocked bin returns POSITION_OCCUPIED.
Why this step matters: Bin position 6 is occupied. AssetCore returns POSITION_OCCUPIED error before any state change. No partial commit, no cleanup required. The conflict detection happens at validation time (L2), so your state stays clean.
Preconditions:
- The item is in the gripper slot.
- The target grid cell is occupied by the blocker.
What AssetCore provides:
- Conflicts detected before state mutation (cheap validation)
- Error response includes exact conflict details (which position, which item)
- Idempotency key preserved for retry with corrected position
What to notice in the code:
- Error is deterministic (not a race condition)
retryable: falsemeans client must change the request (query for free position)- Same idempotency key is reused after replanning
Expected state change:
- No state changes are applied; this is a deterministic validation failure.
Operations
MoveInstance- Moves an existing instance to a new location.
Expected error
{
"code": "POSITION_OCCUPIED",
"detail": "Position 6 in container 2 is occupied by item at anchor 6",
"hint": "Select an unoccupied position or move the existing item first.",
"retryable": false,
"status": 409,
"title": "ConflictError",
"type": "urn:assetcore:error:POSITION_OCCUPIED"
}
await write_client.actions.move_instance(
instance="inst-2",
to={
"container_id": "container-31002",
"kind": "grid_cell",
"position": 6,
"rotation": None,
},
options=ActionOptions(
namespace_id=1,
idempotency_key="robotics-cell-place",
actor_id="robotics-cell",
metadata={
"job_id": "job-robotics-001",
"step": "place-attempt",
"trace_id": "trace-robotics-001",
},
),
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
AssetInstanceLocation location_0 = {0};
location_0.kind = AssetInstanceLocationKind_GridCell;
location_0.container = 31002;
location_0.position = 6;
location_0.rotation = AssetRotation_None;
check_ok(asset_tx_move_instance_semantic(runtime, tx, 2, location_0),
"asset_tx_move_instance_semantic[0]");
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_move_instance",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-place",
"metadata": {
"job_id": "job-robotics-001",
"step": "place-attempt",
"trace_id": "trace-robotics-001"
},
"namespace_id": 1,
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31002",
"kind": "grid_cell",
"position": 6,
"rotation": null
}
},
"op": "MoveInstance"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-place",
"metadata": {
"job_id": "job-robotics-001",
"step": "place-attempt",
"trace_id": "trace-robotics-001"
},
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31002",
"kind": "grid_cell",
"position": 6,
"rotation": null
}
},
"op": "MoveInstance"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Step 8: Grid Free
Find the next available grid anchor.
Why this step matters: After detecting the conflict, the planner queries for free grid positions. This read operation sees the current projection - no locks, no blocking. AssetCore’s read scalability means planners can continuously query for available positions without impacting write throughput.
Preconditions:
- A placement attempt failed due to an occupied grid cell.
What AssetCore provides:
- Read queries never block writes (CQRS architecture)
- Grid-free query returns first available position deterministically
- Freshness lag is bounded and measurable (see response metadata)
What to notice in the code:
- Query parameters:
height=1, width=1(item footprint) - Response returns position 1 (first free anchor in row-major order)
- No transaction required (read-only query)
Expected state change:
- None. This is a read-only planning query.
await read_client.get_container_grid_free(
container_id="container-31002",
namespace_id=1,
height=1,
width=1,
){
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_find_grid_free",
"params": {
"container_id": "container-31002",
"height": 1,
"namespace_id": 1,
"width": 1
}
}let request = client
.get(format!("{}/v1/read/namespaces/1/containers/container-31002/grid/free", read_base_url))
.query(&[("height", 1), ("width", 1)])
.bearer_auth(read_api_key)
.send()
.await?;
let body = request.text().await?;Step 9: Place
Place item into free grid anchor.
Why this step matters: Replanned placement commits the corrected anchor in one atomic move from the gripper to the grid.
Preconditions:
- The item remains in the gripper.
- The free anchor returned by grid_free is still available.
What to notice in the code:
- MoveInstance targets the free grid cell returned by the read step.
Expected state change:
- The item leaves the gripper and occupies the free grid cell.
Operations
MoveInstance- Moves an existing instance to a new location.
await write_client.actions.move_instance(
instance="inst-2",
to={
"container_id": "container-31002",
"kind": "grid_cell",
"position": 1,
"rotation": None,
},
options=ActionOptions(
namespace_id=1,
idempotency_key="robotics-cell-place",
actor_id="robotics-cell",
metadata={
"job_id": "job-robotics-001",
"replan_reason": "grid_free",
"step": "place",
"trace_id": "trace-robotics-001",
},
),
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
AssetInstanceLocation location_0 = {0};
location_0.kind = AssetInstanceLocationKind_GridCell;
location_0.container = 31002;
location_0.position = 1;
location_0.rotation = AssetRotation_None;
check_ok(asset_tx_move_instance_semantic(runtime, tx, 2, location_0),
"asset_tx_move_instance_semantic[0]");
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_move_instance",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-place",
"metadata": {
"job_id": "job-robotics-001",
"replan_reason": "grid_free",
"step": "place",
"trace_id": "trace-robotics-001"
},
"namespace_id": 1,
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31002",
"kind": "grid_cell",
"position": 1,
"rotation": null
}
},
"op": "MoveInstance"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-place",
"metadata": {
"job_id": "job-robotics-001",
"replan_reason": "grid_free",
"step": "place",
"trace_id": "trace-robotics-001"
},
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31002",
"kind": "grid_cell",
"position": 1,
"rotation": null
}
},
"op": "MoveInstance"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Step 10: Place Replay
Replay the placement to confirm idempotency.
Why this step matters: Replaying the exact same commit (same idempotency key) returns success without duplicate effects. This is how AssetCore guarantees idempotency - replaying the log always produces the same state. In a distributed system, this means network retries are safe.
Preconditions:
- The placement commit has already succeeded.
What AssetCore provides:
- Idempotency at the commit level (not just HTTP)
- Replay produces same
commit_idandworld_seqas original - Safe to retry any operation without state corruption
What to notice in the code:
- Identical payload to the successful placement (same key, same operations)
- Response confirms no new events generated (idempotent)
- This is how disaster recovery works: replay the entire log
Expected state change:
- None. The replay returns the cached commit.
Operations
MoveInstance- Moves an existing instance to a new location.
await write_client.actions.move_instance(
instance="inst-2",
to={
"container_id": "container-31002",
"kind": "grid_cell",
"position": 1,
"rotation": None,
},
options=ActionOptions(
namespace_id=1,
idempotency_key="robotics-cell-place",
actor_id="robotics-cell",
metadata={
"job_id": "job-robotics-001",
"replan_reason": "grid_free",
"step": "place",
"trace_id": "trace-robotics-001",
},
),
)OpaqueTransaction* tx = NULL;
check_ok(asset_tx_begin(runtime, 1, &tx), "asset_tx_begin");
AssetInstanceLocation location_0 = {0};
location_0.kind = AssetInstanceLocationKind_GridCell;
location_0.container = 31002;
location_0.position = 1;
location_0.rotation = AssetRotation_None;
check_ok(asset_tx_move_instance_semantic(runtime, tx, 2, location_0),
"asset_tx_move_instance_semantic[0]");
AssetTxMeta meta = {0};
OpaqueEventBatch* batch = NULL;
check_ok(asset_tx_commit(runtime, tx, &meta, &batch), "asset_tx_commit");
asset_event_batch_destroy(runtime, batch);{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_move_instance",
"params": {
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-place",
"metadata": {
"job_id": "job-robotics-001",
"replan_reason": "grid_free",
"step": "place",
"trace_id": "trace-robotics-001"
},
"namespace_id": 1,
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31002",
"kind": "grid_cell",
"position": 1,
"rotation": null
}
},
"op": "MoveInstance"
}
]
}
}let payload = json!({
"actor_id": "robotics-cell",
"idempotency_key": "robotics-cell-place",
"metadata": {
"job_id": "job-robotics-001",
"replan_reason": "grid_free",
"step": "place",
"trace_id": "trace-robotics-001"
},
"operations": [
{
"args": {
"instance": "inst-2",
"to": {
"container_id": "container-31002",
"kind": "grid_cell",
"position": 1,
"rotation": null
}
},
"op": "MoveInstance"
}
]
});
let response = client
.post(format!("{}/v1/write/namespaces/1/commit", write_base_url))
.bearer_auth(write_api_key)
.json(&payload)
.send()
.await?;Validation
These reads and streams confirm the final state after the steps without mutating anything.
Read 1: Read Conveyor
Verify conveyor placements are empty.
await read_client.get_container_continuous_placements_1d(
container_id="container-31001",
namespace_id=1,
){
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_get_container_continuous_placements_1d",
"params": {
"container_id": "container-31001",
"namespace_id": 1
}
}let request = client
.get(format!("{}/v1/read/namespaces/1/containers/container-31001/continuous_1d/placements", read_base_url))
.bearer_auth(read_api_key)
.send()
.await?;
let body = request.text().await?;Read 2: Read Slots
Verify gripper slots are empty.
await read_client.get_container_slots(
container_id="container-31003",
namespace_id=1,
)let request = client
.get(format!("{}/v1/read/namespaces/1/containers/container-31003/slots", read_base_url))
.bearer_auth(read_api_key)
.send()
.await?;
let body = request.text().await?;Read 3: Read Grid
Verify grid placements contain blocker and item.
await read_client.get_container_grid(
container_id="container-31002",
namespace_id=1,
){
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_get_container_grid",
"params": {
"container_id": "container-31002",
"namespace_id": 1
}
}let request = client
.get(format!("{}/v1/read/namespaces/1/containers/container-31002/grid/cells", read_base_url))
.bearer_auth(read_api_key)
.send()
.await?;
let body = request.text().await?;Read 4: Read Robot
Verify robot pose placement.
await read_client.get_container_continuous_placements_2d(
container_id="container-31004",
namespace_id=1,
){
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_get_container_continuous_placements_2d",
"params": {
"container_id": "container-31004",
"namespace_id": 1
}
}let request = client
.get(format!("{}/v1/read/namespaces/1/containers/container-31004/continuous_2d/placements", read_base_url))
.bearer_auth(read_api_key)
.send()
.await?;
let body = request.text().await?;Stream 5: Stream Commit
Read the placement commit from SSE.
{
"id": 1,
"jsonrpc": "2.0",
"method": "assetcore_read_stream",
"params": {
"from_world_seq": 22,
"limit": 1,
"namespace_id": 1
}
}let request = client
.get(format!("{}/v1/read/namespaces/1/stream", read_base_url))
.query(&[("from_world_seq", 22), ("limit", 1)])
.bearer_auth(read_api_key)
.send()
.await?;
let body = request.text().await?;What This Proves: Production-Grade Robotics with Deterministic Guarantees
This scenario demonstrates the complexity of production pick-and-place workflows: continuous position tracking, sensor reconciliation, conflict detection, and automatic replanning.
Proof Point 1: Every State Change is Auditable
Each commit carries metadata: job_id, trace_id, sensor_ts_ms, vision_confidence. When a pick fails, you do not guess - you query the commit log and see:
- Exact encoder position at conveyor advance
- Vision correction applied (delta: 1250mm, confidence: 0.78)
- Which grid position was blocked
- New grid position selected after replanning
Proof Point 2: Conflict Detection Without Locking
Step 7 shows POSITION_OCCUPIED detection at validation time. No distributed locks, no coordination overhead. AssetCore’s single-writer architecture makes conflicts deterministic: they are detected before any state change, and the error response tells you exactly what to fix.
Proof Point 3: Idempotent Replay for Debugging
Step 10 proves idempotency: replaying the exact same commit (same idempotency key, same operations) succeeds without side effects. This is how you debug production failures:
- Export the commit log from the failure window
- Replay locally to reproduce exact state
- Inspect intermediate state at any commit
- Fix the issue and verify with replay
Business Value: From “It Failed” to “Here’s Why”
Traditional robotics stacks give you three conflicting logs (vision, planner, execution) and force you to reconstruct what happened. AssetCore gives you one authoritative log where every state change is timestamped, attributed (actor_id), and replayable.
For commissioning: Replay production runs to validate cell behavior
For debugging: Time-travel to the exact commit where failure occurred
For compliance: Export immutable audit trail with sensor metadata
For optimization: Analyze commit metadata to identify bottlenecks
This is what world-class tooling enables: deterministic state management that lets you focus on robotics domain logic instead of fighting state reconciliation bugs.
Next Steps
- Try it locally: Clone the repo and run the scenario to execute this workflow
- Extend it: Add multi-robot coordination by sharding across namespaces
- Integrate it: See SDK Reference for production integration patterns
- Ask us: Book a technical deep-dive to discuss your robotics use case