Skip to main content

NarratableFact

Enum NarratableFact 

Source
#[non_exhaustive]
pub enum NarratableFact {
Show 18 variants OperationAvailable { workflow: WorkflowKey, operation: OperationKey, summary: String, }, Record { case_ref: CaseRef, label: Option<String>, phase: Value, outcome: Option<Value>, }, StateValue { case_ref: CaseRef, field: String, value: Value, }, ProposedChange { case_ref: CaseRef, field: String, before: FieldValue, after: FieldValue, }, OperationalOutcome { receipt_id: ReceiptId, event_ids: Vec<EventId>, status_code: String, }, InteractionAvailable { interaction_id: InteractionId, interaction_kind: InteractionKind, }, InstructionDeclined { case_ref: CaseRef, interaction_id: InteractionId, option_id: OptionId, question: String, option_label: String, }, ActAwaitingConfirmation { case_ref: CaseRef, operation: String, subject: Option<String>, }, ActRefused { case_ref: Option<CaseRef>, code: String, explanation: String, }, ActChangedNothing { case_ref: CaseRef, operation: Option<String>, explanation: String, }, ValueNeeded { case_ref: Option<CaseRef>, operation: String, arguments: Vec<String>, reason: Option<String>, }, NotUnderstood { words: String, }, ActHeld { operation: String, because: String, }, WorkflowUnavailable { workflow: WorkflowKey, reason: String, }, InteractionAlreadyAnswered { interaction_id: InteractionId, option_id: Option<OptionId>, progress: AnswerProgress, }, AttachmentNotShown { attachment_id: AttachmentId, filename: Option<String>, reason: String, }, ObligationOpen { case_ref: CaseRef, obligation: Value, sentence: Option<String>, relevance: FactRelevance, }, Knowledge { chunk_id: String, source_id: String, text: String, },
}
Expand description

A fact the narrator may state (spec §18.3). Everything else is forbidden.

New fact kinds are expected, so downstream matches need a wildcard arm.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

OperationAvailable

Something the user can do now, in the workflow’s words.

Fields

§workflow: WorkflowKey

The workflow.

§operation: OperationKey

The operation.

§summary: String

What it does.

§

Record

A record a question is about: its name, where its lifecycle stands, and its outcome once complete.

Fields

§case_ref: CaseRef

The case.

§label: Option<String>

The name the user knows it by, when the directory supplied one.

§phase: Value

Its phase, in the workflow’s own vocabulary.

§outcome: Option<Value>

Its outcome, when it is complete.

§

StateValue

A committed field value.

Fields

§case_ref: CaseRef

The case.

§field: String

Field path.

§value: Value

Value.

§

ProposedChange

A proposed, uncommitted change.

Fields

§case_ref: CaseRef

The case.

§field: String

Field path.

§before: FieldValue

Current value.

§after: FieldValue

Proposed value. FieldValue::cleared is “the field is being emptied”, which is not the same statement as “unchanged”.

§

OperationalOutcome

An operational outcome; must be backed by a receipt block.

Fields

§receipt_id: ReceiptId

The receipt.

§event_ids: Vec<EventId>

Events behind it.

§status_code: String

Status code of the receipt.

§

InteractionAvailable

A card is available; must be backed by an interaction block.

Fields

§interaction_id: InteractionId

The interaction.

§interaction_kind: InteractionKind

Shape.

§

InstructionDeclined

The user declined an option on a card, so the server did nothing.

§Why this is not Self::ActRefused

The two look alike and read differently, which is the whole point. A refusal is the server saying no and owes the user a reason. A decline is the user saying no and owes them an acknowledgement — “all right, I haven’t; tell me what you’d like to change” rather than “that could not be done”. Folding them together would hand the narrator one word for two situations and it would write the wrong one half the time.

§Why the narrator needs it at all

The deterministic notice already says the instruction was declined, and it says it whether or not a model runs. What it cannot do is say it in the register of the conversation. Without this fact the narrator sees a turn with no plan, no receipts and nothing outstanding, and the only sentence that fits an empty brief is a generic offer of help — so the user reads a non-sequitur above a canned line, and it is obvious which of the two a machine wrote.

Fields

§case_ref: CaseRef

The case the card belonged to.

