Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7daf735
docs(phase8): add runtime schema freeze inventory
flyingrobots Mar 22, 2026
219bb15
docs(phase8): define runtime schema artifact set
flyingrobots Mar 22, 2026
be8875c
feat(phase8): add runtime schema source fragments
flyingrobots Mar 22, 2026
e08a673
feat(phase8): add playback and scheduler schema fragments
flyingrobots Mar 22, 2026
1ec7dee
feat(phase8): validate local runtime schema fragments
flyingrobots Mar 22, 2026
fb32e42
docs(phase8): add runtime schema conformance audit
flyingrobots Mar 22, 2026
ec4478c
refactor(phase8): align writer head key naming
flyingrobots Mar 22, 2026
096f0c3
docs(phase8): add runtime schema mapping contract
flyingrobots Mar 22, 2026
637c707
refactor(phase8): type ABI runtime identifiers
flyingrobots Mar 22, 2026
fa95989
chore(tooling): track shared workspace settings
flyingrobots Mar 23, 2026
6ac3aba
fix(ci): restore tasks dag refresh inputs
flyingrobots Mar 23, 2026
5254e97
refactor(phase8): add shared runtime schema crate
flyingrobots Mar 23, 2026
ff7dcc0
docs(phase8): narrow shared runtime schema boundary
flyingrobots Mar 23, 2026
2af8725
docs(phase8): mark runtime schema freeze complete
flyingrobots Mar 23, 2026
0dc6f36
fix(phase8): restore schema feature gating and DAG defaults
flyingrobots Mar 23, 2026
2dfbc21
fix(phase8): harden schema freeze tooling
flyingrobots Mar 23, 2026
2521150
refactor(phase8): make worldline ids opaque
flyingrobots Mar 23, 2026
4cbeacb
docs(phase8): document review follow-ups
flyingrobots Mar 23, 2026
21a683e
docs: note phase 8 review fixes
flyingrobots Mar 23, 2026
67f57c7
docs(backlog): add review tooling follow-ups
flyingrobots Mar 24, 2026
629dccd
fix(phase8): resolve schema review follow-ups
flyingrobots Mar 24, 2026
d560ba2
docs(phase8): align review follow-ups
flyingrobots Mar 24, 2026
8a6d83c
fix(phase8): harden schema and ABI freeze contracts
flyingrobots Mar 24, 2026
8476506
fix(phase8): resolve final schema review threads
flyingrobots Mar 25, 2026
22f3f5b
docs(phase8): align final review follow-ups
flyingrobots Mar 25, 2026
2d5fd4f
docs(backlog): queue post-merge review tooling work
flyingrobots Mar 25, 2026
db4f8d0
fix(phase8): tighten final tooling review fixes
flyingrobots Mar 25, 2026
3e5e1f6
docs(phase8): align final review wording
flyingrobots Mar 25, 2026
470c190
docs(backlog): queue pre-pr process hardening
flyingrobots Mar 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ node_modules
dist
coverage
target
target-ra
target-fmt
target-clippy
target-test
Expand All @@ -21,6 +22,7 @@ docs/.vitepress/cache
.idea
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
Comment thread
flyingrobots marked this conversation as resolved.
.obsidian
.claude/

Expand Down
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rust-analyzer.cargo.extraEnv": {
"CARGO_TARGET_DIR": "target-ra"
}
}
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@

## Unreleased

### Fixed (PR #306 follow-up)

- **Fixed** the Phase 8 runtime-schema/tooling follow-ups so workspace
Prettier usage is declared and lockfile-pinned, runtime schema validation now
fails clearly when `node` is unavailable, dependency DAG generation uses the
archived tasks DAG by default with UTC-stable fallback labels, and the
tracked Rust Analyzer workspace target dir is repo-local and cross-platform.
Comment thread
flyingrobots marked this conversation as resolved.
Outdated
- **Fixed** shared Phase 8 type extraction so `WorldlineId` is actually opaque
like `HeadId`, `echo-wasm-abi` forwards `std`/`serde` into
`echo-runtime-schema` explicitly, `echo-wasm-abi --no-default-features`
avoids a stray `std` dependency, and positive-only scheduler/inbox schema
inputs are represented explicitly as `PositiveInt`.

### Fixed (PR #304 follow-up)

- **Fixed** the session WebSocket gateway TLS stack to use the Rustls ring
Expand Down
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ Echo is a deterministic, renderer-agnostic engine. We prioritize:
- rustup toolchain install 1.90.0
- rustup override set 1.90.0

### Shared Workspace Settings

- The repo tracks a minimal [.vscode/settings.json](/Users/james/git/echo/.vscode/settings.json) for project-safe tooling settings only.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
- Keep personal editor preferences such as theme, font family, and UI layout in your user-level VS Code settings, not the tracked workspace file.
- The tracked Rust Analyzer target dir uses the repo-local ignored `target-ra/` path to avoid fighting the default Cargo build directory during background checks.

