Skip to content

Give the crate a document level cbor decoder for the spec's MUST-discard rule - #278

Open
thedavidmeister wants to merge 1 commit into
mainfrom
2026-08-25-issue-203
Open

Give the crate a document level cbor decoder for the spec's MUST-discard rule#278
thedavidmeister wants to merge 1 commit into
mainfrom
2026-08-25-issue-203

Conversation

@thedavidmeister

Copy link
Copy Markdown
Contributor

Closes #203

The decision the issue asks for

cbor_decode is an item/sequence level decoder whose document prefix is
optional by design. Three things in the tree say so, none of them accidental:

  • hash(false) — the metaboard subject for an individual meta — is
    keccak256 over the bare cbor map, and Store::set_dotrain keys its
    cache by exactly those bytes. They carry no prefix and have to decode.
  • cbor_encode (bare item) and cbor_encode_seq (prefix + items) are both
    public, and cbor_decode is the only decoder: it is the inverse of both.
  • Committed roundtrips decode bare cbor_encode output directly —
    authoring_meta_roundtrip, dotrain_meta_roundtrip,
    oa_schema_map_key_roundtrip, no_schema_key_encodes_as_before_roundtrip.

So the issue's first branch — make cbor_decode reject unprefixed input — is
not taken. It would break all three, on a published API, to enforce a rule the
function is not the right place for.

The gap that was real

The spec's MUST ("Tooling that wishes to read meta MUST discard/ignore all
binary data that does not begin with the magic number") is a document level
rule, and the crate gave callers no way to obey it. The solidity half of this
same repo does have it — LibMeta.isRainMetaV1 / checkMetaUnhashedV1 — so the
two halves disagreed about whether unprefixed bytes are meta at all.

Store::store_content was the evidence: it called cbor_decode, then
re-checked bytes.starts_with(RainMetaDocumentV1) itself before caching
anything, because the decoder had thrown away the one fact it needed.

The fix

RainMetaDocumentV1Item::cbor_decode_document — the document level decoder.
Error::NotRainMetaDocumentV1 unless the data begins with the document magic
number, then the existing sequence decode. It is the counterpart of
LibMeta.checkMetaUnhashedV1 and the inverse of cbor_encode_seq under that
magic.

store_content calls it and drops its hand-rolled prefix re-check: same
condition, one place. No behaviour change there.

cbor_decode itself is untouched. Its contract is now stated on the function
and pinned by a test, instead of being re-derived by every reader from the
starts_with branch — which is what the issue asked for on this branch.

Relation to the other cbor_decode / KnownMagic work in flight

QA

  • Discriminating tests (all new, crates/cli/src/meta/mod.rs):
    test_cbor_decode_document_requires_the_document_prefix,
    test_cbor_decode_document_rejects_other_magic_prefix,
    test_cbor_decode_document_rejects_data_shorter_than_the_prefix. Each fails
    on base by construction — base has no such function. The behaviour they pin
    is a real distinction, not just a new name: the first asserts both sides,
    that cbor_decode still accepts the bare map (base behaviour deliberately
    kept) and that cbor_decode_document rejects the same bytes. The third
    covers the < 8 bytes case that solidity isRainMetaV1 opens with.
    The pre-existing test_store_update_with_validation_and_content already
    pinned both store_content branches (prefixed document caches inner items,
    bare sequence does not); it stays green untouched, which is the evidence that
    the store_content rewrite changed nothing.
  • Mutations applied — each applied to the post-fix tree,
    cargo test -p rain-metadata --lib meta::tests:: run, then reverted:
    • if !data.starts_with(...) -> if false (never reject) -> 4 failed:
      the three new tests plus test_store_update_with_validation_and_content.
    • drop the ! (reject exactly the documents) -> 5 failed, adding
      test_store_update_and_update_check.
    • KnownMagic::RainMetaDocumentV1 -> KnownMagic::DotrainV1 in the check
      -> 4 failed.
    • store_content: cbor_decode_document -> cbor_decode (restores the base
      decode, drops the reinstated guard) -> 1 failed,
      test_store_update_with_validation_and_content.
    • Baseline restored and re-run: 53 passed, 0 failed. No surviving mutant.
  • Oracle: the metadata-v1 spec text quoted in the issue, and this repo's own
    src/lib/LibMeta.sol (isRainMetaV1's length guard and magic equality,
    checkMetaUnhashedV1's revert) — not the behaviour of cbor_decode, which is
    the code under test.
  • Category check: the issue poses one question with two branches. Branch
    (b) is taken, with the evidence above. The remedy it names for (b) — say that
    the prefix is optional — is on cbor_decode; the spec MUST that branch (b)
    otherwise leaves unserved is now reachable as cbor_decode_document.
  • Error::NotRainMetaDocumentV1 is a new variant on the public Error enum;
    its Display string is pinned in test_display_fixed_strings alongside the
    others.

Verification

Green locally: cargo test -p rain-metadata --lib meta::tests:: 53 passed,
cargo test -p rain-metadata --lib error:: 6 passed,
cargo clippy --workspace --all-targets clean, cargo fmt --check --all clean.
The full suite was not run locally (many sibling agents share this machine); CI
runs it.

🤖 Generated with Claude Code

`cbor_decode` treats the rain meta document magic number as an optional
prefix, which is the contract the bare item bytes that `hash(false)`
identifies a meta by depend on. The metadata-v1 spec's rule that tooling
MUST discard data not beginning with that magic number is a document
level rule, and the crate had no way to express it: `Store::store_content`
re-checked the prefix itself after decoding, because the decoder dropped
the one fact it needed.

`cbor_decode_document` is that rule, matching solidity
`LibMeta.checkMetaUnhashedV1` in the same repo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 58 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 40a360a5-111e-4342-8611-c359fca1de54

📥 Commits

Reviewing files that changed from the base of the PR and between 45ca96c and f38e16d.

📒 Files selected for processing (2)
  • crates/cli/src/error/mod.rs
  • crates/cli/src/meta/mod.rs

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.

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.

cbor_decode accepts input without the rain meta document prefix; spec says tooling MUST discard data not beginning with the magic number

1 participant