§interaction_id: InteractionId

The card that was answered.

§option_id: OptionId

The option that was chosen.

§question: String

What that card asked, in the reader’s locale, so the acknowledgement a decline owes names what was declined rather than offering to change something.

§option_label: String

The label of the option the user chose, in the reader’s locale.

§

ActAwaitingConfirmation

An act this turn prepared and did not run, because a card is asking the user to authorize it first.

Forbidding the claim that it happened is not enough: a writer told it may not assert X, with no fact to say instead, asserts not-X. This is that fact, so the true sentence («before I do it, I am asking you») is the one it can write. It is emitted wherever the confirmation policy defers a command, since a card raised by policy moves no case and no phase or briefing knows it is there.

Fields

§case_ref: CaseRef

The case the act was aimed at.

§operation: String

The operation that is waiting.

§subject: Option<String>

What the workflow calls the thing being confirmed, when it said.

§

ActRefused

An act the domain refused, and why.

§Why a refusal is not a claim

The claim guard exists to stop a model saying something happened that did not. Saying that something did not happen, with the reason the server itself produced, does not cross that line — it is the honest half of the same rule. Without it an assistant forbidden from claiming success has no way to report failure either, so it writes about something else and the user concludes the write went through.

That is not hypothetical: it is what happens next. A user told nothing about a refusal says “I already gave you that”, the interpreter reads a transcript in which the refusal never occurred, and the complaint gets written into the field the refusal was protecting.

Fields

§case_ref: Option<CaseRef>

The case the act was aimed at, when its target resolved to one.

Absent when the refusal is the target: an act naming a shape the operation does not accept, or a card that is not on screen, never reached a case at all. The narrator is told about it anyway, because the user asked for something and did not get it.

§code: String

The rejection’s stable code.

§explanation: String

The domain’s own sentence, in the reader’s locale, or empty when the rejection carried none.

§

ActChangedNothing

An act the domain accepted, and that changed nothing.

Not a refusal: nothing about it was wrong. The state it asks for is the state the case is already in, so the workflow compiled no commands — which is a legitimate answer, and the one a singleton workflow relies on when its start is proposed a second time.

§Why the narrator needs it

For the reason Self::ActRefused gives, and it is the same sentence: an outcome nobody is told about is read by the user as a success, and by the next turn’s interpreter as a transcript in which it never happened. A refusal has been told for a long time; this one was not, and it leaves exactly the same hole — no receipt, no fact, obligations unchanged — so the writing stage does the only thing an empty brief allows. It asks for something else, or it announces the write.

One turn paid for it whole. The user asked to go on with a draft; the plan proposed starting a workflow that was already open; the domain compiled nothing, the act left no trace, and the reply invented a datum on a document the user had never named.

Fields

§case_ref: CaseRef

The case the act reached.

§operation: Option<String>

The operation, as the catalogue names it. Absent for the acts that carry none — a start is the common one.

§explanation: String

The workflow’s own sentence saying WHY nothing changed, in the reader’s locale, or empty when it wrote none.

One workflow compiles nothing for reasons that want opposite replies — the singleton whose start was proposed twice, the write that tells a field what it already says — and the name of the operation does not separate them. A writer given only the name invents, and what it reaches for is a refusal: «I cannot do that here», to a user who had asked for a correction and now has no idea what to say next.

Filled from WorkflowDefinition::nothing_changed; empty is what every workflow said before that channel existed, and it defaults on deserialization so records written then still load.

§

ValueNeeded

An act that waits for values the user has not given: they are asked for, and nothing is written until they are.

Fields

§case_ref: Option<CaseRef>

The case the act is aimed at, when it resolved to one.

§operation: String

The operation.

§arguments: Vec<String>

The arguments asked for, by the labels people use for them.

§reason: Option<String>

The domain’s explanation, when it refused a value it was given.

§

NotUnderstood

Words of the message that produced nothing to act on.

Fields

§words: String

The words, verbatim.

§

ActHeld

An act held back because another part of the message about the same record was not understood.

Fields

§operation: String

The operation.

§because: String

The words that were not understood.

§

WorkflowUnavailable

A workflow this account cannot start yet, and the reason it declared.