## Communication

- Rely on GitHub discussions or issues for longer-form proposals.
Expand Down
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>
[workspace]
members = [
"crates/echo-runtime-schema",
"crates/warp-core",

"crates/warp-wasm",
Expand Down Expand Up @@ -47,6 +48,7 @@ echo-config-fs = { version = "0.1.0", path = "crates/echo-config-fs" }
echo-dind-tests = { version = "0.1.0", path = "crates/echo-dind-tests" }
echo-dry-tests = { version = "0.1.0", path = "crates/echo-dry-tests" }
echo-graph = { version = "0.1.0", path = "crates/echo-graph" }
echo-runtime-schema = { version = "0.1.0", path = "crates/echo-runtime-schema", default-features = false }
echo-registry-api = { version = "0.1.0", path = "crates/echo-registry-api" }
echo-scene-codec = { version = "0.1.0", path = "crates/echo-scene-codec" }
echo-scene-port = { version = "0.1.0", path = "crates/echo-scene-port" }
Expand Down
2 changes: 1 addition & 1 deletion crates/echo-dind-harness/tests/digest_golden_vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ fn tick_commit_hash_v2_full_chain_golden_vector() {

// Step 3: Compute tick commit hash using the above digests
let schema_hash = make_hash(0xAB);
let worldline_id = WorldlineId(make_hash(0xCD));
let worldline_id = WorldlineId::from_bytes(make_hash(0xCD));
let tick = 42u64;
let parent = make_hash(0x11);
let patch_digest = make_hash(0x22);
Expand Down
24 changes: 24 additions & 0 deletions crates/echo-runtime-schema/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: Apache-2.0
# © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>
[package]
name = "echo-runtime-schema"
version = "0.1.0"
edition = "2024"
rust-version = "1.90.0"
description = "Shared ADR-0008 runtime schema types for Echo"
license = "Apache-2.0"
repository = "https://github.com/flyingrobots/echo"
readme = "README.md"
keywords = ["echo", "runtime", "schema", "worldline"]
categories = ["data-structures"]

[dependencies]
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }

[features]
default = ["std", "serde"]
serde = ["dep:serde"]
std = ["serde?/std"]

[lints]
workspace = true
19 changes: 19 additions & 0 deletions crates/echo-runtime-schema/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!-- SPDX-License-Identifier: Apache-2.0 OR LicenseRef-MIND-UCAL-1.0 -->
<!-- © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots> -->

# echo-runtime-schema

Shared ADR-0008 runtime schema primitives for Echo.

This crate is the Echo-local shared owner for runtime-schema types that are not
inherently ABI-only:

- opaque runtime identifiers
- logical monotone counters
- structural runtime key types

`warp-core` consumes or re-exports these semantic types. `echo-wasm-abi`
converts to and from them where the host wire format differs.

Serde derives are feature-gated. Consumers that need serialization support must
enable this crate's `serde` feature explicitly.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
200 changes: 200 additions & 0 deletions crates/echo-runtime-schema/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// SPDX-License-Identifier: Apache-2.0
// © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>
//! Shared ADR-0008 runtime schema primitives.
//!
//! This crate is the Echo-local shared owner for generated-or-generation-ready
//! runtime schema types that are not inherently ABI-only:
//!
//! - opaque runtime identifiers
//! - logical monotone counters
//! - structural runtime key types
//!
//! Adapter crates such as `echo-wasm-abi` may still wrap these types when the
//! host wire format needs a different serialization contract.

#![cfg_attr(not(feature = "std"), no_std)]

use core::fmt;

macro_rules! logical_counter {
($(#[$meta:meta])* $name:ident) => {
$(#[$meta])*
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct $name(pub u64);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

impl $name {
/// Zero value for this logical counter.
pub const ZERO: Self = Self(0);
/// Largest representable counter value.
pub const MAX: Self = Self(u64::MAX);

/// Builds the counter from its raw logical value.
#[must_use]
pub const fn from_raw(raw: u64) -> Self {
Self(raw)
}

/// Returns the raw logical value.
#[must_use]
pub const fn as_u64(self) -> u64 {
self.0
}

/// Adds `rhs`, returning `None` on overflow.
#[must_use]
pub fn checked_add(self, rhs: u64) -> Option<Self> {
self.0.checked_add(rhs).map(Self)
}

/// Subtracts `rhs`, returning `None` on underflow.
#[must_use]
pub fn checked_sub(self, rhs: u64) -> Option<Self> {
self.0.checked_sub(rhs).map(Self)
}

/// Increments by one, returning `None` on overflow.
#[must_use]
pub fn checked_increment(self) -> Option<Self> {
self.checked_add(1)
}
}

impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
};
}

/// Canonical 32-byte identifier payload used by shared runtime schema ids.
pub type RuntimeIdBytes = [u8; 32];

/// Opaque stable identifier for a worldline.
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
pub struct WorldlineId(RuntimeIdBytes);

impl WorldlineId {
/// Reconstructs a worldline id from its canonical 32-byte representation.
#[must_use]
pub const fn from_bytes(bytes: RuntimeIdBytes) -> Self {
Self(bytes)
}

/// Returns the canonical byte representation of this id.
#[must_use]
pub const fn as_bytes(&self) -> &RuntimeIdBytes {
&self.0
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/// Opaque stable identifier for a head.
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct HeadId(RuntimeIdBytes);

impl HeadId {
/// Inclusive minimum key used by internal `BTreeMap` range queries.
pub const MIN: Self = Self([0u8; 32]);
/// Inclusive maximum key used by internal `BTreeMap` range queries.
pub const MAX: Self = Self([0xff; 32]);

/// Reconstructs a head id from its canonical 32-byte representation.
#[must_use]
pub const fn from_bytes(bytes: RuntimeIdBytes) -> Self {
Self(bytes)
}

/// Returns the canonical byte representation of this id.
#[must_use]
pub const fn as_bytes(&self) -> &RuntimeIdBytes {
&self.0
}
}

logical_counter!(
/// Per-worldline append identity for committed history.
WorldlineTick
);

logical_counter!(
/// Runtime-cycle correlation stamp. No wall-clock semantics.
GlobalTick
);

logical_counter!(
/// Control-plane generation token for scheduler runs.
///
/// This value is not provenance, replay state, or hash input.
RunId
);

/// Composite key identifying a writer head within its worldline.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct WriterHeadKey {
/// The worldline this head targets.
pub worldline_id: WorldlineId,
/// The head identity within that worldline.
pub head_id: HeadId,
}

#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::{GlobalTick, HeadId, RunId, WorldlineId, WorldlineTick, WriterHeadKey};

macro_rules! assert_logical_counter_boundaries {
($ty:ty) => {{
assert_eq!(<$ty>::ZERO.as_u64(), 0);
assert_eq!(<$ty>::MAX.as_u64(), u64::MAX);
assert_eq!(<$ty>::from_raw(41).checked_add(1).unwrap().as_u64(), 42);
assert_eq!(<$ty>::MAX.checked_add(1), None);
assert_eq!(<$ty>::from_raw(42).checked_sub(1).unwrap().as_u64(), 41);
assert_eq!(<$ty>::ZERO.checked_sub(1), None);
assert_eq!(<$ty>::from_raw(7).checked_increment().unwrap().as_u64(), 8);
assert_eq!(<$ty>::MAX.checked_increment(), None);
}};
}

#[test]
fn worldline_tick_checked_arithmetic_boundaries() {
assert_logical_counter_boundaries!(WorldlineTick);
}

#[test]
fn global_tick_checked_arithmetic_boundaries() {
assert_logical_counter_boundaries!(GlobalTick);
}

#[test]
fn run_id_checked_arithmetic_boundaries() {
assert_logical_counter_boundaries!(RunId);
}

#[test]
fn opaque_ids_round_trip_bytes() {
let worldline = WorldlineId::from_bytes([3u8; 32]);
let head = HeadId::from_bytes([7u8; 32]);
assert_eq!(*worldline.as_bytes(), [3u8; 32]);
assert_eq!(*head.as_bytes(), [7u8; 32]);
}

#[test]
fn writer_head_key_preserves_typed_components() {
let key = WriterHeadKey {
worldline_id: WorldlineId::from_bytes([1u8; 32]),
head_id: HeadId::from_bytes([2u8; 32]),
};
assert_eq!(*key.worldline_id.as_bytes(), [1u8; 32]);
assert_eq!(*key.head_id.as_bytes(), [2u8; 32]);
}
}
2 changes: 2 additions & 0 deletions crates/echo-wasm-abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ ciborium = { version = "0.2", default-features = false }
serde-value = { version = "0.7" }
half = { version = "2.4", default-features = false, features = ["alloc"] }
thiserror = { version = "2.0" }
echo-runtime-schema = { workspace = true, default-features = false, features = ["serde"] }

[features]
default = ["std"]
std = [
"serde/std",
"ciborium/std",
"half/std",
"echo-runtime-schema/std",
]
alloc = []

Expand Down
3 changes: 2 additions & 1 deletion crates/echo-wasm-abi/src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! Minimal deterministic codec helpers (length-prefixed, LE scalars).

extern crate alloc;
use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::vec::Vec;
use core::str;
Expand Down Expand Up @@ -187,7 +188,7 @@ impl<'a> Reader<'a> {
pub fn read_string(&mut self, max_len: usize) -> Result<String, CodecError> {
let bytes = self.read_len_prefixed_bytes(max_len)?;
str::from_utf8(bytes)
.map(std::string::ToString::to_string)
.map(ToOwned::to_owned)
.map_err(|_| CodecError::InvalidUtf8)
}
}
Expand Down
Loading
Loading