Skip to content

0024 universal LE binary codec + 0025 sessions design (design-only)#382

Merged
flyingrobots merged 17 commits into
mainfrom
cycle/0025-sessions-as-causal-contexts
May 30, 2026
Merged

0024 universal LE binary codec + 0025 sessions design (design-only)#382
flyingrobots merged 17 commits into
mainfrom
cycle/0025-sessions-as-causal-contexts

Conversation

@flyingrobots
Copy link
Copy Markdown
Owner

@flyingrobots flyingrobots commented May 30, 2026

Summary

Lands two stacked workstreams as one PR (per maintainer instruction):

  • 0024 universal LE binary codec (commits 77bcae6bb257dd) — the in-flight stack that was previously stack/echo-le-binary-codec. Adds Wesley-generated LE binary encode/decode for the rope codec across Rust and TypeScript, EINT envelope work, cross-boundary fixture proofs, and PLATFORM backlog captures.
  • 0025 — sessions as causal contexts (commits 5a73a3f499ad99) — Phase 1 design only. Promotes Session to a first-class durable causal-context node integrating with existing warp-core primitives (playback::SessionId, head_inbox.rs, optic_artifact::PrincipalRef) rather than replacing them. Includes the design packet (design.md, request.md, phase-2-handoff.md), retires PLATFORM_echo-session-proto-split.md to graveyard, and stops cleanly at the METHOD Phase 1 STOP boundary. No Rust code, no API surface changes, no Wesley IR edits. Phase 2 RED + GREEN begin only with explicit implementation greenlight per the handoff note.