Shown what is unavailable, the model rightly proposes no act, so there is no refusal to carry the reason: it travels as this fact instead, like an open obligation, something that has not happened, known from a declaration. It widens nothing the narrator may claim: no ClaimClass covers it and no receipt backs it.

Fields

§workflow: WorkflowKey

The workflow that cannot be started.

§reason: String

Why, in the workflow’s own words, resolved to the reader’s locale.

§

InteractionAlreadyAnswered

The card this turn answered had already been answered.

§The turn this fills

A second click on the same card authorizes nothing: the compare-and-set that guarantees it is the part of this worth leaving alone. But the record it comes back with used to be dropped, so from that point on nothing could tell a second click from a turn with no click at all — and a turn with no plan, no receipts and nothing outstanding still calls the stage that writes the lead-in, which does what that stage always does with an empty brief: it invents.

One such turn told a user to start their invoicing configuration from the payment method. It was collected, it was on the card they were looking at, and the case’s own guidance for that phase said not to start over.

Skipping the stage is not the fix, because the turn would go out silent and a second click is somebody who did not understand the first answer. The fix is to give the turn something true to say.

§It claims nothing this turn did

The original resolution’s events are surfaced beside this as receipts, so prose that says the work is done is backed by the events that did it — which is what “repeat the result without repeating the effect” means. On a resolution still running there are no events yet, and AnswerProgress::Running is the fact that keeps the prose off a claim nothing backs.

Fields

§interaction_id: InteractionId

The card that was clicked again.

§option_id: Option<OptionId>

The option chosen the first time, when the record kept one.

§progress: AnswerProgress

How far the first answer got.

§

AttachmentNotShown

A file the turn carried that the model was not shown.

§Why the writing stage has to be told

A turn’s attachments reach the model as parts of the request, so a question about a document is answered from the document. When one does not get there — the application no longer holds it, the budget for one request would not take it, no provider in the chain accepts its media type — the model has the user’s sentence about a file and no file.

A stage asked to answer about something it cannot see answers anyway, and an answer about the wrong document is worse than an answer about none. So this is a fact and not only a notice: the notice tells the user deterministically, and the fact is what stops the prose describing a document nobody looked at.

It widens nothing the narrator may claim. A file not shown is not an effect, so no ClaimClass covers it and no receipt could back it.

Fields

§attachment_id: AttachmentId

The file, as the turn named it.

§filename: Option<String>

What the user called it, when the upload carried a name.

§reason: String

Why it was not shown, in the reader’s locale.

§

ObligationOpen

An obligation the case still has open.

§Why this is a fact and not a licence

Everything else here describes something that happened. This describes something that has not: a value the workflow’s own projection says is still outstanding. It is on the same side of the design as the rest, because it comes from the projection rather than from the model, and the projection is a pure function of committed state.

It widens nothing the narrator may claim. An obligation is not an effect, so no ClaimClass covers it and no receipt could back it; the claim guard is unmoved. What it changes is whether the assistant can ask for the next thing. A flow whose job is to collect several values could previously only acknowledge each one and wait, because the stage that writes the prose was never told what was still missing.

§It must be the obligations after the turn

The projection that framed the interpretation is the one from before the commands ran. Narrating from it asks the user for the value they have just supplied, which is worse than saying nothing. The runtime re-projects the cases a turn changed and narrates from that.

Fields

§case_ref: CaseRef

The case, at the revision the obligation was read at.

§obligation: Value

The obligation, in the workflow’s own vocabulary.

§sentence: Option<String>

The same thing in words a person would recognise, when the workflow says it (WorkflowDefinition::obligation_sentence). The serialized value is the domain’s structure, and a stage handed only that guesses what to ask for.

§relevance: FactRelevance

Whether this is a case the turn engaged or one that merely exists.

See FactRelevance. Facts about the turn sort first, because the writing stage is told to ask for the first one.

§

Knowledge

Retrieved knowledge.

Fields

§chunk_id: String

Chunk id.

§source_id: String

Source id.

§text: String

The text.

Trait Implementations§

Source§

impl Clone for NarratableFact

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for NarratableFact

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for NarratableFact

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for NarratableFact

Source§

impl PartialEq for NarratableFact

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for NarratableFact

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for NarratableFact

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.