newt_interaction/lib.rs
1//! **Newt Markup interaction protocol — the renderer-neutral model (A2, #1828).**
2//!
3//! ADR: `docs/decisions/newt_markup_interaction_architecture.md`. This crate
4//! is the model half of that MVC variation: an immutable, semantic
5//! [`InteractionDefinition`], a host-minted, out-of-band
6//! [`InteractionInstance`], and a typed [`Response`]. It defines the records
7//! and the STATES; the controller that drives transitions is A3's, and no
8//! renderer lives here or ever will.
9//!
10//! **Dependency direction is binding.** This is the inward layer: it takes no
11//! Ratatui, crossterm, Axum, HTMX, ammonia, browser, mobile, filesystem, or
12//! application dependency, and no `newt-*` crate. `newt-core` depends on this
13//! crate; never the reverse. `tests/guard.rs` arms that as a test rather than
14//! a comment — one half over the resolved dependency closure, one over this
15//! crate's own source — and each half carries an anti-vacuous twin, because a
16//! guard that cannot fail is decoration.
17//!
18//! **Identity is derived, never assigned.** Every record here is a canonical
19//! structured value, so its identity is a `ContentId` minted through
20//! `ContentAddressable` + `canonical::to_canonical_dagcbor` — the codec makes
21//! determinism a property of the encoder, not of caller discipline. Nothing
22//! in this crate hand-rolls a digest or a canonical encoding. The single
23//! deliberate exception is the instance NONCE, which is fresh and
24//! unguessable rather than content-derived: it is a locator that travels
25//! beside the address, and possession of it authorizes nothing. **IDs route;
26//! they are not credentials.**
27//!
28//! This file is a manifest: composition only, no logic.
29
30pub mod binding;
31pub mod definition;
32pub mod downgrade;
33pub mod error;
34pub mod ids;
35pub mod instance;
36pub mod lifecycle;
37pub mod resolution;
38pub mod response;
39pub mod tag;
40
41pub use binding::{
42 validate_response, Accepted, HandlerId, Refusal, RegisteredAction, ResolvedAction,
43 ResponderContext,
44};
45pub use definition::{
46 controls_are_decision_shaped, ChoiceOption, Control, ControlKind, FeatureDemand,
47 InteractionDefinition, InteractionKind, PathKind, Requirement, SemanticRole, SurfaceFeature,
48 TemporalPrecision, DEFINITION_SCHEMA_V1,
49};
50pub use downgrade::{
51 decode_definition, decode_instance, decode_response, plan_presentation, Decoded, Degradation,
52 Presentation, RawRecord, UnknownReason,
53};
54pub use error::ProtocolError;
55pub use ids::{
56 ControlId, DefinitionId, IdempotencyKey, InstanceId, Nonce, OptionId, ResponseId, Revision,
57};
58pub use instance::{
59 Audience, InteractionInstance, LifecycleState, Provenance, ResponderPolicy, Scope,
60 INSTANCE_SCHEMA_V1,
61};
62pub use lifecycle::{publish, HostMint, Lifecycle, LifecycleError};
63pub use resolution::{
64 IdempotencyConflict, Resolution, ResolutionError, ResolutionRecord, ResolutionStore,
65};
66pub use response::{
67 AssertionKind, ControlValue, ResponderProvenance, Response, SecretRef, Submission,
68 RESPONSE_SCHEMA_V1,
69};
70pub use tag::{DefinitionTag, InstanceTag, ResponseTag};