mant_protocol/explanation/matches.rs
1//! Response-relative matching facts and ordinary display bindings.
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4
5/// Maximum retained Name and Form records combined per evidence owner.
6pub const MAX_EXPLANATION_MATCH_RECORDS: usize = 32;
7/// Maximum ordinary display bindings per evidence owner (not a names limit).
8pub const MAX_EXPLANATION_NAME_BINDINGS: usize = 32;
9/// Maximum source occurrences retained per match or display-binding record.
10pub const MAX_EXPLANATION_OCCURRENCES: usize = 32;
11/// Maximum fragments in one occurrence in each target domain.
12pub const MAX_EXPLANATION_FRAGMENTS: usize = 32;
13/// Combined match, display-binding and preview/body fragments per owner.
14pub const MAX_EXPLANATION_POSITIONS: usize = 1024;
15
16/// One documented name that actually matched under the owner's case policy.
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
18#[serde(rename_all = "camelCase", deny_unknown_fields)]
19pub struct ExplanationNameMatch {
20 /// Exact authored spelling, usable even when entry metadata is absent.
21 pub name: String,
22 /// Complete occurrences in available response targets, not implicit aliases.
23 pub occurrences: Vec<ExplanationOccurrence>,
24}
25
26/// One complete authored form that actually matched during collection.
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
28#[serde(rename_all = "camelCase", deny_unknown_fields)]
29pub struct ExplanationFormMatch {
30 /// Snapshot-local ordinal in the original owner's forms, not a durable ID
31 /// or an index into an omitted/filtered response payload.
32 pub source_form_index: u32,
33 /// Complete authored visible text, with original spelling.
34 pub text: String,
35 /// Complete positions in available returned targets.
36 pub occurrences: Vec<ExplanationOccurrence>,
37}
38
39/// An actual identity match, referencing this evidence's outline fields.
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
41#[serde(rename_all = "kebab-case")]
42pub enum ExplanationIdentityField {
43 /// The exact outline node ID matched.
44 Id,
45 /// The structural outline path matched.
46 Path,
47}
48
49/// One ordinary name binding, independent of whether that name matched a query.
50#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
51#[serde(rename_all = "camelCase", deny_unknown_fields)]
52pub struct ExplanationNameBinding {
53 /// Index into this response's `entry.names` (never an absent entry).
54 pub name_index: u32,
55 /// Validated source occurrences projected into the returned payload.
56 pub occurrences: Vec<ExplanationOccurrence>,
57}
58
59/// One whole occurrence, with independent complete projections per target domain.
60/// An unavailable or omitted domain is empty; a partial name is never retained.
61#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
62#[serde(rename_all = "camelCase", deny_unknown_fields)]
63pub struct ExplanationOccurrence {
64 /// Original binding-occurrence ordinal (zero for a complete form match).
65 /// A snapshot coordinate, not a durable identity or returned-array index.
66 pub source_occurrence_index: u32,
67 /// Ordered fragments within returned forms.
68 pub forms: Vec<ExplanationFormRange>,
69 /// Ordered fragments within the returned original body.
70 pub content: Vec<ExplanationContentRange>,
71}
72
73/// Half-open Unicode scalar offsets in returned `entry.forms[formIndex]`.
74#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
75#[serde(rename_all = "camelCase", deny_unknown_fields)]
76pub struct ExplanationFormRange {
77 /// Index into the forms actually returned in this entry's metadata.
78 pub form_index: u32,
79 /// Start in safe visible text, excluding renderer-added framing.
80 pub start_char: u32,
81 /// Exclusive end in the same text root.
82 pub end_char: u32,
83}
84
85/// Shared structural step, rooted here in the single returned `content.block`.
86/// Item/cell steps select an array and must be followed by a block step.
87pub use mant_ir::ContentBlockStep as ExplanationBlockStep;
88
89/// Half-open Unicode scalar offsets rooted in this response's original body.
90/// The path does not reference the full source document or a preview window.
91#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
92#[serde(
93 tag = "kind",
94 rename_all = "kebab-case",
95 rename_all_fields = "camelCase",
96 deny_unknown_fields
97)]
98pub enum ExplanationContentRange {
99 /// Safe visible text of a paragraph, preformatted, equation or unsupported leaf.
100 BlockText {
101 /// Typed path to that leaf, starting at `content.block`.
102 path: Vec<ExplanationBlockStep>,
103 /// First matched scalar in the leaf text.
104 start_char: u32,
105 /// Exclusive end scalar in the same leaf.
106 end_char: u32,
107 },
108 /// Safe visible inline text of exactly one original definition term.
109 DefinitionTerm {
110 /// Typed path to a definition-list block.
111 path: Vec<ExplanationBlockStep>,
112 /// Item in that returned list; an excerpted owner is item zero.
113 item_index: u32,
114 /// Index in that item's terms, independent of form indices.
115 term_index: u32,
116 /// First matched scalar in this term.
117 start_char: u32,
118 /// Exclusive end scalar in the same term.
119 end_char: u32,
120 },
121}