Skip to content

KNAT Application Profile: Vehicle Entity

Purpose

This document defines the KNAT application profile for a Vehicle Entity — a transport-class Janet entity with a mechanical drivetrain, a driver binding slot, and a physics plane shared with other moving actors.

The goal of this profile is to allow KNAT clients to:

  • observe the mechanical state of a running vehicle (rpm, gear, steering angle, speed)
  • determine which entity is currently mounted as driver
  • inject control inputs (where authorized — driver only)
  • subscribe to vehicle-scoped event signals (damage, collision, etc.)
  • locate the vehicle in world space via its region coupling

This profile intentionally does not model:

  • the internal component simulation (that is the vehicle physics engine's concern)
  • passenger bindings beyond the driver slot (future: occupant surface)
  • cargo inventory (future: inventory surface)
  • world-level routing or route state (that is the transport segment surface)
  • governance or economic participation (those are Brand surfaces)

Those surfaces exist elsewhere in the system.

This profile exposes the runtime mechanics and binding state of the vehicle actor itself.


Conceptual Model

A vehicle is not an autonomous actor — it is a mechanical extension of its driver. The distinction shapes the entire surface:

Biologic surface   → what the body is doing (pose + physiology + intent)
Vehicle surface    → what the machine is doing (drivetrain + physics + binding)

The control surface of a vehicle is uniquely access-gated at the binding layer, not just policy-shaped. VehicleEntity.write_control() will reject writes from any entity that is not the currently mounted driver. This is a harder gate than the biologic view projection mechanism.

Within the KNAT graph, a vehicle exposes three categories of surface:

Structural surfaces — compiled from the spec, stable for the lifetime of the entity:

spec          provenance, genome, architecture

Live simulation surfaces — updated each frame by the vehicle physics engine:

drivetrain    rpm, gear, steering_angle
physics       speed (shared /world/physics/* prefix)
driver        bound state, entity_id of current driver

Intent surface — written by the mounted driver, not by the simulation:

control       steering, throttle, brake, clutch, gear, handbrake

The intent surface is doubly protected: it is absent or redacted in projected view, and every write is rejected at the entity layer unless the caller is the registered driver.


Root Graph

A vehicle entity KNAT surface is rooted at:

/vehicle::<entity_id>/

Top-level families:

/vehicle::<entity_id>/
    /spec
    /engine
    /location
    /drivetrain
    /physics
    /control
    /driver
    /signals

Shared paths with other entity subtypes:

/world/runtime/state      "initializing" → "running"
/world/runtime/frame      monotonically increasing integer
/world/physics/speed      current speed in m/s (same path used by biologic)

Spec Surface

Provenance of the vehicle spec this entity was instantiated from. Static after instantiation.

/vehicle::<entity_id>/spec/ref
/vehicle::<entity_id>/spec/genome
/vehicle::<entity_id>/spec/architecture
node type capabilities
ref String read
genome String read
architecture String read

architecture is the free-form discriminant from the vehicle spec (e.g. brands.common.vehicle.passenger.beatle.front_engine_rwd). Consumers building renderers or drivetrain visualisers should read it first to determine which components and joint types are valid.


Engine Surface

Identity of the engine presenting this vehicle. Present on all Janet brand objects exposed via KNAT.

/vehicle::<entity_id>/engine/name
/vehicle::<entity_id>/engine/version
node type capabilities
name String read
version String read

Location Surface

The cross-domain binding between this vehicle and the region field it currently occupies. Same seam pattern as the biologic location surface — region and vehicle KNAT surfaces are coupled here.

/vehicle::<entity_id>/location/region_id
/vehicle::<entity_id>/location/cell_id
node type capabilities
region_id String read, subscribe
cell_id String read, subscribe

region_id matches the id field in the corresponding RegionRuntime snapshot. cell_id matches a stable key in RegionRuntime.cells.


Drivetrain Surface

Live mechanical state of the powertrain and steering system. Written each step by VehicleSurface.step(). These are outputs, not inputs — they reflect what the machine is currently doing, not what the driver has asked for.

/vehicle::<entity_id>/drivetrain/rpm
/vehicle::<entity_id>/drivetrain/gear
/vehicle::<entity_id>/drivetrain/steering_angle

Mapped from KNAT graph paths:

surface path graph path type capabilities notes
drivetrain.rpm /vehicle/state/rpm Float read, subscribe engine RPM; 0 = off, max ≈ 7000
drivetrain.gear /vehicle/state/gear Integer read, subscribe -1 reverse, 0 neutral, 1–6 fwd
drivetrain.steering_angle /vehicle/state/steering_angle Float read, subscribe radians; ±π/4 maximum

rpm is lerped toward the throttle target each step (factor RPM_LERP = 0.15). It does not jump instantly — consumers can observe the ramp-up and engine braking behaviour directly.

steering_angle is the actual mechanical angle, derived from control.steering × MAX_STEERING_ANGLE. It tracks the driver input with no lag (direct mapping in the current model).


Physics Surface

Observable physical state shared with other entity subtypes. The /world/physics/ prefix is the canonical path shared by biologic, vehicle, and future droid surfaces — systems tracking all moving actors can use it uniformly.

/world/physics/speed
node graph path type capabilities units
speed /world/physics/speed Float read, subscribe m/s

Speed is derived from rpm × gear_ratio × SPEED_SCALE, reduced by braking. It is always ≥ 0. Additional physical observables (acceleration, heading, position) will be added under /world/physics/ as the physics model matures.


Control Surface

The driver intent injection surface. Present in full view; absent or redacted in projected view for observers who are not the mounted driver.

/vehicle/control/steering
/vehicle/control/throttle
/vehicle/control/brake
/vehicle/control/clutch
/vehicle/control/gear
/vehicle/control/handbrake
path type range binding target
steering Float -1.0 .. 1.0 steering_column.angle
throttle Float 0.0 .. 1.0 engine_crank.torque
brake Float 0.0 .. 1.0 (friction model)
clutch Float 0.0 .. 1.0 clutch.engagement
gear Integer -1 .. 6 transmission.ratio_index
handbrake Float 0.0 .. 1.0 rear_diff.brake_torque

The binding map (defined in bindings.json) wires each KNAT path to its mechanical simulation target node. When writing, the caller must be the entity currently registered in the driver slot — VehicleEntity.write_control() returns EntityError::EntityNotOwned otherwise.

On dismount (VehicleEntity.dismount_driver()), all control inputs are reset to neutral: throttle 0.0, brake 0.0, steering 0.0, gear 0. This is enforced in code, not by the driver.

Control values may be raw scalars or structured objects with arbitration metadata:

# scalar (direct driver input)
throttle: 0.7

# structured (system-written, e.g. cruise control assist)
throttle:
  value: 0.7
  source: entity::alice
  mode: direct

mode values:

mode meaning
direct driver input passthrough
assist driver-assist overlay (steering correction, ABS)
override autonomous system overriding driver input

Consumers reading control must handle both forms. The structured form does not imply the driver is absent — mode: direct + source: entity::alice is the normal form when full arbitration tracing is enabled.


Driver Surface

Current driver binding state. A vehicle carries exactly one driver at a time.

/vehicle::<entity_id>/driver/bound
/vehicle::<entity_id>/driver/entity_id
path type capabilities notes
bound Boolean read, subscribe true when a driver is mounted
entity_id String read, subscribe absent when bound = false

Subscribe to bound to detect mount/dismount events. When bound transitions from true to false, all control inputs have already been neutralised by the engine — no further cleanup is needed by the consumer.

entity_id matches an EntityId in the system's EntityRegistry. Cross-reference against the biologic or droid surface at that id to characterize the driver.


Signals Surface

Active signals emitted by or directed at this vehicle. Keyed by signal_id. Vehicle signals are mechanical and environmental events — distinct from game-domain matcher events and from biologic behavioral signals.

/vehicle::<entity_id>/signals/<signal_id>/kind
/vehicle::<entity_id>/signals/<signal_id>/intensity
/vehicle::<entity_id>/signals/<signal_id>/frame
/vehicle::<entity_id>/signals/<signal_id>/source
/vehicle::<entity_id>/signals/<signal_id>/target
node type capabilities notes
kind String read, subscribe e.g. damage, collision, fuel_low, speed_limit_breach, alert
intensity Float read, subscribe 0.0 – 1.0
frame Integer read emission frame
source String read optional: cell_id, entity_id, or chem path
target String read optional: entity_id or system name

Drivetrain Constants (Physics Reference)

These constants are baked into VehicleSurface and define the mock physics model. Consumers interpreting telemetry should be aware of them:

constant value meaning
GEAR_RATIOS [0,0, 3.5, 2.1, 1.4, 1.0, 0.8, 0.65] index by gear+1; rev/neutral both 0
MAX_RPM 7000 RPM ceiling
IDLE_RPM 800 RPM floor when in gear
RPM_LERP 0.15 RPM approach rate per step
SPEED_SCALE 0.002 rpm × gear_ratio × scale → m/s
BRAKE_FACTOR 0.25 fraction of speed shed per step at full brake
MAX_STEERING ±π/4 rad maximum steering angle (45°)

Gear index convention: control input and drivetrain.gear use the same range. -1 = reverse (gear_ratio 0 in current model; reverse kinematics not yet implemented), 0 = neutral, 16 = forward.


Cross-Domain Joins

Join Key Description
vehicle → region location.region_id + location.cell_id Vehicle placement in regional space. Same join as biologic location.
vehicle → driver driver.entity_id Resolves to the biologic or droid surface of the mounted driver.
vehicle → world physics /world/physics/speed Shared speed path across all moving entity subtypes.
vehicle ↔ transport segment region_id + cell_id World transport segments reference region nodes; vehicle location determines which segment it occupies.

Responsibilities Boundary

VehicleOwned    — control inputs, drivetrain state, driver binding slot
PhysicsOwned    — speed derivation, brake blending, RPM lerp
BindingOwned    — write authorization (who may write to control nodes)
RegionOwned     — location, terrain friction, cell environment
DriverOwned     — intent values written to /vehicle/control/*

The vehicle surface in KNAT only exposes VehicleOwned and PhysicsOwned outputs. Never write executor or region-owned state into this surface.


MVP Presence

A minimal valid vehicle KNAT snapshot must include:

  • id, frame, engine, view
  • location.region_id, location.cell_id
  • drivetrain.rpm, drivetrain.gear, drivetrain.steering_angle
  • physics.speed
  • driver.bound
  • signals (may be empty object)
  • spec.ref, spec.genome, spec.architecture

The control surface may be omitted entirely in projected view. Consumers must handle its absence.


Example Snapshot

{
    "id": "vehicle::beatle_001",
    "spec": {
        "ref": "file://defs/vehicle/examples/beatle.yml",
        "genome": "000A1C0000",
        "architecture": "brands.common.vehicle.passenger.beatle.front_engine_rwd"
    },
    "engine": { "name": "janet-executor", "version": "0.4.0" },
    "view": "full",
    "frame": 312,
    "location": {
        "region_id": "samanga",
        "cell_id": "cell_042"
    },
    "drivetrain": {
        "rpm": 3210.4,
        "gear": 3,
        "steering_angle": 0.18
    },
    "physics": {
        "speed": 9.53
    },
    "control": {
        "steering": { "value": 0.24, "source": "entity::alice", "mode": "direct" },
        "throttle": { "value": 0.6,  "source": "entity::alice", "mode": "direct" },
        "brake":    0.0,
        "clutch":   0.0,
        "gear":     3,
        "handbrake": 0.0
    },
    "driver": {
        "bound": true,
        "entity_id": "entity::alice"
    },
    "signals": {}
}