Skip to content

Comments

feat: add SignedContextOracleV1 metadata type#92

Open
hardyjosh wants to merge 4 commits intomainfrom
feat/signed-context-oracle-meta
Open

feat: add SignedContextOracleV1 metadata type#92
hardyjosh wants to merge 4 commits intomainfrom
feat/signed-context-oracle-meta

Conversation

@hardyjosh
Copy link
Contributor

@hardyjosh hardyjosh commented Feb 13, 2026

Motivation

Rain orders can consume SignedContextV1 data passed by takers, but there is no standard way for an order to advertise where takers should fetch that data. This metadata type solves the discovery problem.

Solution

Registers a new KnownMagic::SignedContextOracleV1 (0xff7a1507ba4419ca) for order metadata. The payload is a single CBOR text string containing the oracle endpoint URL.

  • KnownMagic::SignedContextOracleV1 added to magic enum + TryFrom
  • KnownMeta::SignedContextOracleV1 variant added
  • signed_context_oracle module with SignedContextOracleV1 struct:
    • new(url) / url() — construct and read
    • to_meta_item() — encode as RainMetaDocumentV1Item
    • cbor_encode() — encode as complete Rain meta document
    • find_in_items() — extract from decoded meta items
    • TryFrom<RainMetaDocumentV1Item> — decode from meta item
  • 7 tests covering magic roundtrip, encode/decode, find

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

Summary by CodeRabbit

  • New Features

    • Added Raindex Signed Context Oracle metadata type with URL-based oracle configuration.
    • Metadata conversions updated to recognize the new oracle type across workflows.
    • URL validation, parsing, and serialization to Rain metadata added.
  • Bug Fixes / Errors

    • Added InvalidUrl error for malformed URL handling.
  • Tests

    • Added tests for encoding/decoding, round-trip conversions, item lookup, and URL parsing edge cases.

New metadata type for signed context oracle endpoint discovery.

- Register KnownMagic::SignedContextOracleV1 (0xff7a1507ba4419ca)
- Add KnownMeta::SignedContextOracleV1 variant
- Add signed_context_oracle module with encode/decode/find helpers
- Payload is a simple URL string (CBOR text) identifying a GET endpoint
  that returns SignedContextV1 data for Rain order evaluation
- 7 new tests (magic roundtrip + oracle encode/decode/find)
@coderabbitai
Copy link

coderabbitai bot commented Feb 13, 2026

Walkthrough

Adds a new RaindexSignedContextOracleV1 metadata type: magic constant, enum variants across meta modules, module export, URL-validated type with (de)serialization and item lookup, and a new InvalidUrl error variant plus unit tests.

Changes

Cohort / File(s) Summary
Magic & Meta enums
crates/cli/src/meta/magic.rs, crates/cli/src/meta/mod.rs
Added RaindexSignedContextOracleV1 to KnownMagic (value 0xff7a1507ba4419ca) and KnownMeta; updated TryFrom<u64> and mapping from KnownMagic to KnownMeta; extended RainMetaDocumentV1Item::unpack_into to recognize the new magic.
New meta type implementation
crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs
New RaindexSignedContextOracleV1(pub String) type with URL parsing/validation, accessors, TryFrom<RainMetaDocumentV1Item>, to_meta_item(), cbor_encode(), find_in_items(), wasm bindings, and comprehensive unit tests for round-trip, lookup, and error cases.
Module exposure
crates/cli/src/meta/types/mod.rs
Exported new raindex_signed_context_oracle module (pub mod raindex_signed_context_oracle;).
Error handling
crates/cli/src/error/mod.rs
Added InvalidUrl(String) variant to Error enum and its Display formatting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • findolor
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add SignedContextOracleV1 metadata type' clearly and concisely summarizes the main change: adding a new metadata type for signed context oracle functionality.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/signed-context-oracle-meta

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

@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: 3

