parlov-elicit 0.5.0

Elicitation engine: strategy selection and probe plan generation for parlov.
Documentation
//! Status-code-diff existence strategies.
//!
//! Each module implements one elicitation strategy that produces a differential
//! signal through status code differences between baseline and probe responses.
//! `scd_chain_registry` wires the `ETag` producer/consumer pairs for validator
//! chaining and the resource-ID, problem-details, content-type, and
//! auth-challenge producer/consumer pairs.

use std::sync::Arc;

use crate::chain::ChainRegistry;

pub mod accept;
pub mod auth_challenge;
pub mod auth_strip;
pub mod case_normalize;
pub mod content_type;
pub mod dependency_delete;
pub mod empty_body;
pub mod if_match;
pub mod if_match_read;
pub mod if_none_match;
pub mod low_privilege;
pub mod problem_details;
pub mod rate_limit_burst;
pub mod rate_limit_headers;
pub mod resource_id;
pub mod scope_manipulation;
pub mod state_transition;
pub mod trailing_slash;
pub mod uniqueness;

pub use accept::AcceptElicitation;
pub use auth_strip::AuthStripElicitation;
pub use case_normalize::CaseNormalizeElicitation;
pub use content_type::ContentTypeElicitation;
pub use dependency_delete::DependencyDeleteElicitation;
pub use empty_body::EmptyBodyElicitation;
pub use if_match::IfMatchElicitation;
pub use if_match_read::IfMatchReadElicitation;
pub use if_none_match::IfNoneMatchElicitation;
pub use low_privilege::LowPrivilegeElicitation;
pub use rate_limit_burst::RateLimitBurstElicitation;
pub use rate_limit_headers::RateLimitHeadersElicitation;
pub use scope_manipulation::ScopeManipulationElicitation;
pub use state_transition::StateTransitionElicitation;
pub use trailing_slash::TrailingSlashElicitation;
pub use uniqueness::UniquenessElicitation;

/// Builds a `ChainRegistry` for status-code-diff validator, resource-ID, problem-details,
/// content-type negotiation, and auth-challenge chains.
///
/// Six edges: real-`ETag` → `If-Match` (write path), real-`ETag` → `If-None-Match` (read path),
/// 201 `Location` → GET/PATCH/DELETE (resource-ID chain), 4xx JSON error body → repaired POST
/// body (problem-details chain), 2xx `Content-Type` → GET with matching/unsupported `Accept`
/// (negotiation chain), and 401/407 `WWW-Authenticate` → GET with crafted `Authorization`
/// (auth-challenge chain).
#[must_use]
pub fn scd_chain_registry() -> ChainRegistry {
    let mut reg = ChainRegistry::new();
    reg.register(
        Arc::new(if_match::IfMatchElicitationProducer),
        Arc::new(if_match::IfMatchElicitationConsumer),
    );
    reg.register(
        Arc::new(if_none_match::IfNoneMatchElicitationProducer),
        Arc::new(if_none_match::IfNoneMatchElicitationConsumer),
    );
    reg.register(
        Arc::new(resource_id::ScdResourceIdProducer),
        Arc::new(resource_id::ScdResourceIdConsumer),
    );
    reg.register(
        Arc::new(problem_details::ScdProblemDetailsProducer),
        Arc::new(problem_details::ScdProblemDetailsConsumer),
    );
    reg.register(
        Arc::new(content_type::ScdContentTypeProducer),
        Arc::new(content_type::ScdContentTypeConsumer),
    );
    reg.register(
        Arc::new(auth_challenge::ScdAuthChallengeProducer),
        Arc::new(auth_challenge::ScdAuthChallengeConsumer),
    );
    reg
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn scd_chain_registry_has_six_edges() {
        assert_eq!(scd_chain_registry().len(), 6);
    }
}