-
Notifications
You must be signed in to change notification settings - Fork 1
Echo/wasm spec 000 scaffold #141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Summary by CodeRabbitRelease Notes
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughThis 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
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50–75 minutes Areas requiring careful attention:
Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Signed-off-by: James Ross <[email protected]>
There was a problem hiding this 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".
There was a problem hiding this 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
⛔ Files ignored due to path filters (3)
Cargo.lockis excluded by!**/*.lockassets/echo-white-2.svgis excluded by!**/*.svgassets/echo-white.svgis 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.0and// © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>
Files:
specs/spec-000-rewrite/src/lib.rscrates/echo-session-client/src/lib.rscrates/rmg-ffi/src/lib.rscrates/echo-session-ws-gateway/src/main.rscrates/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.mdREADME.mddocs/spec-concurrency-and-authoring.mdCONTRIBUTING.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.mdspecs/spec-000-rewrite/Cargo.tomlCargo.tomlREADME.mdcrates/echo-session-ws-gateway/Cargo.tomldocs/spec-concurrency-and-authoring.mddocs/phase1-plan.mdcrates/rmg-ffi/Cargo.tomlCONTRIBUTING.mddocs/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.mdspecs/spec-000-rewrite/Cargo.tomlCargo.tomlREADME.mdcrates/echo-session-ws-gateway/Cargo.tomlcrates/rmg-ffi/src/lib.rscrates/rmg-ffi/Cargo.tomldocs/tasks.mdcrates/echo-session-ws-gateway/src/main.rscrates/rmg-ffi/README.mdCONTRIBUTING.mdcrates/echo-session-ws-gateway/README.mddocs/execution-plan.mdcrates/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.mdspecs/spec-000-rewrite/Cargo.tomlREADME.mddocs/spec-concurrency-and-authoring.mdcrates/rmg-ffi/README.mdCONTRIBUTING.mddocs/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.mdcrates/rmg-ffi/Cargo.tomlCONTRIBUTING.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.mdCONTRIBUTING.mddocs/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.mdCONTRIBUTING.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.mddocs/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_snapshoteach document intent and invariants. Repr(C) layout is correct for FFI.
49-74: Engine lifecycle functions properly documented with Safety sections.
rmg_engine_newandrmg_engine_freeestablish 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:
fnkeyword for function definitions#{ key: value }for object literals::for namespace/module accessthiskeyword for method contextThe 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_errortest 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-devandspec-000-buildtargets:
- Are properly declared as
.PHONY- Change to the correct directory (
specs/spec-000-rewrite)- Use appropriate trunk commands (
servefor dev,build --releasefor prod)- Match the documentation in
specs/spec-000-rewrite/README.mdThe checkmake warnings about missing
all,clean, andtesttargets 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.
| 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), | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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.rsRepository: 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 -80Repository: 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.
| axum = { version = "0.6", features = ["ws"] } | ||
| axum-server = { version = "0.5", features = ["tls-rustls"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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:
-
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.
-
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.
| ## 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 | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| // 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>(()) | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| ## 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/`) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| <body> | ||
| <div id="app"></div> | ||
| <script type="module"> | ||
| import init from "./pkg/spec_000_rewrite.js"; | ||
| init(); | ||
| </script> |
There was a problem hiding this comment.
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:
- Remove the orphaned div (it's dead weight), or
- 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.
| <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.
| /// Top-level Spec-000 Leptos component (WASM). | ||
| #[allow(missing_docs)] | ||
| #[component] | ||
| pub fn App() -> impl IntoView { |
There was a problem hiding this comment.
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.
| /// 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.
| /// WASM entry point required by `trunk serve`. | ||
| #[allow(missing_docs)] | ||
| #[wasm_bindgen(start)] | ||
| pub fn main() { |
There was a problem hiding this comment.
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.
| /// 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.
| ## 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). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Echo is becoming JITOS kernel
Adds spec 0000 scaffold
Specs will be:
This sets up the foundation to build these specs.