Skip to main content

evaluate_accompaniment

Function evaluate_accompaniment 

Source
pub fn evaluate_accompaniment(
    db: &ObjectDatabase,
    request: AccompanimentRequest<'_>,
) -> Result<AccompanimentEvaluation, Error>
Expand description

Evaluate local accompaniment evidence without writing objects, obtaining a clock, performing I/O, or publishing an event. Rights are recomputed in this database borrow; a caller-provided grant is never accepted as authority.

This is only an accompaniment stage. Authentication, credential activity, other authorization checks, pending transactions, and exactly-once event publication belong to the caller. See AccompanimentRequest for explicit timing and bounded-chain evidence; no default order or timeout is installed.

A direct attempt using the original credential is incorrect. A chain that returns to an earlier credential after a distinct companion is unresolved; no cyclic authorization fixed point is inferred. Missing witness rows also remain unresolved, while an explicit Waiting row can reach a verified expiry. Intents refer only to the requested original transaction, including when a child’s failure invalidates its companion.

§Example

use bacnet_objects::{access_control::*, database::ObjectDatabase};
use bacnet_types::{
    constructed::{BACnetAccessRule, BACnetAssignedAccessRights},
    enums::ObjectType,
    primitives::ObjectIdentifier,
};
use core::time::Duration;
let id = |kind, n| ObjectIdentifier::new(kind, n).unwrap();
let point = id(ObjectType::ACCESS_POINT, 1);
let mut db = ObjectDatabase::new();
db.add(Box::new(AccessPointObject::new(1, "entry")?))?;
for n in 1..=2 {
    let rights_id = id(ObjectType::ACCESS_RIGHTS, n);
    let mut rights = AccessRightsObject::new(n, format!("rights-{n}"))?;
    rights.set_positive_access_rules([
        BACnetAccessRule::new(None, Some(point.into()), true),
    ])?;
    if n == 1 {
        rights.set_accompaniment(Some(id(ObjectType::ACCESS_CREDENTIAL, 2).into()))?;
    }
    let mut card = AccessCredentialObject::new(n, format!("card-{n}"))?;
    card.set_assigned_access_rights(vec![BACnetAssignedAccessRights {
        assigned_access_rights: rights_id.into(), enable: true,
    }])?;
    db.add(Box::new(rights))?;
    db.add(Box::new(card))?;
}
let original = CredentialPresentation {
    sequence: 1, credential: id(ObjectType::ACCESS_CREDENTIAL, 1),
    point, at: Duration::from_secs(20),
};
let companion = CredentialPresentation {
    sequence: 2, credential: id(ObjectType::ACCESS_CREDENTIAL, 2),
    point, at: Duration::from_secs(21),
};
let witnesses = [AccompanimentWitness {
    original: original.sequence,
    evidence: AccompanimentEvidence::Presented(companion),
}];
let result = evaluate_accompaniment(&db, AccompanimentRequest {
    original, now: companion.at, witnesses: &witnesses,
    timing: AccompanimentTiming {
        order: AccompanimentOrder::After,
        fallback_period: Duration::from_secs(5),
        deadline: AccompanimentDeadline::Inclusive,
    },
    max_links: 8,
})?;
assert_eq!(result.outcome, AccompanimentOutcome::Satisfied);
assert_eq!(result.events.len(), 1);
// The application still checks authentication and all other authorization
// criteria before acting; it owns transaction state and event publication.

§Errors

Original credential/point or original rights-read errors are returned from evaluate_access_rights. Unavailable accompaniment/companion evidence is an AccompanimentOutcome::Unresolved result instead.