foundation tier

foundation-conversation-closure

How a conversation is allowed to end: the closed set of intents a member may pick, which of them end a conversation and which only defer it, and a decline type with nowhere to put a member's own words.

How a conversation is allowed to end: the closed set of intents a member may pick, which of them end a conversation and which only defer it, and a decline type with nowhere to put a member's own words.

Tierfoundation
Rolevalue_object
Pathcrates/foundation/conversation-closure
Edition2021
Targetsfoundation_conversation_closure
Public items10 across 0 modules
Tests8

What it is for

How a conversation is allowed to end.

Built before the discovery grid, on the Gate 1.5 panel's finding (2026-08-27, unanimous): prove the closure mechanism first and add matching once it works. A grid that surfaces people is worth nothing if the ending it exists to enable does not hold its shape.

# The mechanism is the absence of a field

The product promise is that a decline is a courtesy from the application, never ghost-written in a member's voice. Every seat in the consensus round landed independently on the same enforcement, and it is not a review rule or a lint:

Decline carries an Intent and a TemplateVersion. There is no field for a member's words, no field for tone, and no field for style. "Make it sound more like me" cannot be added as an option because there is nowhere to put it — it would require changing this type, which is a visible act with a test attached rather than a tempting one-line addition to a request struct.

no_member_words_can_reach_the_recipient is that test. It is not a formality: it exists so that the day someone adds a String to this type in good faith, the build says no and names the promise being broken.

# What this crate does NOT do

It does not generate text. The wording lives in a reviewed catalogue keyed by (intent, template_version) on the application side, so that changing what people read is a content review rather than a code change, and so that every message ever sent can be reconstructed from two stored values.

It does not classify anything. Members pick an intent; nothing infers one. Where a model is involved at all it is offline, proposing catalogue variants for review, and its output becomes static data before it can reach anyone.

It does not re-implement domain-conversation-engine's IntentRegistry or application-conversation's admit, which already enforce that unconstrained model output never becomes a Candidate (sprint 3.114, 99 tests). Those govern classifying an incoming message; this governs a member choosing how to end one, and the choosing step has no model in it at all.

Capabilities

Decline

How a conversation is allowed to end.

Item
pub struct Decline
Decline :: fn new(intent : Intent, template : TemplateVersion) -> Self
Decline :: fn closes_the_conversation(self) -> bool
fn endings(declines : & Decline) -> usize

Intent

How a conversation is allowed to end.

Item
pub struct Intent
Intent :: fn is_terminal(self) -> bool
fn vocabulary() -> Vec <Intent>
fn intent(token : & str) -> Option <Intent>

Kind

How a conversation is allowed to end.

Item
pub enum Kind

TemplateVersion

How a conversation is allowed to end.

Item
pub struct TemplateVersion

How to use it

No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.

Module structure

No public modules: the crate root is its whole surface.

Public surface

`crate root`

ItemWhat it is
pub enum KindWhether an intent ends a conversation or only pauses it
pub struct IntentOne intent a member may pick.
Intent :: fn is_terminal(self) -> boolDoes choosing this end the conversation?
pub struct TemplateVersionWhich reviewed wording a member's counterpart was shown
pub struct DeclineA member's decision to end or pause a conversation
Decline :: fn new(intent : Intent, template : TemplateVersion) -> SelfRecord a decline
Decline :: fn closes_the_conversation(self) -> boolDoes this close the conversation for the purpose of the closure measure?
fn vocabulary() -> Vec <Intent>Every intent in the ratified vocabulary, in the seed's order
fn intent(token : & str) -> Option <Intent>Look up one intent
fn endings(declines : & Decline) -> usizeThe closure measure's numerator: declines that actually ended something

No pub use re-exports: every item above is declared in this crate.

Boundary

Depends on no other workspace tier.

Shares tier foundation with 27 other crates: foundation-audit-log, foundation-basemodels, foundation-bounded-io, foundation-crypto-sign, foundation-decisioning, foundation-encounter-vocabulary, foundation-fs-metadata, foundation-i18n, … (27 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)foundation
Architectural role (taxonomy)value_object
Locationcrates/foundation/conversation-closure
Vocabulary in force (lexicon)current

Dependencies

Runtime. None.

Development. None.

Build. None.

Depended on by. Nothing in this workspace.

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
libfoundation_conversation_closure`src/lib.rs`

Error model

No public error type was detected: no public item declares a type named *Error, and no public signature returns one.

Operational characteristics

PropertyEvidence
async public surfacenone detected
async runtimenone detected
database accessnone detected
network I/Onone detected
unsafe codenone detected
environment variablesnone detected

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.

No workspace crate depends on this one.

Verification

KindCount
Unit tests8
Integration tests0
Examples0
Doctests0

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
crate root700

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc1010
Public modules with a //! block00
pie showData
    title Public items with rustdoc
    "Documented" : 10
    "No rustdoc detected" : 0

Metrics

MetricValue
Rust source files1
Source lines265
Code lines141
Public API items10
Public modules0
Tests8
Examples0
Cargo features0
Direct runtime dependencies0
Workspace reverse dependencies0
pie showData
    title Public API by kind
    "enum" : 1
    "function" : 3
    "method" : 3
    "struct" : 3
pie showData
    title Rust source composition
    "Code" : 141
    "Blank or comment" : 124

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

All foundation · Manual