🤖 Fix all issues with AI agents
In `@crates/cli/src/meta/types/signed_context_oracle/mod.rs`:
- Around line 36-45: Update the doc comment for
KnownMagic::SignedContextOracleV1 to state the payload is a raw UTF-8 string
(not a CBOR text string); the surrounding implementation (SignedContextOracleV1
handling in to_meta_item and the TryFrom that uses String::from_utf8)
encodes/decodes raw UTF-8 bytes, so change the comment in magic.rs to "raw UTF-8
string" to match the behavior.
- Around line 25-29: SignedContextOracleV1::new currently accepts any String
(including empty) which is invalid for a GET endpoint; update new to validate
the URL (e.g., check !url.trim().is_empty()) and reject empty values instead of
silently accepting them: either change the signature to return
Result<SignedContextOracleV1, YourErrorType> and return an Err when the URL is
empty, or keep the constructor but add a clear panic/assert with a descriptive
message; ensure you reference SignedContextOracleV1::new and the URL parameter
when implementing the check and choose an existing error type (or create a small
one) for the Result variant.
- Around line 65-74: The TryFrom implementation for SignedContextOracleV1
currently returns Error::UnsupportedMeta when the RainMetaDocumentV1Item magic
mismatches; change this to return Error::InvalidMetaMagic(expected, actual) to
match peer implementations (e.g., DotrainGuiStateV1, DotrainSourceV1). In the
TryFrom<RainMetaDocumentV1Item> for SignedContextOracleV1 function, replace the
early-return Err(Error::UnsupportedMeta) with
Err(Error::InvalidMetaMagic(KnownMagic::SignedContextOracleV1, value.magic)) so
the error reports both the expected KnownMagic (SignedContextOracleV1) and the
actual value.

