Roadmap

Rolling versioning: 0.MINOR.PATCH, incremented as work lands. A major version bump (1.0.0, 2.0.0, ...) is a deliberate decision made by a human — never automated.

We work one release at a time. Don't start tasks from a later release until the current one is closed out, unless explicitly reprioritized.

Status

Current release: v0.7.0 (in progress)


v0.1.0 — Scaffolding

v0.2.0 — Body layer: sensors & actuators

Verified: both board targets (esp32dev, esp32-s3-devkitc-1) build clean with PlatformIO. Not yet verified against real hardware — pin choices per board are a starting point, expect to override them per physical chassis.

v0.3.0 — WiFi hotspot & dashboard

Verified: both board targets build the firmware and the LittleFS image clean with PlatformIO. Not yet run on real hardware. "Drive targets" config is deferred to v0.4.0, once drives exist to configure — for now the dashboard's manual actuator sliders stand in for direct output control.

v0.4.0 — Physiology & drives

Verified: both board targets build clean with PlatformIO; a 20 Hz behavior tick runs Physiology::update() and the dashboard's new Physiology section shows live value/drive per variable plus fuzz_scale. Not yet run on real hardware, so the tuning constants (decay/recovery/coupling rates) are starting points, not calibrated values. h_social has no sensor source yet (needs another robot/human present) and sits at rest until a later release. h_curiosity's novelty signal is a placeholder (proportional to raw sensor change) — real prediction error arrives with contingency memory in v0.5.0.

v0.5.0 — Contingency memory

Verified: both board targets build clean with PlatformIO (RAM use +7KB for the 256-entry table). Not yet run on real hardware. The article's pseudocode doesn't specify how a sensor-delta pattern gets linked to "led to improving drives" — that's left to whoever queries the memory. This implementation makes it concrete: each entry tracks an EMA of drive-pressure change (mean_drive_delta) alongside the action/sensor codes, so query_bias() can rank matches by whether they historically helped. query_bias() is implemented and exposed on the dashboard, but nothing calls it yet — no action generator exists until v0.7.0, so today the table only learns from whatever a human does via the dashboard sliders or the heartbeat blink.

v0.6.0 — Spatial memory & navigation

Verified: both board targets build clean with PlatformIO. Not yet run on real hardware. A significant, deliberate departure from the article's pseudocode: this hardware has no positioning sensor (no encoders/IMU/GPS), and the article's spatial_bias(position, drives, spatial_map) assumes position already exists without saying where it comes from. Rather than fabricate open-loop odometry from commanded motor duty cycle — which would drift into meaninglessness within seconds, since duty cycle isn't measured displacement — this uses the article's own explicitly offered alternative (§8.1): "a coarse 2-D grid OR a set of place cells". A place cell here is a coarse signature of current sensor readings; same ambient conditions are treated as the same place, which is the same gradient-following idea §10 already uses for individual channels (light, RF), just made the identity of a location instead of a single bias term.

Consequence: best_cell() (the "spatial bias contribution" task) answers which remembered place looks most promising for current drives, but not which direction to move — there's no direction without real coordinates. Turning that into actual motor output is deferred to v0.7.0's core loop, which will need a concrete policy for it (most likely: bias exploration persistence/exploitation balance rather than literal steering, given the hardware). Currently, with only 2 sensor channels on both board profiles, signature entropy is low (few distinguishable "places") — richer differentiation needs richer sensor profiles, which is a board-config change, not an engine change.

v0.7.0 — Core loop integration

ActionGenerator is the piece every prior release was missing: physiology, contingency memory, and spatial memory now actually drive the actuators each tick (baseline + drive-scaled noise + contingency bias + spatial nudge, clamped) instead of only observing whatever the dashboard did. A channel recently touched from the dashboard (Actuator::manual_override_active, 3s window) is left alone rather than fought over — the heartbeat blink uses the same mechanism (write_manual) so it stays system-owned without a hardcoded channel-name exception in the engine.

Task split: high-frequency work (PWM via hardware LEDC, ADC via on-demand cached Sensor::read()) needs no separate task — the hardware and existing on-demand reads already satisfy it. Behavior task is the existing 20 Hz tick. Slow task is the new StateLogger, ~1 Hz, appending physiology + total actuator cost to a 64KB-capped /log.csv on the same LittleFS partition the dashboard serves from — downloadable at /log.csv with zero extra server code, and exposed as a button on the dashboard's Config tab.

Fixed-point arithmetic: evaluated and deliberately not done. The article's advice (§14.2) targets microcontrollers generically; both ESP32 and ESP32-S3 have a hardware single-precision FPU, so float ops in a tick this small (a few hundred multiply-adds across four modules, worst case) cost microseconds — replacing them with fixed-point would trade real readability for no measurable benefit on this specific hardware. Revisit only if a future board target lacks an FPU.

Honest limitation carried over from v0.6.0: SpatialMemory::best_cell() still can't say which direction to move, only which remembered place looks best. ActionGenerator resolves that the way flagged there — as an explore/exploit nudge (wider noise if a better place than "here" is known, narrower if "here" already looks best), not fabricated steering.

Verified: both esp32dev and esp32-s3-devkitc-1 build clean (firmware + LittleFS image) with PlatformIO. Dashboard changes (manual-override badge, log download link) verified against a mocked API in a real browser. Not yet run on real hardware — the gains/constants above (noise, bias, and nudge scaling) are starting points, not tuned values.

v0.8.0 — Life-state persistence

v0.9.0 — Charging station integration

v1.0.0 — First stable "alive" release (human-gated)

Backlog / later