The 0025 design responds to a structural smell that surfaced in the jedit Slice B EINT cutover (jedit PR #33): the wire was carrying jedit-internal session state because Echo had no name for the thing. Rather than codifying the client-side workaround, this cycle's design proposes the engine-side concept that makes the workaround scaffold-deletable.

Key locked design decisions (binding on Phase 2)

  • Session is a principal-bound causal-context node; does not own an ingress queue or a mutation-ordering lane (HeadInbox / IngressTarget and worldline head/tick remain authoritative).
  • playback::SessionId is unified with this cycle's SessionId — two live concepts forbidden.
  • Two settlement events (IntentReceiptIssued, IntentEffectsQuiesced) replace the ambiguous IntentSettled; IntentEffectsQuiesced is a one-way gate per intent.
  • IntentRejected records stage (Decode / SessionGate / HeadInboxAdmission / Execution) and reason; MissingSession and UnknownSession are distinct.
  • system/genesis is primordial with a concrete PrincipalRef::system("genesis")-shaped identity. No null session, no null principal anywhere.
  • V1 routing is single-target IngressTarget; atomic multi-target deferred. V1 abortive close is the weaker variant — pending-ingress cancellation in HeadInbox is deferred to a follow-up cycle.
  • EINT wire target is an IngressAddress-shaped protocol value mapped to runtime IngressTarget at decode (no Rust enum smuggling).

Test plan

  • Phase 1 STOP per METHOD — no code, no RED tests in this PR
  • All five pre-RED decisions documented in phase-2-handoff.md for the Phase 2 agent
  • Markdown lint clean (markdownlint-cli2, prettier)
  • Internal-consistency audit clean (no stale references to dropped v1 model: Session-owned inbox/lane, target_worldlines plural, writer_ref, echo-session-proto-split coordination)
  • Reviewer: confirm 0024 stack is approved-for-main alongside 0025 design (the two are landing together by maintainer call)
  • Reviewer: confirm playback::SessionId unification scope is acceptable for Phase 2 implementation
  • Reviewer: confirm primordial system/genesis bootstrap shape (genesis-time creation, not via intent) before Phase 2 starts
  • Reviewer: confirm wesley-core = "0.0.4" pin reconciliation path before Phase 2 (Session as Wesley-emitted node type)

Companion: jedit PR #33 (Slice A+B EINT cutover with first-class session port + the architectural follow-up from this design review).

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced universal little-endian binary codec as the default serialization format, replacing CBOR.
    • Added support for additional scalar types and containers: 32-bit integers, canonicalized floating-point numbers, booleans, optional types, and lists.
    • Expanded codec validation to detect and reject malformed or incomplete payloads.
  • Tests

    • Added comprehensive test suites validating codec roundtrips and cross-boundary wire encoding.
  • Documentation

    • Added design specification for universal LE binary codec with schema fingerprinting.
    • Added design specification for sessions as causal contexts with lifecycle and attribution handling.

Review Change Stack

Extends echo-wasm-abi::codec with the missing GraphQL scalar coverage
required by the universal LE binary codec:

  write_i32_le / read_i32_le   — for GraphQL Int
  write_f32_le / read_f32_le   — for GraphQL Float (with inline canonicalization)
  write_bool   / read_bool      — for GraphQL Boolean (u8 0x00/0x01)
  write_option / read_option    — presence tag (u8) + conditional payload
  write_list   / read_list      — u32 LE count + elements

Also adds `canonicalize_f32()` as a public helper that replicates the
F32Scalar::new() invariant without depending on warp-math:
  NaN (any) → 0x7fc00000, subnormal → +0.0, -0.0 → +0.0.

Adds CodecError::InvalidBoolTag for malformed bool/option presence bytes.

28 new unit tests cover roundtrips, wire byte layout, and f32 edge cases
(NaN variants, subnormals, -0.0, +Infinity).

Part of 0024-universal-le-binary-codec Phase 2.
Replace CBOR vars encoding with echo_wasm_abi::codec LE binary.
Generate impl Encode + Decode for all InputObject and Enum types.
Generate impl Encode + Decode for all Vars structs.
Always force CODEC_ID = "le-binary-v1" (hard cutover, no migration).
Update encode/decode helpers and error types to use codec::CodecError.
Update generation tests and smoke crate to match new behavior.

Also adds CodecError::Trailing and Reader::remaining() to codec.rs so
decode_from_bytes rejects trailing bytes after a complete decode.

Part of 0024-universal-le-binary-codec Phase 4.
Adds tests/jedit_rope_cross_boundary.rs in echo-wasm-abi that uses the
LE binary codec primitives to encode canonical rope-schema Vars values
and asserts the produced byte sequences are bytewise identical to the
literal hex vectors asserted by jedit/spec/rope-codec.spec.mjs.

This locks the Rust↔TS contract for the rope codec at the primitive
level: AnchorBias / CheckpointKind enum discriminants, the
CreateBufferWorldlineInput layout (with required + nullable fields
mixed), the ReplaceRangeAsTickInput i32 layout, and the
CreateCheckpointInput enum-in-the-middle layout. 12 tests, all green.

If a future change breaks parity, both ends fail simultaneously: the
TS spec on one side and these Rust assertions on the other.

Covers Phase 6 (cross-boundary roundtrip fixtures) of
docs/design/0024-universal-le-binary-codec/design.md.
Adds tests/jedit_rope_cross_boundary_eint.rs covering pack_intent_v1
against the same hex literals asserted by jedit/spec/eint.spec.mjs.
Pairs the EINT envelope contract on the Rust side with the TS
packIntentV1 added in jedit's stack/jedit-rope-rename.

This locks the wrapper layer (envelope) so the next phase (swapping
jedit's optic-client JSON wire for EINT-wrapped LE binary vars) can
proceed without worrying about envelope drift.
Adds a `stable_op_id_pinned` test module to echo-wesley-gen that
asserts the FNV-1a outputs for the five rope-schema operations match
the same u32 values pinned by `wesley_core::stable_op_id` (added in
wesley-core ≥0.0.5).

These tests catch drift between echo-wesley-gen's local stable_op_id
copy and wesley-core's canonical version, which will collapse to a
single source of truth when echo bumps wesley-core to 0.0.5+. Until
then, this pin is the guarantee that the local copy stays bytewise
identical to Wesley.

Also adds a docstring on the local `stable_op_id` flagging the
transitional duplication.
- bad-code/PLATFORM_echo-wesley-gen-monolith: 2000+ line file mixes
  type/codec/op-id/footprint/registry/intent/optic/contract-host emit.
  Suggested split into composable sub-emitters.
- bad-code/PLATFORM_warp-wasm-cbor-debt: outer request types and all
  response envelopes are still CBOR; `_cbor` function names; codec_id
  reports cbor-canonical-v1 while EINT path is LE binary. Audited
  2026-05-28; full removal is a future cycle.
- cool-ideas/PLATFORM_schema-version-fingerprint-prefix: 32-byte
  SCHEMA_SHA256 prefix on every framed message gives hard rejection
  instead of silent corruption — codec_id captures format version but
  not schema version.
- cool-ideas/PLATFORM_wesley-emitted-fixture-vectors: wire-parity hex
  literals are duplicated in Rust and TS specs today; Wesley should
  emit fixture-vectors.json and both sides read the same file.
The frame that connects Echo, Wesley, jedit, git-warp, Graft, WARPDrive,
warp-ttd, and the rest exists — it's the table in
docs/architecture/there-is-no-graph.md under 'Runtimes As Optics'. A
first-time visitor to github.com/flyingrobots cannot see it; they see
~20 sibling repos with no ordering, status, or dependency hints.

Card proposes two shapes (profile README is the lightweight win; an
umbrella repo with diagram + status is the heavier path) and
recommends shipping the lightweight one first. Estimated half a day
for the profile README; the biggest blocker is honestly labeling
which projects are foundational vs experimental vs archived.

Filed in echo's backlog because echo's docs already host the WARP
optics framing language. The card prompts lifting that frame from
buried architecture notes to a profile-level front door.
Pull and design phase for cycle 0025, extending the 0024 LE binary cutover
with a first-class Session concept in Echo. Branched from
stack/echo-le-binary-codec rather than main because the EINT envelope under
discussion in 0024 is exactly the surface where session addressing attaches;
deferring would force a wire-shape rebuild or block jedit's observe-path
cutover.

Promotes Session from jedit's client-side scaffold (the JeditWorldlineSession
Port introduced in jedit commit 26a8f43, Slice B of 0024) to a first-class
addressable causal-context node, with the following design commitments:

  - Session is a new primitive that composes Writer/Worldline/Connection/
    Optic, not a generalization of any of them.
  - Two-event settlement (IntentReceiptIssued + IntentEffectsQuiesced)
    replaces the ambiguous IntentSettled.
  - runUntilIdle takes an explicit until: receipt | quiescent mode — no
    fake idle.
  - Two-stage close (graceful vs abortive); detached post-close sub-lanes
    explicitly out of v1.
  - Cross-session worldline concurrency: v1 obstruction-only; true
    concurrent lanes deferred.
  - Intent.target_worldlines typed plural, v1 enforces singleton.
  - PrincipalRef-shaped writer identity from day one.
  - No null/default session; system sessions are explicit and named.
  - Naming collision with echo-session-proto acknowledged; coordination
    plan stated.

Phase 1 STOP per METHOD: presenting the design for human review before
proceeding to RED/GREEN.
…ives

Substantial Phase 1 revision after reading warp-core. The original v1
positioned Session as owning an inbox and a causal lane. That conflicts
with existing primitives:

  - warp-core::head_inbox already provides worldline-scoped ingress
    (IngressTarget::DefaultWriter / InboxAddress / ExactHead, plus
    HeadInbox queues). A session-owned inbox would create a duplicate
    admission queue.
  - warp-core::playback::SessionId already exists with semantics close
    to this cycle's Session ("client's authenticated context and
    subscription set"). Two live SessionId concepts are forbidden.
  - warp-core::optic_artifact::PrincipalRef already exists and is the
    right shape for Session.writer_ref.

Revised model:

  - Session is a first-class durable causal-context node with
    PrincipalRef, lifecycle state, admission gate, attribution surface,
    and a queryable event projection.
  - Session does NOT own an inbox. Submissions route through the
    existing HeadInbox after the session admission gate validates
    status/capability.
  - Session does NOT own a causal lane. Worldline head/tick remains the
    mutation-ordering authority. The session-scoped view of work is a
    derived projection (working name SessionEventLog — explicitly NOT
    SessionLane to avoid implying a competing causal-ordering primitive).
  - playback::SessionId is unified with this cycle's SessionId. The
    shape stays; ViewSession becomes a read-side facet attached to a
    Session.
  - System bootstrap: system/genesis is primordial (created at genesis,
    no originating intent); all other system sessions opened normally
    through it.
  - EINT envelope change classified as "additive to the semantic
    envelope model, potentially breaking to strict encoders/decoders;
    coordinate with 0024."
  - PLATFORM_echo-session-proto-split moved to graveyard. The networked
    inspection prototype is retired entirely; the Session name is
    reclaimed for the causal-context sense.

Phase 1 STOP per METHOD: presenting the revised design for review.
Eight targeted fixes after directional approval, before Phase 2 RED:

  1. principal_ref / principal_label replace writer_ref / writer_label.
     Session unifies read and write contexts; principal is the canonical
     name.
  2. Drop target_worldlines plural. v1 uses existing IngressTarget. Atomic
     multi-target submissions deferred as a future cycle with a future
     shape (NonEmptyList<IngressTarget> or AtomicIngressBatch).
  3. SessionEventLog ordering pinned: engine event log's deterministic
     event order (LogicalTime / event sequence + content-address tie-
     breaker). Explicitly not mutation order.
  4. IntentRejected gains stage (SessionGate | HeadInboxAdmission |
     Execution) and reason. Distinguishes unknown-session (no projection),
     closed-session (appears in that session's projection), and base-head-
     mismatch (attributed to the valid submitting session).
  5. Abortive close grounded: IngressEnvelope must carry session_id
     attribution and HeadInbox needs a cancel-by-session_id API. Fallback
     scope call documented if the extension is too invasive.
  6. system/genesis carries a concrete PrincipalRef::system("genesis")-
     shaped identity. No null principal anywhere, even at the bottom
     turtle.
  7. EINT target field is an IngressAddress-shaped protocol value mapped
     to warp-core::head_inbox::IngressTarget at decode. Codec does not
     smuggle the Rust enum directly.
  8. Quiescence registration rule: bounded child work must be registered
     before observing parent quiescence; after IntentEffectsQuiesced,
     no new bounded child may be registered for that intent. Makes
     quiesced a one-way gate per intent. Added as core invariant #10
     and to the test list.

Implementation outline expanded to 11 steps (added the HeadInbox
attribution extension and the quiescence gate to runUntilIdle).

Phase 1 STOP holds: presenting the cleaned design for Phase 2 RED green-
light.
Three pre-RED clarifications binding on Phase 2 tests:

  1. Abortive close v1: commit to weaker variant (B), not the full
     HeadInbox surgery. IngressEnvelope content-addressing is
     determinism-critical; bundling Session introduction with
     IngressEnvelope.session_id and HeadInbox cancel-by-session_id in
     one cycle multiplies risk inside a strict-determinism engine.
     V1 abortive close blocks new submissions and cancels interruptible
     accepted work; pending-ingress cancellation is deferred to a
     follow-up cycle. Tests assert the deferral explicitly so the
     scope call is honest, not silent.

  2. Wire/runtime naming discipline pinned for RED: IngressAddress is
     the wire/EINT type; IngressTarget is the warp-core runtime type;
     the decode boundary maps one to the other. Tests for the wire
     surface assert on IngressAddress; tests for admission assert on
     IngressTarget; neither asserts the wire serializes IngressTarget
     directly.

  3. IntentRejected gains a Decode stage and a MissingSession reason,
     distinct from UnknownSession. Missing means "header absent";
     unknown means "header present but does not resolve." MissingSession
     has no SessionEventLog projection to land in; UnknownSession
     likewise. ClosedSession appears in that closed session's
     projection. BaseHeadMismatch is attributed to the valid submitting
     session at HeadInboxAdmission.

Phase 1 STOP holds; awaiting Phase 2 RED scope confirmation.
Doc-only commit closing out Phase 1 design work cleanly. Captures the
locked design decisions, the five pre-RED decisions that Phase 2 must
resolve before writing tests, the full RED test matrix expressed as
invariants (not tests), and an explicit reminder that no Rust tests,
stubs, modules, or API surface have been introduced in this cycle.

Path 1 chosen: stop after Phase 1, hand off Phase 2 explicitly, do not
let RED start implicitly. RED tests against nonexistent warp-core APIs
effectively create the public shape of the implementation; that crosses
the design-only boundary scoped for this conversation.

Phase 2 (RED + GREEN) begins only with explicit implementation
greenlight.
Doc-only fixes after a strict review found contradictions and stale
language. No design changes — just bringing the doc into sync with the
decisions already locked across the cycle's prior commits.

request.md:
  - Drop rejected v1 model language (Session "ingress mailbox" and
    "accepted causal lane" — both rejected in 8a21f04).
  - Drop Intent.target_worldlines: NonEmptyList typed acceptance criterion
    (replaced with single IngressTarget in a53cac9).
  - Rename "writer reference" / "writer identity" to "principal reference"
    / "principal identity" per 34e4984.
  - Rewrite echo-session-proto-split non-goal as "retired entirely"
    rather than "coordinated" (retirement landed in 8a21f04).
  - Expand acceptance criteria to cover the IntentRejected stage/reason
    surface, the one-way quiescence gate, the abortive-close deferral,
    the system/genesis primordial bootstrap, the IngressAddress wire
    boundary, and the no-null-session/principal invariant.

design.md:
  - Close-section bullet list (was: "Cancel / reject pending ingress"
    listed as a v1 feature with parenthetical link to the deferral
    subsection) rewritten to match the deferral: pending-ingress
    cancellation is out of v1.
  - Non-goal language for atomic multi-target submissions rewritten;
    no more "type admits plural; v1 enforces singleton" since the design
    body now uses a single IngressTarget (a53cac9). Future cycle picks
    both shape and semantics together.
  - Correlation closing list (session position in SessionEventLog) and
    test bullet for IntentSubmitted/IntentAccepted ordering both updated
    to engine event log deterministic order — matches the Ordering
    subsection. The two had silently disagreed.
  - Session shape code-block alignment fixed after writer_ref →
    principal_ref rename (visual columns no longer drifted).
  - ADR-0008 reference hedged to "per the head_inbox.rs module comment"
    since the ADR file itself wasn't verified during design.

graveyard/PLATFORM_echo-session-proto-split.md:
  - Replace curly quotes with straight in the preserved original prose
    for consistency with surrounding documents.

phase-2-handoff.md surveyed under the same audit; remaining
echo-session-proto-split references in it are correct historical
pointers to the graveyard location and do not need changes.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 30, 2026

Warning

Review limit reached

@flyingrobots, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 58 minutes. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 90cb058b-3f7b-4c6b-83ac-12ec60a56ce6

📥 Commits

Reviewing files that changed from the base of the PR and between 8ef2fc9 and f25e07a.

📒 Files selected for processing (8)
  • crates/echo-wasm-abi/src/codec.rs
  • crates/echo-wasm-abi/tests/jedit_rope_cross_boundary.rs
  • crates/echo-wesley-gen/src/main.rs
  • crates/echo-wesley-gen/tests/generation.rs
  • docs/design/0024-universal-le-binary-codec/design.md
  • docs/method/backlog/bad-code/DOCS_no-published-umbrella-for-warp-optics.md
  • docs/method/backlog/cool-ideas/PLATFORM_wesley-emitted-fixture-vectors.md
  • docs/method/backlog/cool-ideas/PLATFORM_wesley-gen-test-loop-speedup.md
📝 Walkthrough

Walkthrough

This PR implements the foundational LE binary codec infrastructure (scalar/container wire support, canonicalized f32 handling, option/list encoding) and switches the generator from Canonical CBOR to LE binary format. It establishes cross-boundary codec test fixtures asserting exact byte encodings, and introduces comprehensive design documentation for sessions as causal contexts with phase-2 readiness guidance.

Changes

LE Binary Codec Implementation & Generator Conversion

Layer / File(s) Summary
Codec error types and decode validation
crates/echo-wasm-abi/src/codec.rs
CodecError gains InvalidBoolTag and Trailing variants; decode_from_bytes enforces strict no-trailing-bytes validation.
Writer/Reader scalar and container encodings
crates/echo-wasm-abi/src/codec.rs
Writer adds i32 LE, canonicalized f32, bool, Option, and &[T] list encoders; Reader gains matching decoders with tag validation and bounded capacity allocation.
Canonical f32 normalization
crates/echo-wasm-abi/src/codec.rs
Public canonicalize_f32 helper deterministically maps NaNs, subnormals, and signed zeros to canonical bit pattern.
Codec roundtrip and canonicalization tests
crates/echo-wasm-abi/src/codec.rs
Comprehensive test module covering i32, f32 (NaN/subnormal/±0.0), bool, Option, list roundtrips, and canonicalize_f32 bit-pattern properties.
Generator codec id migration
crates/echo-wesley-gen/src/main.rs
Codec id constants and IR generation switched from cbor-canon-v1 to le-binary-v1; codec id hardwired into artifact metadata.
Stable op-id pinning and test coverage
crates/echo-wesley-gen/src/main.rs
Relocates pinned FNV-1a stable_op_id implementation; adds unit test asserting bytewise op-id outputs for Mutation/Query operations.
Enum and input object Encode/Decode generation
crates/echo-wesley-gen/src/main.rs
Generates LE binary Encode/Decode impls for enum (u32 discriminants) and input object (field-by-field) types.
Operation vars encoding/decoding migration
crates/echo-wesley-gen/src/main.rs
Refactors per-operation *Vars helpers from Canonical CBOR (encode_cbor, decode_cbor, CanonError) to LE binary (encode_to_vec, decode_from_bytes, CodecError); updates GeneratedIntentError variant and all error handling paths.
LE codec encode/decode helper generators
crates/echo-wesley-gen/src/main.rs
Introduces encode_arg_stmt, decode_arg_expr, encode_field_stmt, decode_field_expr helpers; fixes scalar_list_element_decoder to correctly qualify user-defined types inside generated module scope.

Cross-Boundary Test Fixtures & Generator Integration Tests

Layer / File(s) Summary
Rope schema type definitions and encode/decode helpers
crates/echo-wasm-abi/tests/jedit_rope_cross_boundary.rs
Rust equivalents of rope schema types (AnchorBias, CheckpointKind, CreateBufferWorldlineInput, ReplaceRangeAsTickInput, CreateCheckpointInput) with explicit LE binary encode/decode functions using Writer/Reader.
Rope schema roundtrip and byte-level fixtures
crates/echo-wasm-abi/tests/jedit_rope_cross_boundary.rs
Fixture-style #[test] cases asserting exact byte encodings against expected hex vectors and roundtrip decode correctness; includes offset layout checks for optional author and start_byte/end_byte.
EINT intent encoding byte-level tests
crates/echo-wasm-abi/tests/jedit_rope_cross_boundary_eint.rs
Three unit tests validating pack_intent_v1 returns exact bytewise output matching fixed hex vectors for variable op_id/vars_len combinations.
Generator test codec id and decode updates
crates/echo-wesley-gen/tests/*
Updates fixture and tests to expect le-binary-v1 codec id; switches embedded smoke-test deserialization from decode_cbor to decode_from_bytes for IncrementVars and CounterValueVars.

Design Documentation: LE Codec & Sessions Framework

Layer / File(s) Summary
0024 universal LE binary codec design specification
docs/design/0024-universal-le-binary-codec/design.md
Specifies wire encoding table, required codec.rs/codec.ts primitives, f32 canonicalization, schema-hash prefix gating, TypeScript codec mirror, generated Encode/Decode implementation, cross-language tests, and key risks/unknowns.
0025 sessions as causal contexts design specification
docs/design/0025-sessions-as-causal-contexts/design.md
Defines Session as durable principal-bound causal-context node; specifies lifecycle events, rejection model, runUntilIdle semantics, close behavior (graceful/abortive), system sessions, EINT wire changes (session_id/intent_id headers, IngressAddress routing), core invariants, phase-1 outline, and phase-2 test checklist.
0025 sessions phase-2 handoff and request documentation
docs/design/0025-sessions-as-causal-contexts/phase-2-handoff.md, request.md
Phase-2 handoff records locked binding decisions, pre-RED open questions, RED matrix test targets by domain, and startup workflow; request doc clarifies acceptance criteria and v1 non-goals.
Backlog audit and documentation smell cards
docs/method/backlog/bad-code/*
Documents architectural issues: WARP optics missing umbrella, echo-wesley-gen monolith pain, warp-wasm CBOR/LE inconsistency.
Cool-ideas and graveyard documentation
docs/method/backlog/cool-ideas/*, docs/method/graveyard/*
Proposes schema-version fingerprint prefix, Wesley-emitted JSON fixture vectors for cross-language parity, and retires echo-session-proto split.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • flyingrobots/echo#253: Foundational deterministic codec.rs toolkit (Writer/Reader, Encode/Decode, decode_from_bytes, CodecError) that this PR extends with scalar/container APIs and f32 canonicalization.

Suggested labels

tooling

Poem

🔧 The codec rises, little-endian and clean,
Canonical bits in a deterministic stream—
No more CBOR's encoding spree,
Sessions flow true through SHA256's decree. 🌊

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title accurately summarizes the two major changes: design implementation of 0024 (LE binary codec) and 0025 (sessions), with explicit design-only scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cycle/0025-sessions-as-causal-contexts

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
Copy Markdown

@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.

Reviewed commit: 499ad99133

ℹ️ 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".

Comment thread crates/echo-wesley-gen/src/main.rs
Comment thread crates/echo-wesley-gen/src/main.rs
Comment thread crates/echo-wesley-gen/src/main.rs
Comment thread crates/echo-wasm-abi/src/codec.rs Outdated
@flyingrobots
Copy link
Copy Markdown
Owner Author

Self-Code-Review (Code Rabbit, second pass) — @codex please confirm

Second pedantic pass over the full PR diff vs origin/main. Echo branch was reviewed previously at the cycle level; this pass treats the PR scope as a whole.

Issue count

Severity Count
CRITICAL 0
HIGH 0
MEDIUM 0
MINOR 0
INFO 1

Findings

# File Severity Type Description
I1 crates/echo-wasm-abi/src/codec.rs, crates/echo-wesley-gen/src/main.rs INFO Scope note The 0024 Rust work in this PR was authored on the parent stack/echo-le-binary-codec and predates this conversation. Spot-checked the 13 unwrap() occurrences in codec.rs — all confined to #[test] blocks (idiomatic for Rust tests). No smells surfaced; deferring to existing review history for this code.

Design-packet consistency audit

Ran the stale-term audit from the previous review (grep -RIn "ingress mailbox\|accepted causal lane\|target_worldlines\|writer_ref\|writer_label\|type admits plural\|SessionLane" across the 0025 packet, the 0024 packet, and the graveyard tombstone): zero stale references remain. submission order mentions in design.md are now both in negation context (not raw submission order, not "submission order" in any caller-clock sense).

Cross-references between design.md, request.md, and phase-2-handoff.md are coherent. The retired echo-session-proto-split.md carries a tombstone with a forward pointer to 0025.

Verdict

Echo PR is in good shape. Phase 1 STOP boundary holds — no Rust code, no Wesley IR edits, no API surface changes in the 0025 design packet. The 0024 stack rides this PR per maintainer direction.

@codex — please confirm or push back on any of the above before this lands.

Copy link
Copy Markdown

@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.

Reviewed commit: 499ad99133

ℹ️ 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".

Comment thread crates/echo-wesley-gen/src/main.rs
Comment thread crates/echo-wesley-gen/src/main.rs Outdated
Comment thread crates/echo-wasm-abi/src/codec.rs Outdated
Two security/determinism fixes in echo-wasm-abi codec, both flagged by
Codex P2 on PR #382.

codec.rs read_f32_le:
  Previously returned the raw decoded f32 bit pattern. The writer
  canonicalizes (NaN -> 0x7fc00000, subnormals -> +0.0, -0.0 -> +0.0)
  but the reader did not, so an untrusted EINT or query-var payload
  could submit a non-canonical NaN/subnormal/-0.0 and have it land in
  generated vars verbatim. Two distinct byte strings then represent the
  same intended value, breaking the deterministic-codec contract.

  Wrapped the return in canonicalize_f32 (idempotent on already-canonical
  inputs; honest senders see no behavior change).

codec.rs read_list:
  Previously did Vec::with_capacity(count) before reading any element
  bytes. A malformed payload with u32 count = 0xFFFFFFFF followed by
  zero elements forced a multi-gigabyte pre-allocation (DoS or abort)
  before validation could run.

  Now caps initial_capacity at min(count, remaining_bytes_in_buf). Since
  any list element occupies at least one byte (e.g. a u8 tag), an honest
  count cannot exceed the byte budget; capping at the budget is looser
  than any real workload but still defeats the DoS amplification.

Verified: cargo test -p echo-wasm-abi green (2/2 lib tests).

Resolves PR threads (codex P2)
#382 crates/echo-wasm-abi/src/codec.rs:275
#382 crates/echo-wasm-abi/src/codec.rs:305
…qualification

Five P2 codex findings on echo-wesley-gen + supporting reader helper in
echo-wasm-abi.

  codec.rs: added pub Reader::read_byte_array<const N: usize>() so the
  generator can emit fixed-size array reads for no_std ID fields without
  duplicating take/try_into logic per generated crate.

  main.rs encode_arg_stmt / encode_field_stmt:
    - Nullable list branch was emitting w.write_list(&self.field, ...)
      against an Option<Vec<_>> field. Now wraps in write_option when
      not required.
    - no_std mode maps GraphQL ID to [u8; 32], but emitters always
      treated ID like String. Added 'ID' if args.no_std arms in both
      encode_arg_stmt and encode_field_stmt that emit write_bytes
      (required) or write_option + write_bytes (nullable).

  main.rs decode_arg_expr / decode_field_expr:
    - Nullable list now wraps with read_option + read_list.
    - no_std ID arms emit r.read_byte_array::<32>() (required) or
      r.read_option(|r| r.read_byte_array::<32>()) (nullable).

  main.rs scalar_list_element_decoder:
    - Took a super_qualified: bool parameter. Arg-context callers
      pass true (Vars Decode impls live in __echo_wesley_generated;
      user types need super::). Field-context callers pass false.
      Previously user-defined list element types under Vars compiled
      with bare 'Tag::decode' which the compiler could not resolve.

Resolves PR threads (codex P2)
#382 crates/echo-wesley-gen/src/main.rs:1804
#382 crates/echo-wesley-gen/src/main.rs:1811
#382 crates/echo-wesley-gen/src/main.rs:1882
#382 crates/echo-wesley-gen/src/main.rs:1979
@flyingrobots
Copy link
Copy Markdown
Owner Author

Phase III — Code Lawyer Activity Summary (@codex)

All 7 unresolved review threads on this PR are addressed. Two commits added on top of the existing stack.

Consolidated table

# Source Severity File Commit Outcome
1 codex P2 High crates/echo-wasm-abi/src/codec.rs:275 (canonicalize floats on decode) 74684887 read_f32_le now wraps canonicalize_f32; non-canonical NaN / subnormal / -0.0 inputs cannot enter generated vars from untrusted payloads
2 codex P2 High crates/echo-wasm-abi/src/codec.rs:305 (avoid pre-allocating untrusted list lengths) 74684887 read_list caps Vec::with_capacity at min(count, remaining_bytes); defeats the ff ff ff ff multi-GB pre-allocation DoS
3 codex P2 Medium crates/echo-wesley-gen/src/main.rs:1804 (encode nullable lists as options) 8ef2fc97 encode_arg_stmt list branch now wraps write_list in write_option when !arg.required; Option<Vec<_>> fields type-check
4 codex P2 Medium crates/echo-wesley-gen/src/main.rs:1882 (wrap nullable list input fields as options) 8ef2fc97 Same fix mirrored in encode_field_stmt; nullable list inputs on input-objects compile
5 codex P2 Medium crates/echo-wesley-gen/src/main.rs:1811 (no_std ID byte codecs) 8ef2fc97 Added "ID" if args.no_std arms in both encode helpers (w.write_bytes(...)) and both decode helpers (r.read_byte_array::<32>()); supporting Reader::read_byte_array<const N> added in codec.rs
6 codex P2 Medium crates/echo-wesley-gen/src/main.rs:1979 (qualify user-defined list decoders) 8ef2fc97 scalar_list_element_decoder gained super_qualified: bool; arg-context callers pass true (Vars Decode in __echo_wesley_generated); field-context callers pass false. tags: [Tag!]! under Vars now resolves super::Tag::decode correctly
7 codex P2 Medium nullable list decode counterpart 8ef2fc97 decode_arg_expr + decode_field_expr list branches wrap with `read_option(

Verification

  • cargo build -p echo-wesley-gen: green (2m 53s)
  • cargo check -p echo-wesley-gen --tests: green (6m 18s)
  • cargo test -p echo-wasm-abi: green (2/2 lib tests after codec.rs changes)
  • Pre-commit verify-local (clippy + check) on 8ef2fc97: green (15m 8s)
  • Pre-push verify-local: green (12m 56s, cached on re-push)

Status

All findings resolved. Phase 1 STOP boundary on 0025 design packet still holds — no design content was changed in Phase III; only the 0024-stack Rust code that codex flagged was touched.

@codex — please confirm the codec hardening, the read_byte_array addition, and the four wesley-gen emit-path fixes meet the bar before merge.

Copy link
Copy Markdown

@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.

Reviewed commit: 8ef2fc9731

ℹ️ 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".

Comment thread crates/echo-wesley-gen/src/main.rs
Copy link
Copy Markdown
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: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/echo-wasm-abi/src/codec.rs`:
- Around line 57-64: Add a unit test that asserts decode_from_bytes returns
Err(CodecError::Trailing) when a valid encoded payload is followed by an extra
byte: create a valid encoded byte vector for a simple Decode type (e.g., a
primitive or a small struct used elsewhere), append one extra byte, call
decode_from_bytes::<T>(&bytes) and assert it yields Err(CodecError::Trailing);
place the test in this module's #[cfg(test)] tests so the behavior is locked in.

In `@crates/echo-wasm-abi/tests/jedit_rope_cross_boundary.rs`:
- Around line 299-372: The tests currently only roundtrip via the Rust
encoder/decoder (replace_range_as_tick_vars / decode_replace_range_as_tick_input
and encode_create_checkpoint_vars / decode_create_checkpoint_input), which won't
catch drift versus the TypeScript wire contract; replace or augment these tests
by pinning fixed expected byte vectors (literal u8 arrays) for
replace_range_as_tick and create_checkpoint ops (like the existing
create_buffer_worldline test does), assert that
encode_replace_range_as_tick_vars(&input) and
encode_create_checkpoint_vars(&input) produce exactly those literals, and also
assert that decode_* still parses those literals back to the original structs so
both encoder and decoder are validated against a stable wire-format golden
vector.

In `@crates/echo-wesley-gen/src/main.rs`:
- Around line 179-194: The helper fnv1a_step and the stable_op_id implementation
currently perform FNV-1 (multiply then xor) while the comment and name claim
FNV-1a; update the code to make the contract explicit and consistent: either
rename fnv1a_step (and update the doc comment on stable_op_id) to reflect FNV-1,
or change fnv1a_step to implement true FNV-1a (xor the byte into hash first,
then multiply) and update any pinned test vectors accordingly; ensure you modify
the symbol fnv1a_step and the doc comment on stable_op_id so the function name,
implementation, and comment all match the chosen algorithm.
- Around line 159-160: The IR's codec_id must be normalized to the canonical
value before any artifact preimage or hashes are computed: update the generator
to set ir.codec_id (currently set at codec_id: Some("le-binary-v1".to_string()))
immediately after parsing/constructing the IR so that
generated_rust_artifact_hash(), observer_identity_hashes(), and
op_footprint_certificate() all see the normalized codec (not the raw JSON input
like "cbor-canon-v1"); in practice, normalize or overwrite the incoming codec_id
to the canonical "le-binary-v1" right after IR construction and before any calls
to generated_rust_artifact_hash(), observer_identity_hashes(), or
op_footprint_certificate() so hashes and certificates are computed consistently.
- Around line 2011-2048: The scalar list element helpers treat "ID" like String
but map_type/map_helper_type map no-std ID to [u8; 32], causing mismatched
codegen; update scalar_list_element_encoder and scalar_list_element_decoder to
branch on args (Args) for "ID" so that in no-std mode they emit
encoders/decoders for a fixed 32-byte array instead of String/str (use the same
no-std predicate used elsewhere), while leaving the String/ID-as-String behavior
for std mode; reference scalar_list_element_encoder,
scalar_list_element_decoder, the type_name "ID", the Args parameter and
safe_ident to locate where to change the match arms and ensure encoders
write/read fixed 32 bytes and decoders produce/consume [u8; 32] consistent with
map_type/map_helper_type.
- Around line 307-321: Add a module-level import so the generated modules can
resolve the Encode/Decode trait methods: in the top of the main generated module
and inside the __echo_wesley_generated module, bring
echo_wasm_abi::codec::Encode and echo_wasm_abi::codec::Decode into scope (import
them as underscore aliases) so impls like Encode for `#name` and nested calls like
v.encode(w) / v.decode(r) compile; update the module headers where the generated
impls (impl echo_wasm_abi::codec::Encode for `#name` and impl
echo_wasm_abi::codec::Decode for `#name`) are emitted to include this import.

In `@crates/echo-wesley-gen/tests/generation.rs`:
- Line 1408: The test is asserting pub const CODEC_ID == "le-binary-v1" but the
inline IR fixture still declares "cbor-canon-v1", so update the inline IR in
this test (and other inline IR snippets in generation.rs) to set codec_id =
"le-binary-v1" to match the expected wire contract, or alternatively make the
test fail on stale ids by asserting equality from the parsed IR rather than
accepting mismatches; locate the failing assertion assert!(stdout.contains("pub
const CODEC_ID: &str = \"le-binary-v1\"")) and the surrounding inline IR
string(s) in generation.rs and replace any "cbor-canon-v1" occurrences with
"le-binary-v1".

In `@docs/design/0024-universal-le-binary-codec/design.md`:
- Around line 84-86: Update the doc to remove or correct the claim that enums
are append-only and "Adding a new variant at the end is safe": state that enum
changes (including appending variants) are breaking for mixed-version peers
because the framing explicitly gates payloads by SCHEMA_SHA256, so any schema
change will cause rejection; replace the "Enum discriminant" paragraph with text
that explains enum discriminants are deterministic and ordered by SDL
declaration order but that all schema edits (reorder, insert, append) change
SCHEMA_SHA256 and are therefore incompatible with peers using a different schema
version, and reference SCHEMA_SHA256 and the framing/version-gate behavior to
make the incompatibility precise.

In `@docs/method/backlog/bad-code/DOCS_no-published-umbrella-for-warp-optics.md`:
- Around line 118-119: The document uses two variants for the same project name
("WARP DRIVE" vs "WARPDrive"); pick one canonical form (e.g., "WARPDrive") and
replace the mismatched occurrence at the diff fragment ("Before WARP DRIVE goes
from vapor to v0.0.1 — the umbrella story...") so it matches the canonical name,
and scan the rest of the document to normalise all instances to that single
canonical term.

In `@docs/method/backlog/cool-ideas/PLATFORM_wesley-emitted-fixture-vectors.md`:
- Around line 39-40: The markdown list contains a stale repo-root path
`echo/crates/echo-wasm-abi/tests/jedit_rope_cross_boundary.rs`; update that
entry to use the correct repo-root style (e.g.,
`crates/echo-wasm-abi/tests/jedit_rope_cross_boundary.rs`) so cross-references
like the test file name `jedit_rope_cross_boundary.rs` resolve consistently with
other paths in the document.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f78542fa-09eb-4c07-a93f-4ef7c7ccd0ae

📥 Commits

Reviewing files that changed from the base of the PR and between b8b430a and 8ef2fc9.

📒 Files selected for processing (16)
  • crates/echo-wasm-abi/src/codec.rs
  • crates/echo-wasm-abi/tests/jedit_rope_cross_boundary.rs
  • crates/echo-wasm-abi/tests/jedit_rope_cross_boundary_eint.rs
  • crates/echo-wesley-gen/src/main.rs
  • crates/echo-wesley-gen/tests/fixtures/toy-counter/echo-ir-v1.json
  • crates/echo-wesley-gen/tests/generation.rs
  • docs/design/0024-universal-le-binary-codec/design.md
  • docs/design/0025-sessions-as-causal-contexts/design.md
  • docs/design/0025-sessions-as-causal-contexts/phase-2-handoff.md
  • docs/design/0025-sessions-as-causal-contexts/request.md
  • docs/method/backlog/bad-code/DOCS_no-published-umbrella-for-warp-optics.md
  • docs/method/backlog/bad-code/PLATFORM_echo-wesley-gen-monolith.md
  • docs/method/backlog/bad-code/PLATFORM_warp-wasm-cbor-debt.md
  • docs/method/backlog/cool-ideas/PLATFORM_schema-version-fingerprint-prefix.md
  • docs/method/backlog/cool-ideas/PLATFORM_wesley-emitted-fixture-vectors.md
  • docs/method/graveyard/PLATFORM_echo-session-proto-split.md

Comment thread crates/echo-wasm-abi/src/codec.rs
Comment thread crates/echo-wasm-abi/tests/jedit_rope_cross_boundary.rs
Comment thread crates/echo-wesley-gen/src/main.rs Outdated
Comment thread crates/echo-wesley-gen/src/main.rs Outdated
Comment thread crates/echo-wesley-gen/src/main.rs
Comment thread crates/echo-wesley-gen/src/main.rs Outdated
Comment thread crates/echo-wesley-gen/tests/generation.rs
Comment thread docs/design/0024-universal-le-binary-codec/design.md Outdated
Comment thread docs/method/backlog/bad-code/DOCS_no-published-umbrella-for-warp-optics.md Outdated
Comment thread docs/method/backlog/cool-ideas/PLATFORM_wesley-emitted-fixture-vectors.md Outdated
…c, docs)

Code Lawyer pass on the 11 unresolved review threads on PR #382.

wesley-gen list element no_std ID handling (codex P2 / coderabbit Critical):
  scalar_list_element_encoder/_decoder used to treat ID as String
  unconditionally, so under --no-std a [ID] field generated v.as_str()
  on [u8; 32] (encode) and read_string -> Vec<[u8; 32]> (decode),
  neither of which compile. Both helpers now thread args through, gate
  on id_is_bytes = args.no_std && type_name == "ID", and emit
  write_bytes / read_byte_array::<32> arms matching the scalar-helper
  fix from 8ef2fc9. New consumer-crate compile regression test pins
  this in test_no_std_id_list_field_compiles_in_consumer_crate.

wesley-gen codec trait imports inside generated modules (coderabbit Critical):
  Generated Encode/Decode impls call .encode(w) / Type::decode(r) on
  nested user types via method/associated-fn syntax. Bringing
  echo_wasm_abi::codec::{Encode, Decode} into scope at the top of the
  generated module AND inside __echo_wesley_generated removes a
  trait-resolution dependency on the implementing impl block at every
  call site.

wesley-gen ir.codec_id normalization (coderabbit Major):
  Generator advertised CODEC_ID = "le-binary-v1" but artifact hash,
  observer identity, and footprint certificate preimages read
  ir.codec_id directly, so an IR declaring "cbor-canon-v1" produced
  an artifact whose hash was derived under the old codec while
  claiming the new one. ir.codec_id is now normalized to
  DEFAULT_CODEC_ID immediately after parsing.

wesley-gen test fixtures: cbor-canon-v1 -> le-binary-v1 (coderabbit Major):
  All eight inline IR snippets in tests/generation.rs updated so the
  fixtures prove the new wire contract rather than relying on silent
  metadata rewriting.

wesley-gen fnv1_step rename (coderabbit Minor):
  fnv1a_step multiplies before xor (FNV-1) while name/doc claimed
  FNV-1a. Renamed helper, updated doc to call out the misnomer, noted
  that stable_op_id_pinned vectors lock the contract to this FNV-1
  ordering. No behavioral change.

wasm-abi pinned wire vectors for rope ops (coderabbit Major):
  replace_range_as_tick and create_checkpoint only had local
  roundtrips; encoder/decoder drift could co-mutate silently. Added
  four pinned literal-byte fixtures covering minimal + with-author
  for replace_range_as_tick and manual-save-with-label + auto-save-
  no-label for create_checkpoint. Each both encodes -> matches the
  literal AND decodes the literal back to the original struct.

wasm-abi CodecError::Trailing regression tests (coderabbit Trivial):
  Locked the public decode_from_bytes contract with three tests using
  a tiny OneInt(i32) Decode shape: exact-payload-accepted, one-
  trailing-byte-rejected, many-trailing-bytes-rejected.

Doc threads:
  - 0024-universal-le-binary-codec/design.md: removed the "Adding a
    new variant at the end is safe" enum-compatibility claim; framed
    declaration-order rule as a same-version determinism guarantee
    consistent with the SCHEMA_SHA256 hard-gate.
  - DOCS_no-published-umbrella-for-warp-optics.md: canonicalized
    "WARP DRIVE" -> "WARPDrive".
  - PLATFORM_wesley-emitted-fixture-vectors.md: fixed stale repo-root
    path locator.

Backlog (cool ideas):
  - PLATFORM_wesley-gen-test-loop-speedup.md: documents the iteration-
    cost sources observed during this review pass (60-120s per
    integration test, 4m53s pre-commit) and proposes shared target-
    dir for generated consumer crates, pre-built wesley-gen binary
    in tests, and crate-scoped pre-commit cargo check.

Verified: echo-wasm-abi --lib 80/80 (incl. new Trailing tests),
echo-wasm-abi --test jedit_rope_cross_boundary 16/16 (incl. four new
pinned-byte tests), echo-wesley-gen --bins 1/1 (stable_op_id_pinned),
and five targeted wesley-gen integration tests pass.

Resolves PR #382 review threads:
#382
@flyingrobots flyingrobots merged commit 781f97b into main May 30, 2026
36 checks passed
@flyingrobots flyingrobots deleted the cycle/0025-sessions-as-causal-contexts branch May 30, 2026 18:29
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.

1 participant