Comment on lines 65 to 74
impl TryFrom<RainMetaDocumentV1Item> for SignedContextOracleV1 {
type Error = Error;
fn try_from(value: RainMetaDocumentV1Item) -> Result<Self, Self::Error> {
if !matches!(value.magic, KnownMagic::SignedContextOracleV1) {
return Err(Error::UnsupportedMeta);
}
let bytes = value.unpack()?;
let url = String::from_utf8(bytes)?;
Ok(Self(url))
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find the Error enum definition and InvalidMetaMagic variant
rg -n 'enum Error|InvalidMetaMagic' --type rust | head -30

Repository: rainlanguage/rain.metadata

Length of output: 1152


🏁 Script executed:

# Check the DotrainGuiStateV1 TryFrom implementation
rg -B5 -A10 'impl TryFrom<RainMetaDocumentV1Item> for DotrainGuiStateV1' --type rust

Repository: rainlanguage/rain.metadata

Length of output: 1336


🏁 Script executed:

# Check the DotrainSourceV1 TryFrom implementation
rg -B5 -A10 'impl TryFrom<RainMetaDocumentV1Item> for DotrainSourceV1' --type rust

Repository: rainlanguage/rain.metadata

Length of output: 1349


🏁 Script executed:

# Check all TryFrom implementations for RainMetaDocumentV1Item to see error handling patterns
rg -B2 -A8 'impl TryFrom<RainMetaDocumentV1Item>' --type rust

Repository: rainlanguage/rain.metadata

Length of output: 8562


Use Error::InvalidMetaMagic for consistency with peer implementations.

Other TryFrom<RainMetaDocumentV1Item> implementations in this codebase (DotrainGuiStateV1 and DotrainSourceV1) return Error::InvalidMetaMagic(expected, actual) on magic mismatch, providing diagnostic context about which magic value was expected versus received. This implementation returns the less informative Error::UnsupportedMeta.

♻️ Proposed fix
     fn try_from(value: RainMetaDocumentV1Item) -> Result<Self, Self::Error> {
-        if !matches!(value.magic, KnownMagic::SignedContextOracleV1) {
-            return Err(Error::UnsupportedMeta);
+        if value.magic != KnownMagic::SignedContextOracleV1 {
+            return Err(Error::InvalidMetaMagic(
+                KnownMagic::SignedContextOracleV1,
+                value.magic,
+            ));
         }
📝 Committable suggestion

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

Suggested change
impl TryFrom<RainMetaDocumentV1Item> for SignedContextOracleV1 {
type Error = Error;
fn try_from(value: RainMetaDocumentV1Item) -> Result<Self, Self::Error> {
if !matches!(value.magic, KnownMagic::SignedContextOracleV1) {
return Err(Error::UnsupportedMeta);
}
let bytes = value.unpack()?;
let url = String::from_utf8(bytes)?;
Ok(Self(url))
}
impl TryFrom<RainMetaDocumentV1Item> for SignedContextOracleV1 {
type Error = Error;
fn try_from(value: RainMetaDocumentV1Item) -> Result<Self, Self::Error> {
if value.magic != KnownMagic::SignedContextOracleV1 {
return Err(Error::InvalidMetaMagic(
KnownMagic::SignedContextOracleV1,
value.magic,
));
}
let bytes = value.unpack()?;
let url = String::from_utf8(bytes)?;
Ok(Self(url))
}
}
🤖 Prompt for AI Agents
In `@crates/cli/src/meta/types/signed_context_oracle/mod.rs` around lines 65 - 74,
The TryFrom implementation for SignedContextOracleV1 currently returns
Error::UnsupportedMeta when the RainMetaDocumentV1Item magic mismatches; change
this to return Error::InvalidMetaMagic(expected, actual) to match peer
implementations (e.g., DotrainGuiStateV1, DotrainSourceV1). In the
TryFrom<RainMetaDocumentV1Item> for SignedContextOracleV1 function, replace the
early-return Err(Error::UnsupportedMeta) with
Err(Error::InvalidMetaMagic(KnownMagic::SignedContextOracleV1, value.magic)) so
the error reports both the expected KnownMagic (SignedContextOracleV1) and the
actual value.

@hardyjosh hardyjosh requested a review from findolor February 13, 2026 17:19
@hardyjosh hardyjosh self-assigned this Feb 13, 2026
@hardyjosh hardyjosh requested a review from 0xgleb February 13, 2026 17:19
items
.iter()
.find(|item| matches!(item.magic, KnownMagic::SignedContextOracleV1))
.and_then(|item| Self::try_from(item.clone()).ok())
Copy link
Contributor

Choose a reason for hiding this comment

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

might be better to return an error if we find the magic but can't decode the item. None makes sense if the magic wasn't found

- Validate URL on construction using url::Url (Gleb's suggestion)
  - new() takes Url, parse() takes &str and validates
  - Invalid/empty URLs are rejected with Error::InvalidUrl
- find_in_items() now returns Result<Option<Self>, Error> (Gleb's suggestion)
  - Returns Err if magic found but decode fails
  - Returns Ok(None) only if magic not found
- Fix doc comment: payload is raw UTF-8 bytes, not CBOR text string
- Added Error::InvalidUrl variant
- 10 tests (up from 7): added tests for URL validation, empty URL,
  decode error propagation, parsed_url accessor
The metadata type is specific to the Raindex calculateOrderIO entrypoint,
not a generic oracle standard. Rename to reflect this.
Copy link

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs`:
- Around line 46-48: The parsed_url() method exists only because the newtype
stores a String; change the inner type from String to url::Url so URL parsing
happens at construction and parsed_url() can become a simple infallible accessor
returning &Url (or expose the inner Url directly). Update the newtype definition
(the tuple struct holding self.0), constructors/parsers that currently accept
strings to parse into Url at creation, and replace calls to parsed_url() with
the new accessor to remove the needless Result handling.
- Line 21: The struct RaindexSignedContextOracleV1 currently exposes its inner
String as pub which allows callers to construct invalid instances and break the
URL validation invariant; make the inner field private (remove pub) so instances
can only be created through the validated constructors (new() and parse()),
update any call sites to use those constructors, and if deserialization/wasm
needs require construction add a custom serde::Deserialize impl or use
#[serde(try_from = "String")] that calls Url::parse (or wrap Url directly) so
parsed_url() can never fail at runtime.

/// directly to `SignedContextV1`.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(target_family = "wasm", derive(Tsify))]
pub struct RaindexSignedContextOracleV1(pub String);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

The pub inner field breaks the URL validation invariant.

new() and parse() ensure only valid URLs are stored, but pub String lets callers bypass this entirely:

// Compiles fine, no validation
let bad = RaindexSignedContextOracleV1("not a url".into());

This also means parsed_url() can unexpectedly fail on an instance that was "successfully" constructed.

Make the field private to enforce the invariant:

Proposed fix
-pub struct RaindexSignedContextOracleV1(pub String);
+pub struct RaindexSignedContextOracleV1(String);

If WASM/serde deserialization needs to construct this type, add a custom Deserialize impl (or a #[serde(try_from = "String")]) that validates via Url::parse. Based on learnings, the url crate is already a dependency and Url provides validation, type safety, and serde support — consider wrapping Url directly if Tsify/WASM constraints allow it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs` at line 21,
The struct RaindexSignedContextOracleV1 currently exposes its inner String as
pub which allows callers to construct invalid instances and break the URL
validation invariant; make the inner field private (remove pub) so instances can
only be created through the validated constructors (new() and parse()), update
any call sites to use those constructors, and if deserialization/wasm needs
require construction add a custom serde::Deserialize impl or use
#[serde(try_from = "String")] that calls Url::parse (or wrap Url directly) so
parsed_url() can never fail at runtime.

Comment on lines +46 to +48
pub fn parsed_url(&self) -> Result<Url, Error> {
Url::parse(&self.0).map_err(|e| Error::InvalidUrl(e.to_string()))
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

parsed_url() would be unnecessary if Url were stored directly.

If you keep String internally, this method is fine but its fallibility is misleading when the struct is properly constructed. If you switch the inner type to url::Url, this becomes a simple accessor and cannot fail. Based on learnings, in the rain.metadata crate, prefer wrapping url::Url instead of String for types that represent URLs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs` around lines
46 - 48, The parsed_url() method exists only because the newtype stores a
String; change the inner type from String to url::Url so URL parsing happens at
construction and parsed_url() can become a simple infallible accessor returning
&Url (or expose the inner Url directly). Update the newtype definition (the
tuple struct holding self.0), constructors/parsers that currently accept strings
to parse into Url at creation, and replace calls to parsed_url() with the new
accessor to remove the needless Result handling.

Copy link

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs`:
- Around line 63-68: The function cbor_encode unnecessarily allocates a Vec for
a single element; change the argument to RainMetaDocumentV1Item::cbor_encode_seq
to use a stack-allocated single-element array slice instead of &vec![...]. In
other words, replace the &vec![self.to_meta_item()] allocation with a reference
to a single-element array slice (e.g., &[self.to_meta_item()]) when calling
RainMetaDocumentV1Item::cbor_encode_seq with KnownMagic::RainMetaDocumentV1
inside the cbor_encode method.

---

Duplicate comments:
In `@crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs`:
- Around line 19-21: RaindexSignedContextOracleV1 currently exposes a pub String
which bypasses URL validation and allows Deserialize to create invalid
instances; change the inner type to a validated wrapper (preferably url::Url or
a new private struct holding Url) instead of pub String, implement/display a
getter if needed, and add a custom Deserialize (or #[serde(try_from = "String")]
impl) that runs Url::parse and returns an error on failure so deserialization
and direct construction both enforce validity; update or remove parsed_url()
accordingly and ensure Tsify/WASM compatibility if keeping Url by using an
intermediate String conversion for the WASM build.
- Around line 45-48: parsed_url currently returns Result<Url, Error> but the
inner String is guaranteed valid at construction, so change parsed_url to be
infallible: update its signature to pub fn parsed_url(&self) -> Url and return
the parsed Url directly (e.g.
Url::parse(&self.0).expect("RaindexSignedContextOracle invariant: stored URL is
valid")) or, better, return a cloned Url if you change the inner type later;
reference the parsed_url method in this module and remove the map_err branch and
Result usage.

Comment on lines +63 to +68
pub fn cbor_encode(&self) -> Result<Vec<u8>, Error> {
RainMetaDocumentV1Item::cbor_encode_seq(
&vec![self.to_meta_item()],
KnownMagic::RainMetaDocumentV1,
)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Unnecessary heap allocation in cbor_encode — prefer a stack-allocated slice.

&vec![self.to_meta_item()] allocates a Vec just to pass a single-element slice. Use an array reference instead.

♻️ Proposed fix
-        RainMetaDocumentV1Item::cbor_encode_seq(
-            &vec![self.to_meta_item()],
-            KnownMagic::RainMetaDocumentV1,
-        )
+        RainMetaDocumentV1Item::cbor_encode_seq(
+            &[self.to_meta_item()],
+            KnownMagic::RainMetaDocumentV1,
+        )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs` around lines
63 - 68, The function cbor_encode unnecessarily allocates a Vec for a single
element; change the argument to RainMetaDocumentV1Item::cbor_encode_seq to use a
stack-allocated single-element array slice instead of &vec![...]. In other
words, replace the &vec![self.to_meta_item()] allocation with a reference to a
single-element array slice (e.g., &[self.to_meta_item()]) when calling
RainMetaDocumentV1Item::cbor_encode_seq with KnownMagic::RainMetaDocumentV1
inside the cbor_encode method.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants