Skip to main content

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}