Expand description
§encounter
encounter resolves what happens when several characters interact in a
scene. Give it the what could happen (a catalog of possible actions)
and the who is present (the characters); it picks one of three
protocols (one-shot exchange, turn-by-turn scene, or long-running
scheme) and returns a structured what happened — beats and typed
effects, replayable and testable. It does not generate prose, run a
drama manager, or decide policy — those live in the layer above.
§Architecture
encounter is standalone: it depends on serde, toml, and
thiserror, nothing else. Scoring and pattern evaluation are delegated
to consumers via traits:
ActionScorer— scores available actions for an actor. This is where your scoring policy lives — a utility/salience model, a GOAP planner, or an LLM call.AcceptanceEval— determines whether a responder accepts a chosen action. This is where your fabula evaluator, reaction model, or argumentation backend lives. Fabula here means the precondition language encounter uses for action availability — typically a small DSL the bridge crate parses.
On each beat, the protocol asks ActionScorer for ranked actions and
then asks AcceptanceEval whether the chosen action lands.
§Pluggable backends
The canonical reasoning backend is the
argumentation crate, via the
encounter-argumentation
bridge. It implements both consumer traits using a Dung-framework-style
argument graph with weighted-bipolar attacks and a β-budget acceptance
dial. If you need more than the built-in AlwaysAccept / AlwaysReject
test helpers, start with that bridge.
§Quick example: SingleExchange
use encounter::resolution::SingleExchange;
use encounter::scoring::{AlwaysAccept, ScoredAffordance};
use encounter::affordance::{AffordanceSpec, CatalogEntry};
use encounter::types::Effect;
let entry = CatalogEntry {
spec: AffordanceSpec {
name: "greet".into(),
domain: "social".into(),
bindings: vec!["self".into(), "target".into()],
considerations: Vec::new(),
effects_on_accept: vec![Effect::RelationshipDelta {
axis: "friendship".into(),
from: "target".into(),
to: "self".into(),
delta: 0.05,
}],
effects_on_reject: Vec::new(),
drive_alignment: Vec::new(),
},
precondition: String::new(),
};
let scored = ScoredAffordance {
entry,
score: 0.8,
bindings: [("self".into(), "alice".into()), ("target".into(), "bob".into())]
.into_iter()
.collect(),
};
let protocol = SingleExchange;
let result = protocol.resolve("alice", "bob", &[scored], &AlwaysAccept);
assert_eq!(result.beats.len(), 1);
assert!(result.beats[0].accepted);Runnable versions of all three protocols live in the examples/ directory
of the source repository.
§Catalog loading
use encounter::catalog::load_catalog_dir;
use std::path::Path;
let entries = load_catalog_dir(Path::new("path/to/catalog")).unwrap();
println!("loaded {} affordances", entries.len());§Inspirations
The protocols are small, opinionated reductions of shapes that have shipped or been published. Each one is named for what it borrows, not for what it reproduces faithfully:
SingleExchangereduces the intent/reaction step from McCoy et al., Comme il Faut (Game AI Pro 3, ch. 43). Full CiF social-games are out of scope.MultiBeattakes the speaker-rotation loop from Evans & Short, Versu (IEEE TCIAIG 2014). Full social-practice goal stacks, role tableaux, and obligations are out of scope.BackgroundSchemetakes the progress-bar shape from the scheme system in Crusader Kings III (CK3). Agents, discovery rolls, and counter-actions are out of scope.TurnPolicy::AdjacencyPairis the adjacency-pair model from Sacks, Schegloff & Jefferson, Lectures on Conversation (1992).
Re-exports§
pub use affordance::AffordanceSpec;pub use affordance::CatalogEntry;pub use error::Error;pub use escalation::EscalationRequest;pub use escalation::FidelityHint;pub use escalation::check_escalation;pub use practice::DurationPolicy;pub use practice::PracticeSpec;pub use practice::TurnPolicy;pub use resolution::MultiBeat;pub use resolution::SingleExchange;pub use resolution::background::BackgroundScheme;pub use resolution::background::SchemePhase;pub use scoring::AcceptanceEval;pub use scoring::ActionScorer;pub use scoring::AlwaysAccept;pub use scoring::AlwaysReject;pub use scoring::ScoredAffordance;pub use types::Beat;pub use types::ConsiderationSpec;pub use types::DriveAlignment;pub use types::Effect;pub use types::EncounterResult;pub use value_argument::ValueArgumentInput;pub use value_argument::ValueArgumentResult;pub use value_argument::resolve_value_argument;
Modules§
- affordance
- Affordance catalog types:
AffordanceSpecandCatalogEntry. - catalog
- Catalog loader: reads
.toml+.fabulafile pairs from a directory tree. - error
- Crate error types.
- escalation
- Escalation request types and detection logic.
- practice
- Practice specification types:
PracticeSpec,TurnPolicy, andDurationPolicy. - resolution
- Resolution protocols for encounter resolution.
- scoring
- Scoring traits and scored affordance types for encounter resolution.
- types
- Core data types shared across the crate.
- value_
argument - DF-style value argument resolution.