Documentation / Core contracts

Resource discovery

Authorized descriptors and bounded projections.

ROM 0.1.0 · SOURCE CANDIDATE Markdown

Runtime::discover(&actor).await returns metadata that the accepted Resource definitions explicitly allow that actor to see. It uses the same supervised, bounded I/O and current-authority checks as observations. A transport must use this method rather than Runtime::descriptor<R>, which remains trusted-host inspection.

Discovery defaults to an empty catalog. Opt in each item deliberately:

rust
Task::definition().discovery_policy(|actor, target| {
    actor.subject == "operator" && match target {
        rom::DiscoveryTarget::Resource => true,
        rom::DiscoveryTarget::Field(name) => matches!(name, "title" | "done"),
        rom::DiscoveryTarget::Action(name) => name == "complete",
    }
})

Before discovery discloses any fields or actions, the actor must have a Resource grant. The callback can capture trusted host configuration and must be Send + Sync. Like other native policy callbacks, it must terminate and must not recursively call into the Runtime. After a concurrent invalidation, the callback can run again. A panic is supervised and makes the Runtime terminal, rather than returning partial metadata.

The public types are Discovery { version, resources }, DiscoveredResource { kind, version, fields, actions }, and DiscoveredField { name, shape }. Version 1 serializes as:

json
{"version":1,"resources":[{"kind":"tasks","version":1,"fields":[{"name":"done","shape":{"type":"bool"}},{"name":"title","shape":{"type":"string"}}],"actions":["complete"]}]}

Kinds, fields and action names are sorted. Shapes use a snake_case type tag: string, bool, u64, i64, f64, nullable, optional, list, map, enum, and reference. Containers carry their nested shape in value; enums carry a string array. References carry "value":{"kind":"target-kind"}. If a field shape refers to a kind hidden from this actor, discovery omits the field completely. This includes references nested in containers. There are no hidden totals, omission markers, source ownership, policy names, or sample/default values.

Metadata visibility grants no permission to read rows, use query predicates, or invoke mutations. Those operations retain their own current authorization, including checks against actual prior and proposed values. Discovery does not scan rows, call field codecs or actions, or evaluate row policies against invented values. Action names carry no input schema: native Input codecs are opaque.

The entire serialized response must fit Limits::snapshot_bytes. Before construction copies the envelope and borrowed metadata fragments into output, it charges their sizes against the limit. Exhaustion returns TooLarge; it never returns a truncated catalog. Expiry, local revocation, and current identity denial prevent disclosure. Treat each result as a current observation, not a permanent permission grant.

HTTP clients POST the empty object {} to /discover under the normal host credential resolver and body limits. Unknown fields, non-object requests, and duplicate keys are rejected. The demo publishes only Task and InventoryItem metadata to its existing domain actors; configuration, identity and attachment metadata remain undiscoverable by default.

This page follows the captured repository source.View the source