Skip to content

feat: add SignedContextOracleV1 metadata type#92

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

feat: add SignedContextOracleV1 metadata type#92
hardyjosh wants to merge 3 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 supporting URL-based oracle configuration storage and retrieval.
    • Implemented URL validation, parsing, and serialization capabilities for oracle metadata in Rain format.
    • Added InvalidUrl error handling for invalid URL configurations.

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

This PR introduces a new metadata type for Raindex Signed Context Oracle V1, adding magic number recognition, enum variants across meta modules, URL validation and serialization utilities, and extending error handling for URL validation failures.

Changes

Cohort / File(s) Summary
Magic and Meta Type Infrastructure
crates/cli/src/meta/magic.rs, crates/cli/src/meta/mod.rs
Added RaindexSignedContextOracleV1 variant to KnownMagic enum with magic number 0xff7a1507ba4419ca and TryFrom<u64> support; extended KnownMeta enum with corresponding variant and conversion logic; updated RainMetaDocumentV1Item::unpack_into to handle new variant.
Type Implementation
crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs
New module implementing RaindexSignedContextOracleV1 struct with URL storage, validation via parse() method, serialization to Rain metadata format via to_meta_item() and cbor_encode(), extraction via find_in_items(), and TryFrom conversion from metadata items; includes comprehensive unit tests for round-trip encoding/decoding and error cases.
Error Handling
crates/cli/src/error/mod.rs
Added InvalidUrl(String) variant to Error enum for URL validation failures with corresponding Display formatting.
Module Exposure
crates/cli/src/meta/types/mod.rs
Exposed new raindex_signed_context_oracle public module.

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' accurately describes the main objective of the PR, which is to introduce a new metadata type for advertising signed context oracle endpoints.
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
🧪 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
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
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.

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

Comments