Skip to content

Conversation

@flyingrobots
Copy link
Owner

Echo is becoming JITOS kernel

Adds spec 0000 scaffold

Specs will be:

  • Documentation
  • Interactive Onboarding Demos
  • Rust + WASM + WW + TS
  • JITOS Contributor Certification Materials
  • Live Tests

This sets up the foundation to build these specs.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added WebSocket-to-Unix socket gateway enabling browser clients to connect to the session hub with TLS support and origin filtering.
    • Introduced WASM-based living specs runner for in-browser kernel testing and validation.
    • Enhanced error handling with structured error responses for unauthorized RMG publishes and protocol violations.
  • Documentation

    • Added comprehensive methodology guide and RMG View Protocol specification.
    • Updated scripting integration examples and architecture documentation.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

This PR introduces a WebSocket-to-Unix-socket gateway for session management with frame validation and optional TLS, enforces single-producer semantics on RMG streams with structured error handling in the session service, adds a WASM-based living specification framework using Leptos+Trunk, pivots scripting documentation from Lua to Rhai throughout, and establishes engineering standards including the JITOS kernel branding and methodology documentation.

Changes

Cohort / File(s) Summary
WebSocket Gateway – New Crate
crates/echo-session-ws-gateway/Cargo.toml, crates/echo-session-ws-gateway/README.md, crates/echo-session-ws-gateway/src/main.rs
Adds a new Tokio+Axum WebSocket-to-Unix-socket bridge with configurable TLS, origin filtering, 12-byte framing protocol (4-byte length header, 32-byte trailer), max payload guards (8 MiB default), graceful shutdown on Ctrl-C, per-connection task spawning for WS reader/writer and UDS reader/writer, and ping/pong keepalive.
RMG Stream Authority Enforcement
crates/echo-session-service/src/main.rs, crates/echo-session-client/src/lib.rs
Adds per-RmgId producer ownership validation in session service; rejects non-owner publishes with E_FORBIDDEN_PUBLISH (403); enforces snapshot→diff sequencing and epoch/hash continuity; forwards error payloads to initiating connection and broadcasts valid frames. Client now surfaces error messages as local notifications with kind NotifyKind::Error.
WASM Living Spec Scaffold (spec-000)
specs/spec-000-rewrite/Cargo.toml, specs/spec-000-rewrite/README.md, specs/spec-000-rewrite/index.html, specs/spec-000-rewrite/src/lib.rs
Adds Leptos+Trunk CSR scaffold with epoch-counter component, dark-themed HTML layout, WASM entry point, and make targets (spec-000-dev, spec-000-build); establishes a living specification runner embedded in the browser.
Workspace & Build Configuration
Cargo.toml, Makefile
Adds crates/echo-session-ws-gateway and specs/spec-000-rewrite to workspace members; introduces spec-000-dev (runs trunk serve) and spec-000-build (runs trunk build --release) phony targets.
Scripting Runtime Pivot: Lua → Rhai
crates/rmg-ffi/Cargo.toml, crates/rmg-ffi/README.md, crates/rmg-ffi/src/lib.rs, docs/rmg-demo-roadmap.md, docs/rmg-runtime-architecture.md, docs/roadmap-mwmr-mini-epic.md, docs/rust-rhai-ts-division.md, docs/spec-concurrency-and-authoring.md, docs/spec-mwmr-concurrency.md, docs/spec-networking.md, docs/spec-rmg-core.md
Systematically replaces Lua references with Rhai across documentation and package descriptions; updates code examples from Lua syntax to Rhai syntax (e.g., {entity = id}#{ entity: id }); reflects Rhai as the deterministic scripting layer for gameplay authoring.
Engineering Standards & Methodology
CONTRIBUTING.md, README.md, docs/METHODOLOGY.md, docs/decision-log.md, docs/execution-plan.md, docs/phase1-plan.md, docs/spec-rmg-view-protocol.md, docs/tasks.md, WASM-TASKS.md
Adds JITOS kernel branding, METHODOLOGY.md detailing 5x Duty living-spec workflow, expanded decision log with authority/gateway/Rhai decisions, marks three RMG View Protocol tasks as completed (define protocol, generalize as EIP, enforce authority), expands task list with viewer dirty-flag sync, pub/sub toggles, and integration testing.

Sequence Diagram

sequenceDiagram
    autonumber
    actor Pub as Publisher<br/>(Client 1)
    participant SS as Session Service
    actor Sub as Subscriber<br/>(Client 2)
    
    rect rgba(150, 200, 200, 0.2)
    note over Pub,Sub: Ownership Enforcement: Valid Publisher
    Pub->>SS: Message::RmgStream<br/>(Snapshot, rmg_id=X)
    SS->>SS: Check: producer set?<br/>No → assign Pub
    SS->>SS: Validate snapshot state<br/>(epoch, hash)
    SS->>Sub: Broadcast RmgStream<br/>(fresh timestamp)
    SS->>Pub: Implicit ack<br/>(frame accepted)
    end
    
    rect rgba(200, 150, 150, 0.2)
    note over Pub,Sub: Ownership Enforcement: Non-Owner Rejected
    actor Attacker as Attacker<br/>(Client 3)
    Attacker->>SS: Message::RmgStream<br/>(Diff, rmg_id=X)
    SS->>SS: Check: producer set?<br/>Yes, != Attacker
    SS->>Attacker: Message::Error<br/>(E_FORBIDDEN_PUBLISH, 403)
    SS--XSub: (frame rejected,<br/>no broadcast)
    end
    
    rect rgba(200, 200, 150, 0.2)
    note over Pub,Sub: Client: Error Notification Flow
    Attacker->>Attacker: Recv Message::Error
    Attacker->>Attacker: Convert to Notification<br/>(NotifyKind::Error,<br/>NotifyScope::Local)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50–75 minutes

Areas requiring careful attention:

  • crates/echo-session-ws-gateway/src/main.rs: Frame parsing logic (12-byte header with 4-byte length at offset 8, 32-byte trailer validation), TLS configuration/loading, per-client task spawning (reader/writer/keepalive), origin filtering, Unix socket connection error handling, and graceful shutdown coordination.
  • crates/echo-session-service/src/main.rs: RmgStream ownership enforcement (per-connection producer tracking, E_FORBIDDEN_PUBLISH rejection, epoch/hash validation logic, snapshot↔diff sequencing); new error payload construction; ensure error responses don't bypass the connection check.
  • specs/spec-000-rewrite/src/lib.rs: Leptos component correctness, WASM entry point (panic hook setup), signal state management, and JSX rendering logic.
  • Heterogeneous changes: Documentation Lua→Rhai substitutions are repetitive but numerous; spot-check a few to ensure terminology consistency, especially in executable examples (spec-concurrency-and-authoring.md, spec-networking.md, spec-rmg-core.md).

Possibly related PRs

  • Rmg viewer #138 — Modifies the same RMG/session/viewer stack (session service, session client, protocol definitions), indicating parallel or sequential work on the streaming and viewer architecture.

🚀 A gateway opens wide, three clients now collide,
One rules the stream with might, two others turned aside—
From Lua's ancient tongue we pivot to Rhai's flame,
A WASM-born spec runner joins the coding game! 🎪✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the primary change: introducing a WASM spec-000 scaffold with new crate infrastructure, documentation, and build targets.
Description check ✅ Passed The description directly relates to the changeset by explaining the strategic context (JITOS kernel) and the purpose of the scaffold, aligning with the extensive documentation and structural additions.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch echo/wasm-spec-000-scaffold

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/rust-rhai-ts-division.md (1)

5-76: LGTM: Comprehensive Rhai pivot with minor formatting issues.

The document consistently replaces Lua with Rhai across all layers (runtime stack, gameplay authoring, bindings, tooling). The technical division remains sound.

Minor formatting issue: markdownlint flags missing blank lines around headings at lines 22, 32, 38, and 43. While not critical, fixing these improves markdown standards compliance.

Apply this diff to fix heading spacing:

 - `rmg-cli` – CLI utilities
 
 ---
+
 ## Rhai (gameplay authoring layer)
 
 ### Responsibilities

(Repeat pattern for other flagged headings at lines 32, 38, 43)

crates/echo-session-service/src/main.rs (1)

455-557: Refactor authorization logic for clarity.

The RmgStream handler consolidates ownership checks, epoch validation, and broadcast logic in a deeply nested structure spanning 100+ lines. While functionally correct, the cognitive complexity is high.

Consider extracting validation into dedicated functions:

  • validate_producer_authority(stream, conn_id, rmg_id) -> Result<(), ErrorPayload>
  • validate_frame_sequence(stream, frame) -> Result<(), ErrorPayload>

This would:

  • Reduce nesting (currently 4-5 levels)
  • Make error paths testable in isolation
  • Improve readability of the happy path
  • Allow reuse if other message types need similar validation

Example extraction:

fn validate_producer_authority(
    stream: &StreamState,
    conn_id: u64,
    rmg_id: RmgId,
) -> Result<(), ErrorPayload> {
    if let Some(p) = stream.producer {
        if p != conn_id {
            return Err(ErrorPayload {
                code: 403,
                name: "E_FORBIDDEN_PUBLISH".into(),
                details: None,
                message: format!("rmg_id {} is owned by {}", rmg_id, p),
            });
        }
    }
    Ok(())
}

fn validate_frame_sequence(
    stream: &mut StreamState,
    frame: &RmgFrame,
) -> Result<(), ErrorPayload> {
    match frame {
        RmgFrame::Snapshot(s) => {
            stream.last_epoch = Some(s.epoch);
            stream.last_hash = s.state_hash;
            stream.latest_snapshot = Some(s.clone());
            Ok(())
        }
        RmgFrame::Diff(d) => {
            let last = stream.last_epoch.ok_or_else(|| ErrorPayload {
                code: 409,
                name: "E_RMG_SNAPSHOT_REQUIRED".into(),
                details: None,
                message: "send a snapshot before the first diff".into(),
            })?;
            
            if d.from_epoch != last || d.to_epoch != d.from_epoch + 1 {
                return Err(ErrorPayload {
                    code: 409,
                    name: "E_RMG_EPOCH_GAP".into(),
                    details: None,
                    message: format!(
                        "expected {}->{} but got {}->{}",
                        last, last + 1, d.from_epoch, d.to_epoch
                    ),
                });
            }
            
            stream.last_epoch = Some(d.to_epoch);
            stream.last_hash = d.state_hash;
            Ok(())
        }
    }
}

Then the main handler simplifies to:

Message::RmgStream { rmg_id, frame } => {
    let (subs, pkt) = {
        let mut h = hub.lock().await;
        let stream = h.streams.entry(rmg_id).or_default();
        
        // Validate producer
        if let Err(payload) = validate_producer_authority(stream, conn_id, rmg_id) {
            let tx = h.conns.get(&conn_id).map(|c| c.tx.clone());
            let ts = h.alloc_ts();
            if let Some(tx) = tx {
                let pkt = encode_message(Message::Error(payload.clone()), ts)?;
                let _ = tx.send(pkt).await;
            }
            anyhow::bail!("producer authorization failed");
        }
        
        // Validate and update sequence
        if let Err(payload) = validate_frame_sequence(stream, &frame) {
            let tx = h.conns.get(&conn_id).map(|c| c.tx.clone());
            let ts = h.alloc_ts();
            if let Some(tx) = tx {
                let pkt = encode_message(Message::Error(payload.clone()), ts)?;
                let _ = tx.send(pkt).await;
            }
            anyhow::bail!("frame sequence validation failed");
        }
        
        // Set producer if first publish
        if stream.producer.is_none() {
            stream.producer = Some(conn_id);
        }
        
        let subs = stream.subscribers.clone();
        let ts = h.alloc_ts();
        let pkt = encode_message(Message::RmgStream { rmg_id, frame }, ts)?;
        (subs, pkt)
    };
    
    let h = hub.lock().await;
    for sub in subs {
        if let Some(conn) = h.conns.get(&sub) {
            let _ = conn.tx.send(pkt.clone()).await;
        }
    }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1627b79 and 35b06d7.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • assets/echo-white-2.svg is excluded by !**/*.svg
  • assets/echo-white.svg is excluded by !**/*.svg
📒 Files selected for processing (31)
  • CONTRIBUTING.md (2 hunks)
  • Cargo.toml (1 hunks)
  • Makefile (1 hunks)
  • README.md (4 hunks)
  • WASM-TASKS.md (1 hunks)
  • crates/echo-session-client/src/lib.rs (2 hunks)
  • crates/echo-session-service/src/main.rs (3 hunks)
  • crates/echo-session-ws-gateway/Cargo.toml (1 hunks)
  • crates/echo-session-ws-gateway/README.md (1 hunks)
  • crates/echo-session-ws-gateway/src/main.rs (1 hunks)
  • crates/rmg-ffi/Cargo.toml (1 hunks)
  • crates/rmg-ffi/README.md (1 hunks)
  • crates/rmg-ffi/src/lib.rs (1 hunks)
  • docs/METHODOLOGY.md (1 hunks)
  • docs/decision-log.md (1 hunks)
  • docs/execution-plan.md (3 hunks)
  • docs/phase1-plan.md (5 hunks)
  • docs/rmg-demo-roadmap.md (2 hunks)
  • docs/rmg-runtime-architecture.md (1 hunks)
  • docs/roadmap-mwmr-mini-epic.md (1 hunks)
  • docs/rust-rhai-ts-division.md (3 hunks)
  • docs/spec-concurrency-and-authoring.md (3 hunks)
  • docs/spec-mwmr-concurrency.md (1 hunks)
  • docs/spec-networking.md (2 hunks)
  • docs/spec-rmg-core.md (1 hunks)
  • docs/spec-rmg-view-protocol.md (1 hunks)
  • docs/tasks.md (1 hunks)
  • specs/spec-000-rewrite/Cargo.toml (1 hunks)
  • specs/spec-000-rewrite/README.md (1 hunks)
  • specs/spec-000-rewrite/index.html (1 hunks)
  • specs/spec-000-rewrite/src/lib.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Every source file must start with exactly // SPDX-License-Identifier: Apache-2.0 and // © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>

Files:

  • specs/spec-000-rewrite/src/lib.rs
  • crates/echo-session-client/src/lib.rs
  • crates/rmg-ffi/src/lib.rs
  • crates/echo-session-ws-gateway/src/main.rs
  • crates/echo-session-service/src/main.rs
🧠 Learnings (13)
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Consult `docs/architecture-outline.md` before touching runtime code in `packages/echo-core`

Applied to files:

  • docs/rust-rhai-ts-division.md
  • README.md
  • docs/spec-concurrency-and-authoring.md
  • CONTRIBUTING.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Applies to packages/echo-core/src/**/*.rs : Tests and benchmarks are mandatory for runtime changes once the harness exists

Applied to files:

  • docs/rust-rhai-ts-division.md
  • specs/spec-000-rewrite/Cargo.toml
  • Cargo.toml
  • README.md
  • crates/echo-session-ws-gateway/Cargo.toml
  • docs/spec-concurrency-and-authoring.md
  • docs/phase1-plan.md
  • crates/rmg-ffi/Cargo.toml
  • CONTRIBUTING.md
  • docs/execution-plan.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Applies to packages/echo-core/src/**/*.rs : Public APIs across crates (`rmg-core`, `rmg-ffi`, `rmg-wasm`) must carry rustdoc comments explaining intent, invariants, and usage

Applied to files:

  • docs/rust-rhai-ts-division.md
  • specs/spec-000-rewrite/Cargo.toml
  • Cargo.toml
  • README.md
  • crates/echo-session-ws-gateway/Cargo.toml
  • crates/rmg-ffi/src/lib.rs
  • crates/rmg-ffi/Cargo.toml
  • docs/tasks.md
  • crates/echo-session-ws-gateway/src/main.rs
  • crates/rmg-ffi/README.md
  • CONTRIBUTING.md
  • crates/echo-session-ws-gateway/README.md
  • docs/execution-plan.md
  • crates/echo-session-service/src/main.rs
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Applies to packages/echo-core/src/**/*.rs : Respect determinism: preferably use Echo PRNG instead of random seeds without mitigation

Applied to files:

  • docs/rust-rhai-ts-division.md
  • specs/spec-000-rewrite/Cargo.toml
  • README.md
  • docs/spec-concurrency-and-authoring.md
  • crates/rmg-ffi/README.md
  • CONTRIBUTING.md
  • docs/execution-plan.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Formatting is auto-fixed with `cargo fmt` by default; set `ECHO_AUTO_FMT=0` to run check-only

Applied to files:

  • README.md
  • crates/rmg-ffi/Cargo.toml
  • CONTRIBUTING.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Keep `main` pristine; feature work belongs on branches named `echo/<feature>` or `timeline/<experiment>`

Applied to files:

  • README.md
  • CONTRIBUTING.md
  • docs/execution-plan.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Run `cargo clippy --all-targets -- -D missing_docs` and `cargo test` before every PR

Applied to files:

  • README.md
  • CONTRIBUTING.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Capture milestones, blockers, and decisions in `docs/decision-log.md`, relevant specs, or PR descriptions

Applied to files:

  • docs/decision-log.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Record outcomes and next steps in `docs/decision-log.md` and ensure impacted docs stay in sync when wrapping up a session

Applied to files:

  • docs/decision-log.md
  • docs/phase1-plan.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Every meaningful design choice should be documented in `docs/` (specs, diagrams, memorials) or `docs/decision-log.md`

Applied to files:

  • docs/decision-log.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: When a PR touches non-doc code, update `docs/execution-plan.md` and `docs/decision-log.md` in the same PR

Applied to files:

  • CONTRIBUTING.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Applies to **/*.rs : Every source file must start with exactly `// SPDX-License-Identifier: Apache-2.0` and `// © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>`

Applied to files:

  • CONTRIBUTING.md
📚 Learning: 2025-12-10T11:22:22.785Z
Learnt from: CR
Repo: flyingrobots/echo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-10T11:22:22.785Z
Learning: Start each session by updating *Today's Intent* in `docs/execution-plan.md`

Applied to files:

  • docs/execution-plan.md
🧬 Code graph analysis (1)
crates/echo-session-service/src/main.rs (1)
crates/echo-session-proto/src/wire.rs (2)
  • decode_message (263-292)
  • encode_message (232-260)
🪛 checkmake (0.2.2)
Makefile

[warning] 131-131: Missing required phony target "all"

(minphony)


[warning] 131-131: Missing required phony target "clean"

(minphony)


[warning] 131-131: Missing required phony target "test"

(minphony)

🪛 LanguageTool
docs/spec-rmg-view-protocol.md

[grammar] ~40-~40: Ensure spelling is correct
Context: ...se) and clear dirty on success; retry/backoff on error. - Subscriptions: apply incomi...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

README.md

[grammar] ~11-~11: Ensure spelling is correct
Context: ...nstead of hopes and prayers. > > THE REVΩLUTION WILL BE DETERMINISTIC. > **THE PROO...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
specs/spec-000-rewrite/README.md

9-9: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


15-15: Bare URL used

(MD034, no-bare-urls)


19-19: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


23-23: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

docs/rust-rhai-ts-division.md

22-22: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


32-32: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


38-38: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


43-43: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

README.md

3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


7-7: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


9-9: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


75-75: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


77-77: Bare URL used

(MD034, no-bare-urls)

WASM-TASKS.md

8-8: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


13-13: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


18-18: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


24-24: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


29-29: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


34-34: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


40-40: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

docs/spec-concurrency-and-authoring.md

9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


27-27: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


34-34: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


35-35: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


70-70: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

CONTRIBUTING.md

48-48: Bare URL used

(MD034, no-bare-urls)

crates/echo-session-ws-gateway/README.md

9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


10-10: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Security Audit
🔇 Additional comments (36)
docs/rmg-runtime-architecture.md (1)

77-77: Terminology update consistent with PR-wide Lua→Rhai pivot.

Line 77 correctly reflects the scripting language transition. Determinism invariant preserved; no behavioral change.

docs/spec-mwmr-concurrency.md (1)

73-73: Rhai terminology update; no functional impact on Family ID semantics.

Family ID computation and determinism guarantees remain unchanged.

crates/rmg-ffi/src/lib.rs (8)

1-9: SPDX header & module-level docs correct; public API fully documented per learnings.

  • SPDX/copyright (lines 1–2): ✓ Exact specification match
  • Module doc (lines 4–8): Updated to include Rhai host modules; consistent with PR pivot
  • #![deny(missing_docs)] enforces comprehensive rustdoc on all public items

20-47: All public structs carry field-level rustdoc as required.

RmgEngine, rmg_node_id, rmg_tx_id, rmg_snapshot each document intent and invariants. Repr(C) layout is correct for FFI.


49-74: Engine lifecycle functions properly documented with Safety sections.

rmg_engine_new and rmg_engine_free establish clear ownership semantics. Null-pointer handling correct (line 68–70 early return on null).


76-119: rmg_engine_spawn_motion_entity: FFI correctness with proper bounds checking.

  • Null checks on all three pointers (line 93)
  • UTF-8 validation (lines 97–101)
  • Output written safely via unsafe dereference (line 116)
  • All invariants documented in Safety block

121-189: Transaction and rewrite application functions: proper error handling.

  • rmg_engine_begin (lines 126–133): Null check + TxId wrapping ✓
  • rmg_engine_apply_motion (lines 140–164): Validates tx.value ≠ 0, applies ApplyResult matching ✓
  • rmg_engine_commit (lines 171–189): Writes snapshot hash via unsafe deref with validation ✓

191-228: rmg_engine_read_motion: Multi-step validation before unsafe access.

Checks engine, output pointers, node ID, record existence, payload validity (lines 202–224). Deterministic output order (position, velocity) maintained.


230-245: Helper functions with safety comments; slice construction guarded.

handle_to_node_id (lines 230–237): Null-safe, returns Option.
copy_vec3 (lines 239–245): Safety comment documents caller precondition (buffer ≥ 3 elements).


247-325: Test suite: determinism + error-path coverage.

  • ffi_motion_rewrite_is_deterministic (lines 273–312): Spawns two identical engines, applies motion rule, verifies snapshot hash equality and correct position/velocity reads ✓
  • ffi_apply_no_match_returns_false (lines 316–324): Validates error path with bogus node ID ✓

Tests are appropriate for bootstrap phase. Could expand with UTF-8 rejection test (line 98–100) or stale tx ID handling, but current scope is adequate.

Cargo.toml (2)

26-37: Release and bench profiles appropriately configured.

  • Release (lines 26–30): LTO enabled, single codegen unit, stripped binaries (optimized for size + link-time optimization)
  • Bench (lines 32–37): Derives from release, sets opt-level=3, disables LTO (faster compile), enables debug info (for profiling)

Profiles are sensible for the project scope.


3-20: Workspace members list correctly formatted with proper Cargo.toml manifests.

Both new crates are properly defined:

  • crates/echo-session-ws-gateway: WebSocket-to-Unix-socket bridge (edition 2021, Apache-2.0)
  • specs/spec-000-rewrite: Living spec for Echo/JITOS (edition 2024, Apache-2.0)

No Rust source files exist yet in either crate, so SPDX header verification is not applicable at this stage. When .rs files are added, they must include the exact SPDX and copyright headers per coding guideline.

docs/rmg-demo-roadmap.md (2)

37-44: Demo 4 terminology updated from Lua → Rhai; determinism invariant preserved.

  • Title (line 37): "Lua Live Coding Loop" → "Rhai Live Coding Loop" ✓
  • Goal (lines 39–42): References updated; hot-reload and deterministic equivalence claims remain valid under Rhai ✓
  • Determinism via replay (line 43) is architecture-independent; correct for Rhai ✓

71-71: Roadmap table entry aligned with Demo 4 section heading.

Line 71: "Demo 4 Lua API" → "Demo 4 Rhai API" matches updated terminology in demo section.

crates/rmg-ffi/README.md (1)

7-7: FFI bindings README correctly advertises Rhai as first-class embedding target.

Line 7 now positions C/C++ and Rhai host modules as equal consumers of the C ABI. Change aligns with module-level doc update in src/lib.rs (line 6).

docs/roadmap-mwmr-mini-epic.md (1)

54-54: Phase 3 rule registration example updated to Rhai syntax.

Line 54 correctly shows Rhai map syntax: register_rule{name, match, exec, ?id, ?revision}. Optional fields denoted; engine-computed behavior documented. Consistent with spec-mwmr-concurrency.md.

docs/spec-rmg-core.md (2)

97-100: Rhai API surface example: syntax and semantics correct.

Lines 98–100 correctly translate Lua table syntax {entity = id} to Rhai map syntax #{ entity: id }. Function signature and semantic intent unchanged. Consistent with Rhai language specification.


88-106: API surface section covers all three language bindings consistently.

  • Rust (lines 89–95): Low-level, direct engine calls ✓
  • Rhai (lines 97–100): Scripting-layer binding with map parameters ✓
  • TypeScript/WASM (lines 102–105): Async JS bindings ✓

All three preserve determinism semantics and naming conventions. Cross-language consistency maintained.

CONTRIBUTING.md (2)

44-49: LGTM: Clear WASM workflow documentation.

The new living specs section provides precise, executable instructions. The bare URL on line 48 is appropriate for a localhost dev server reference—markdownlint's complaint is a false positive in this instructional context.


67-67: Good: Determinism constraint migrated to Rhai.

The code style guidance correctly preserves Echo's determinism requirements for the new scripting layer.

crates/rmg-ffi/Cargo.toml (1)

8-8: LGTM: Package description accurately reflects Rhai integration.

The updated description correctly distinguishes in-process Rhai hosting from C ABI for external consumers.

docs/phase1-plan.md (1)

14-116: LGTM: Consistent Rhai pivot throughout Phase 1 plan.

All Lua references systematically replaced with Rhai across task descriptions, demonstrations, and completion criteria. The terminology is internally consistent and aligns with the broader repository pivot.

docs/spec-networking.md (1)

50-58: LGTM: Rhai syntax is accurate.

The converted code examples use correct Rhai syntax:

  • fn keyword for function definitions
  • #{ key: value } for object literals
  • :: for namespace/module access
  • this keyword for method context

The API surface documentation accurately reflects Rhai semantics.

README.md (2)

162-162: LGTM - Rhai pivot reflected correctly.

The updated comment accurately reflects the scripting runtime pivot from Lua to Rhai, consistent with the decision-log entries and broader PR changes.


310-317: Developer benchmark documentation is clear.

The benchmark documentation provides clear commands and references additional README documentation. Well-structured for developer onboarding.

WASM-TASKS.md (1)

6-6: Excellent test-first policy.

The explicit "write failing tests first, then implement" policy aligns with best practices and the learnings indicating mandatory tests for runtime changes.

docs/spec-rmg-view-protocol.md (1)

1-73: Outstanding protocol specification.

This RMG View Protocol spec is exceptionally well-structured:

  • Clear authority model (single producer per RmgId)
  • Comprehensive error taxonomy
  • Gapless sequencing with hash validation
  • Backpressure mechanism via ResyncRequest
  • Reusable EIP template pattern
  • Open questions section acknowledging unresolved design space

The 8 MiB MAX_PAYLOAD cap provides clear DoS protection. Error codes are specific enough for client debugging.

docs/spec-concurrency-and-authoring.md (1)

5-5: Rhai pivot documented correctly.

The clarification that Rhai/Rust developers author gameplay systems is consistent with the broader scripting runtime pivot documented throughout the PR.

crates/echo-session-service/src/main.rs (2)

1-2: LGTM - Required headers present.

SPDX and copyright headers are correct per coding guidelines.

Based on coding guidelines.


182-247: Excellent authorization test coverage.

The non_owner_publish_is_rejected_with_error test properly validates:

  • Owner establishes authority via first snapshot
  • Non-owner diff is rejected with E_FORBIDDEN_PUBLISH
  • Error payload reaches the attacker
  • Subscriber does not receive the invalid diff
  • HTTP 403 code used appropriately

This test pattern should be replicated for other error codes (E_RMG_SNAPSHOT_REQUIRED, E_RMG_EPOCH_GAP).

docs/decision-log.md (1)

9-12: Decision log entries are exemplary.

The new decision log entries (2025-12-11) comprehensively document:

  • Browser WS gateway rationale and tradeoffs
  • Scripting runtime pivot with clear justification
  • RMG authority enforcement with error taxonomy
  • CI security audit policy

Each entry follows the Context→Decision→Rationale→Consequence pattern perfectly. This documentation discipline makes the codebase exceptionally maintainable.

Based on learnings: decisions are properly captured in docs/decision-log.md.

specs/spec-000-rewrite/README.md (1)

5-26: Living spec documentation is clear.

The README provides straightforward setup and build instructions. The "Next steps" section appropriately scopes the remaining work (kernel bindings, RMG rendering, completion badge).

Minor markdown improvements:

  • Add shell language specifier to code blocks (lines 9, 19)
  • Use link syntax for bare URL at line 15
  • Add blank line before "Next steps" heading

These are cosmetic only.

Makefile (1)

130-137: Spec-000 targets implemented correctly.

The new spec-000-dev and spec-000-build targets:

  • Are properly declared as .PHONY
  • Change to the correct directory (specs/spec-000-rewrite)
  • Use appropriate trunk commands (serve for dev, build --release for prod)
  • Match the documentation in specs/spec-000-rewrite/README.md

The checkmake warnings about missing all, clean, and test targets are overly prescriptive for a project-specific Makefile that uses explicit target names.

docs/execution-plan.md (2)

38-55: Documentation updates tracking completed work — LGTM.

The "Today's Intent" entries properly document the completed WebSocket gateway, Rhai pivot, and RMG authority enforcement work. Consistent with the code changes in this PR.


469-470: Backlog items updated to reflect Rhai scripting — LGTM.

Lua references correctly replaced with Rhai. Aligns with the scripting pivot documented throughout the codebase.

crates/echo-session-ws-gateway/src/main.rs (1)

1-4: SPDX header and module docs — LGTM.

Headers match the required format exactly. Module-level documentation is present and concise.

Comment on lines +212 to +219
Ok((Message::Error(err), _, _)) => {
let _ = notif_tx.send(Notification {
kind: NotifyKind::Error,
scope: NotifyScope::Local,
title: format!("{} ({})", err.name, err.code),
body: Some(err.message),
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for ErrorPayload definition
echo "=== ErrorPayload Definition ==="
ast-grep --pattern $'struct ErrorPayload {
  $$$
}'

echo ""
echo "=== ErrorPayload Usage and Error Code Patterns ==="
rg -nP --type=rust -C3 'ErrorPayload\s*\{|error.*code|name:\s*"' crates/echo-session-client/src/

echo ""
echo "=== Search for error classification or scoping logic ==="
rg -nP --type=rust -C2 'NotifyScope|error.*scope|Local|Global' crates/echo-session-client/src/lib.rs | head -50

echo ""
echo "=== Examine the full context around line 212-219 ==="
sed -n '200,230p' crates/echo-session-client/src/lib.rs

Repository: flyingrobots/echo

Length of output: 2760


🏁 Script executed:

#!/bin/bash
# Search for ErrorPayload in proto files
echo "=== Looking for ErrorPayload definition ==="
fd --extension proto | head -20

echo ""
echo "=== Search in proto files for ErrorPayload ==="
rg -A 10 'message ErrorPayload|struct ErrorPayload' --type=proto

echo ""
echo "=== Check echo_session_proto crate ==="
find . -path "*echo*proto*" -name "*.rs" -type f | head -10

echo ""
echo "=== Search for ErrorPayload in Rust files across repo ==="
rg -nA 5 'ErrorPayload' --type=rust | head -80

Repository: flyingrobots/echo

Length of output: 6106


🏁 Script executed:

#!/bin/bash
# Get complete ErrorPayload definition
echo "=== Full ErrorPayload Definition ==="
sed -n '94,104p' crates/echo-session-proto/src/lib.rs

echo ""
echo "=== Check if error codes/names are used for routing elsewhere ==="
rg -nP 'code:\s*\d+|E_[A-Z_]+|error\.code|error\.name' --type=rust crates/echo-session-client/src/lib.rs | head -30

echo ""
echo "=== Check entire error handling chain in client ==="
sed -n '205,230p' crates/echo-session-client/src/lib.rs

echo ""
echo "=== Look for error code semantics or classification ==="
rg -nP 'code:\s*(3|40[0-9]|50[0-9])' --type=rust crates/ | head -20

echo ""
echo "=== Check if there's any scope determination logic elsewhere ==="
rg -nP 'scope.*=.*match|if.*code|if.*name' --type=rust crates/

Repository: flyingrobots/echo

Length of output: 3186


Scope classification must distinguish session-level errors from decode failures using error codes.

The current implementation blindly assigns NotifyScope::Local to all protocol errors, ignoring the semantic distinction provided by error codes:

  • 3: Decode/wire failures → Local (correct)
  • 403 (E_FORBIDDEN_PUBLISH): Session permission denied → Global (incorrect; currently Local)
  • 409 (E_RMG_EPOCH_GAP, E_RMG_SNAPSHOT_REQUIRED): Protocol state violations → Global (incorrect; currently Local)

The ErrorPayload structure provides both code and name fields—semantic markers already in use by the session service to distinguish error origins. The client must respect this distinction when routing notifications.

Implement error classification logic using the error code range or name prefix (e.g., code >= 400 or name.starts_with("E_FORBIDDEN")) to assign the appropriate scope.

🤖 Prompt for AI Agents
In crates/echo-session-client/src/lib.rs around lines 212 to 219, the
notification always uses NotifyScope::Local for protocol errors; change this to
classify by error code/name so decode/wire failures stay Local while
session/protocol errors are Global (e.g., treat code == 3 or codes < 400 as
NotifyScope::Local, and codes >= 400 as NotifyScope::Global; optionally fall
back to name-based checks such as name.starts_with("E_FORBIDDEN") or
name.starts_with("E_RMG") to cover any ambiguous codes), then construct
Notification with the chosen scope before sending via notif_tx.

Comment on lines +16 to +17
axum = { version = "0.6", features = ["ws"] }
axum-server = { version = "0.5", features = ["tls-rustls"] }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

axum rust crate latest stable version 2024 2025

💡 Result:

  • Latest stable axum (2025): 0.8.4 (release listed Apr 30, 2025). [1]
  • Latest stable axum (2024): 0.7.1 (release listed Jul 31, 2024); axum 0.8.0 was announced Jan 1, 2025. [1][2]

Sources: axum crate listing (lib.rs/crates/axum). [1] Tokio blog announcing axum 0.8.0. [2]


🌐 Web query:

axum 0.6 security advisories CVE

💡 Result:

Yes — axum had a known CVE: CVE-2022-3212 (RustSec RUSTSEC-2022-0055). It’s a denial‑of‑service / OOM issue where certain extractors didn’t set a default request-body size limit. Affected versions: axum <= 0.5.15 and 0.6.0-rc.1 (axum-core also affected). Fixes: axum >= 0.5.16 or >= 0.6.0-rc.2 (axum-core patched in 0.2.8 / 0.3.0-rc.2). Patched behavior sets a 2 MB default body limit — upgrade or apply an explicit body limit as a workaround. [1][2]

Sources:

  • RustSec advisory RUSTSEC-2022-0055 (CVE-2022-3212). [1]
  • OSV / GHSA entry summarizing affected/fixed versions. [2]

🌐 Web query:

axum-server 0.5 compatibility axum 0.7

💡 Result:

Short answer: No — use axum-server 0.7.x with axum 0.7.

Why: axum 0.7 introduced hyper 1.0 and other breaking API changes; axum-server published 0.7.x to match (the axum-server crate shows 0.7.x releases and examples using axum 0.7). axum-server 0.5 (older release) predates those changes and is not guaranteed to work with axum 0.7. [1][2]

Sources:

  • axum 0.7 announcement (hyper 1.0 / API changes). [1]
  • axum-server crate / releases and examples showing axum 0.7 support (use axum-server 0.7.x). [2]

Upgrade both axum and axum-server to compatible versions; axum 0.6 + axum-server 0.5 are severely outdated.

The manifest specifies axum = "0.6" and axum-server = "0.5", both of which are multiple major versions behind current stable (axum 0.8.4, released Apr 2025). Beyond staleness:

  1. Security: CVE-2022-3212 (RUSTSEC-2022-0055) is a denial-of-service/OOM vulnerability in axum extractors that affected 0.6.0-rc.1. While patched in later 0.6.x releases, using 0.6 at all leaves you vulnerable to this class of issue.

  2. Incompatibility: axum-server 0.5 is incompatible with axum 0.7+ due to breaking changes introduced by hyper 1.0 integration in axum 0.7. Upgrading axum alone while keeping axum-server 0.5 will cause compilation or runtime failures.

Action: Upgrade both together. Use axum-server 0.7.x paired with axum 0.7.x, or axum-server 0.7.x with axum 0.8.x for the latest stability and security posture.

🤖 Prompt for AI Agents
In crates/echo-session-ws-gateway/Cargo.toml around lines 16-17, the manifest
pins axum = "0.6" and axum-server = "0.5" which are incompatible and outdated;
update both to compatible, maintained releases (e.g., set axum = "0.8" and
axum-server = "0.7" or at minimum axum = "0.7" with axum-server = "0.7"), keep
the existing features (ws and tls-rustls), run cargo update and cargo build to
catch breaking changes, and then adjust imports/usage for any axum/axum-server
API changes introduced by the upgrade (especially around hyper integration and
extractor behavior) until the project compiles and tests pass.

Comment on lines +7 to +15
## Usage

```
cargo run -p echo-session-ws-gateway -- \
--unix-socket /tmp/echo-session.sock \
--listen 0.0.0.0:8787 \
--allow-origin https://your.host \
--tls-cert cert.pem --tls-key key.pem
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Markdown lint violations: missing blank lines around heading and code fence.

Static analysis flagged MD022 and MD031. The heading and code fence need breathing room.

Apply this fix:

 ## Usage
+

cargo run -p echo-session-ws-gateway --
--unix-socket /tmp/echo-session.sock
--listen 0.0.0.0:8787
--allow-origin https://your.host
--tls-cert cert.pem --tls-key key.pem

+
## Features

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


10-10: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🤖 Prompt for AI Agents
In crates/echo-session-ws-gateway/README.md around lines 7 to 15, the heading
and fenced code block lack required blank lines (MD022 and MD031). Fix by adding
a blank line before the triple-backtick fence that starts the example and a
blank line after the closing triple-backtick and before the next heading so the
code block and headings are separated by one empty line each.

Comment on lines +132 to +145
async fn handle_socket(mut socket: WebSocket, state: Arc<AppState>, peer: SocketAddr) {
let unix = match UnixStream::connect(&state.unix_socket).await {
Ok(stream) => stream,
Err(err) => {
error!(?err, "failed to connect to unix socket");
let _ = socket
.send(Message::Close(Some(axum::extract::ws::CloseFrame {
code: axum::extract::ws::close_code::ERROR,
reason: "upstream unavailable".into(),
})))
.await;
return;
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

No timeout on Unix socket connect — can hang indefinitely.

If the Unix socket exists but the service is deadlocked or slow to accept, UnixStream::connect blocks forever. The WebSocket client hangs with no feedback.

Wrap with a timeout:

-    let unix = match UnixStream::connect(&state.unix_socket).await {
+    let unix = match tokio::time::timeout(
+        Duration::from_secs(5),
+        UnixStream::connect(&state.unix_socket),
+    )
+    .await
+    {
+        Ok(Ok(stream)) => stream,
+        Ok(Err(err)) => {
-        Ok(stream) => stream,
-        Err(err) => {
             error!(?err, "failed to connect to unix socket");
             // ... send close frame ...
             return;
         }
+        Err(_) => {
+            error!("unix socket connect timeout");
+            let _ = socket
+                .send(Message::Close(Some(axum::extract::ws::CloseFrame {
+                    code: axum::extract::ws::close_code::ERROR,
+                    reason: "upstream timeout".into(),
+                })))
+                .await;
+            return;
+        }
     };

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In crates/echo-session-ws-gateway/src/main.rs around lines 132 to 145, the
UnixStream::connect call can block indefinitely if the upstream is unresponsive;
wrap the connect in a tokio::time::timeout (e.g. timeout(Duration::from_secs(N),
UnixStream::connect(...))). If the timeout elapses, log a clear timeout error
and close the WebSocket with an appropriate CloseFrame (same as current error
path but indicating timeout/upstream unavailable), and handle the Result from
timeout to treat both connect errors and elapsed time similarly. Add the
necessary imports (tokio::time::{timeout, Duration}) and choose a sensible
timeout duration.

Comment on lines +160 to +179
// UDS -> WS task: frame and forward packets
let max_len = state.max_frame_bytes;
let out_tx_clone = out_tx.clone();
let uds_to_ws = tokio::spawn(async move {
let mut buf = vec![0u8; 16 * 1024];
let mut acc: Vec<u8> = Vec::with_capacity(32 * 1024);
loop {
let n = uds_reader.read(&mut buf).await?;
if n == 0 {
break;
}
acc.extend_from_slice(&buf[..n]);
while let Some(pkt) = try_extract_frame(&mut acc, max_len)? {
if out_tx_clone.send(Message::Binary(pkt)).await.is_err() {
return Ok::<(), anyhow::Error>(());
}
}
}
Ok::<(), anyhow::Error>(())
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Unbounded accumulator — DoS vector if upstream sends malformed data.

The acc vector grows without limit. If the upstream Unix socket sends data that never completes a valid frame (malicious or buggy), memory consumption is unbounded. An attacker controlling the upstream could exhaust memory.

Add a cap on accumulator size:

+const MAX_ACC_SIZE: usize = 16 * 1024 * 1024; // 16 MiB accumulator cap
+
 let uds_to_ws = tokio::spawn(async move {
     let mut buf = vec![0u8; 16 * 1024];
     let mut acc: Vec<u8> = Vec::with_capacity(32 * 1024);
     loop {
         let n = uds_reader.read(&mut buf).await?;
         if n == 0 {
             break;
         }
         acc.extend_from_slice(&buf[..n]);
+        if acc.len() > MAX_ACC_SIZE {
+            return Err(anyhow!("accumulator overflow — malformed upstream"));
+        }
         while let Some(pkt) = try_extract_frame(&mut acc, max_len)? {

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +71 to +79
## JITOS Engineering Standard (Living Specs)

Echo follows the JITOS Engineering Standard: every SPEC is simultaneously documentation, implementation, interactive demo (WASM), living test, and contributor certification. See `docs/METHODOLOGY.md` for the full 5x Duty model and workflow.

### WASM Dev Quickstart (Spec-000)
- Prereq: `rustup target add wasm32-unknown-unknown` and `cargo install --locked trunk`
- Dev: `make spec-000-dev` (hot reload at http://127.0.0.1:8080)
- Build: `make spec-000-build` (outputs to `specs/spec-000-rewrite/dist/`)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Address markdown formatting issues.

Multiple markdown lint issues in this section:

  • Line 75: Missing blank line after heading
  • Line 77: Bare URL should use link syntax

These are cosmetic but reduce readability.

Apply this diff:

 ## JITOS Engineering Standard (Living Specs)
-
 Echo follows the JITOS Engineering Standard: every SPEC is simultaneously documentation, implementation, interactive demo (WASM), living test, and contributor certification. See `docs/METHODOLOGY.md` for the full 5x Duty model and workflow.
 
 ### WASM Dev Quickstart (Spec-000)
+
 - Prereq: `rustup target add wasm32-unknown-unknown` and `cargo install --locked trunk`
-- Dev: `make spec-000-dev` (hot reload at http://127.0.0.1:8080)
+- Dev: `make spec-000-dev` (hot reload at <http://127.0.0.1:8080>)
 - Build: `make spec-000-build` (outputs to `specs/spec-000-rewrite/dist/`)

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

75-75: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


77-77: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In README.md around lines 71 to 79, the Markdown has formatting issues: add a
blank line immediately after the "### WASM Dev Quickstart (Spec-000)" heading
(line ~75) so the list renders correctly, and replace the bare URL
"http://127.0.0.1:8080" with Markdown link syntax (e.g.
[http://127.0.0.1:8080](http://127.0.0.1:8080)) in the Dev line so it’s not a
bare URL; keep other text unchanged.

Comment on lines +82 to +87
<body>
<div id="app"></div>
<script type="module">
import init from "./pkg/spec_000_rewrite.js";
init();
</script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Orphaned #app div — Leptos mounts to <body>, not this element.

The <div id="app"></div> sits here doing absolutely nothing. In lib.rs:44, you call leptos::mount_to_body(...), which renders the component directly into <body>, completely bypassing this div.

Either:

  1. Remove the orphaned div (it's dead weight), or
  2. Use leptos::mount_to(document().get_element_by_id("app").unwrap(), ...) if you want controlled mounting.

If mounting to body is intentional (common pattern), clean up the HTML:

   <body>
-    <div id="app"></div>
     <script type="module">
       import init from "./pkg/spec_000_rewrite.js";
       init();
     </script>
   </body>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<body>
<div id="app"></div>
<script type="module">
import init from "./pkg/spec_000_rewrite.js";
init();
</script>
<body>
<script type="module">
import init from "./pkg/spec_000_rewrite.js";
init();
</script>
</body>
🤖 Prompt for AI Agents
In specs/spec-000-rewrite/index.html around lines 82–87, there's an unused <div
id="app"></div> because the app is mounted directly to <body> in lib.rs:44 via
leptos::mount_to_body; remove the orphaned div if you intend to mount to body,
or change the Rust mounting call to mount to the element by id
(document().get_element_by_id("app").unwrap()) if you want controlled mounting —
update the HTML or the mounting call accordingly so the DOM element and mounting
target match.

Comment on lines +8 to +11
/// Top-level Spec-000 Leptos component (WASM).
#[allow(missing_docs)]
#[component]
pub fn App() -> impl IntoView {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Redundant #[allow(missing_docs)] — there's a doc comment right above it.

You have /// Top-level Spec-000 Leptos component (WASM). on line 8, then immediately suppress the lint that would have fired if it were missing. Pick one: document it OR suppress the warning. Both is cargo-cult code.

Remove the redundant allow:

 /// Top-level Spec-000 Leptos component (WASM).
-#[allow(missing_docs)]
 #[component]
 pub fn App() -> impl IntoView {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Top-level Spec-000 Leptos component (WASM).
#[allow(missing_docs)]
#[component]
pub fn App() -> impl IntoView {
/// Top-level Spec-000 Leptos component (WASM).
#[component]
pub fn App() -> impl IntoView {
🤖 Prompt for AI Agents
In specs/spec-000-rewrite/src/lib.rs around lines 8 to 11, the
#[allow(missing_docs)] attribute is redundant because a doc comment (///
Top-level Spec-000 Leptos component (WASM).) is already present; remove the
#[allow(missing_docs)] line so the code is either documented or intentionally
suppressed but not both.

Comment on lines +39 to +42
/// WASM entry point required by `trunk serve`.
#[allow(missing_docs)]
#[wasm_bindgen(start)]
pub fn main() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Same redundancy: doc comment + #[allow(missing_docs)].

Line 39 documents main(), then line 40 suppresses the docs warning. Wasteful duplication of intent.

 /// WASM entry point required by `trunk serve`.
-#[allow(missing_docs)]
 #[wasm_bindgen(start)]
 pub fn main() {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// WASM entry point required by `trunk serve`.
#[allow(missing_docs)]
#[wasm_bindgen(start)]
pub fn main() {
/// WASM entry point required by `trunk serve`.
#[wasm_bindgen(start)]
pub fn main() {
🤖 Prompt for AI Agents
In specs/spec-000-rewrite/src/lib.rs around lines 39 to 42, there's redundant
documentation: the doc comment for main() and the #[allow(missing_docs)]
attribute express the same intent; remove the #[allow(missing_docs)] attribute
on line 40 (or alternatively remove the doc comment) so only one of them
remains—prefer keeping the doc comment and delete the attribute to eliminate the
duplication.

Comment on lines +8 to +41
## P0 — Bootstrap & Scaffold
- [ ] Scaffold `specs/spec-000-rewrite` Leptos+Trunk app (CSR) with `index.html`, `src/lib.rs`, panic hook, hot-reload.
- [ ] Add workspace membership and `make spec-000-{dev,build}` helpers.
- [ ] Failing check: `cargo check -p spec-000-rewrite --target wasm32-unknown-unknown` in CI job (Trunk build).

## P1 — Kernel Bindings & Types
- [ ] Add `wasm-bindgen` feature to kernel crate (or shim crate) and expose minimal RMG/rewrite API (add node, set field, connect, tombstone, materialize).
- [ ] Create shared DTO crate (`echo-wasm-abi`) with serde + wasm-bindgen-friendly types for graph and rewrite log; reuse in UI.
- [ ] Failing tests: wasm-bindgen unit test exercising add/set/connect/tombstone round-trip serialization.

## P1 — UI MVP (Living Spec)
- [ ] Render graph (SVG/canvas) from serialized RMG; simple layout.
- [ ] Render rewrite log; click-to-time-travel replays history via kernel API.
- [ ] “Apply Rewrite” panel hooks to kernel methods; updates view reactively.
- [ ] Failing tests: screenshot/DOM snapshot via Playwright (Trunk serve) or headless wasm-bindgen tests for state transitions.

## P2 — Certification & Win Condition
- [ ] Implement completion detector that issues a completion hash/badge when the user reaches target state (Spec-000).
- [ ] Persist/emit completion hash for PR inclusion; document the flow.
- [ ] Failing test: deterministic hash for canonical walkthrough sequence.

## P2 — Tooling & CI
- [ ] GitHub Action: build spec-000 with Trunk (wasm32-unknown-unknown), cache target/Trunk, artifact the dist.
- [ ] Size guard: assert wasm bundle < configured budget; fail if exceeded.
- [ ] Lint: add `cargo fmt`/`clippy` (wasm target) gate for spec crates.

## P3 — UX & Resilience
- [ ] Error surface: UI shows kernel errors (invalid rewrite, payload too large).
- [ ] Offline-first: bundle assets, graceful fallback when no network.
- [ ] Performance pass: incremental graph diffing instead of full redraw; fast layout for ≤200 nodes.
- [ ] Accessibility: keyboard navigation for rewrites; ARIA on controls.

## P3 — Future Spec Template
- [ ] Turn spec-000 into a `spec-template/` scaffold script for future specs (copy, rename, wire to new kernel module, add win condition).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Address markdown heading spacing throughout.

Multiple headings lack blank lines before their content (lines 8, 13, 18, 24, 29, 34, 40). While minor, consistent formatting improves readability and satisfies linters.

The pattern is consistent: each ## P<N> — <Title> heading should have a blank line before the first list item. Apply this pattern to all six section headings (P0 through P3 sections).

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

8-8: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


13-13: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


18-18: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


24-24: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


29-29: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


34-34: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


40-40: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
In WASM-TASKS.md around lines 8 to 41 the section headings (## P0 — Bootstrap &
Scaffold, ## P1 — Kernel Bindings & Types, ## P1 — UI MVP (Living Spec), ## P2 —
Certification & Win Condition, ## P2 — Tooling & CI, ## P3 — UX & Resilience, ##
P3 — Future Spec Template) do not have a blank line before their first list
item; insert a single blank line after each heading so there is an empty line
between the heading and the subsequent checklist items to match markdown style
and linter expectations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants