Skip to main content

sqlite_graphrag/i18n/validation/
messages_not_found.rs

1//! GAP-SG-143: canonical English texts for every [`crate::errors::AppError::NotFound`]
2//! payload the crate builds.
3//!
4//! # Why these are English-only
5//!
6//! Unlike the `AppError::Validation` catalogs such as [`super::messages_naming`], which
7//! resolves [`crate::i18n::current`] at construction because
8//! [`super::app_error_pt::validation`] only prefixes its argument, the
9//! `NotFound` payload is translated at DISPLAY time by
10//! [`super::app_error_pt::not_found`]. Resolving the locale here would break
11//! that layer twice over: `localized_message_for(Language::English)` would
12//! return Portuguese whenever the process locale is `pt-BR`, and the
13//! replace-chain would run over text that no longer matches its English
14//! patterns.
15//!
16//! So these functions own the ENGLISH wording, in one place, and
17//! `app_error_pt::not_found` owns the Portuguese. The pairing is enforced by
18//! `not_found_catalog_has_no_english_residue_in_pt` in `src/i18n/tests.rs`,
19//! which pushes every builder below through the translation chain and fails on
20//! any surviving English.
21//!
22//! Adding a builder here without extending the chain therefore fails the test
23//! rather than shipping a bilingual hybrid — the exact regression GAP-SG-143
24//! recorded.
25
26// ── memories ──────────────────────────────────────────────────────────
27
28/// A memory name did not resolve, in a context that has no namespace to report.
29pub fn memory_named_not_found(name: &str) -> String {
30    format!("memory '{name}' not found")
31}
32
33/// A memory name did not resolve inside a specific namespace.
34pub fn memory_named_not_found_in_namespace(name: &str, namespace: &str) -> String {
35    format!("memory '{name}' not found in namespace '{namespace}'")
36}
37
38/// A memory id exists but is owned by a different namespace than the one asked
39/// for. Distinct from a plain miss: the row is there, the caller is not
40/// entitled to it, and naming both namespaces is what makes that actionable.
41pub fn memory_id_in_other_namespace(id: i64, actual: &str, requested: &str) -> String {
42    format!("memory id {id} exists but belongs to namespace '{actual}', not '{requested}'")
43}
44
45// ── entities ──────────────────────────────────────────────────────────
46
47/// An entity name did not resolve, in a context that has no namespace to report.
48pub fn entity_named_not_found(name: &str) -> String {
49    format!("entity '{name}' not found")
50}
51
52/// An entity name did not resolve inside a specific namespace.
53pub fn entity_named_not_found_in_namespace(name: &str, namespace: &str) -> String {
54    format!("entity '{name}' not found in namespace '{namespace}'")
55}
56
57/// An entity name did not resolve, but near-matches exist.
58///
59/// `suggestions` is rendered by the caller as a comma-separated list so this
60/// function stays free of formatting policy.
61pub fn entity_named_not_found_with_suggestions(
62    name: &str,
63    namespace: &str,
64    suggestions: &str,
65) -> String {
66    format!(
67        "entity '{name}' not found in namespace '{namespace}'. Did you mean: {suggestions}? \
68         Re-run with --fuzzy to auto-resolve a clear match, or pass the canonical name."
69    )
70}
71
72/// An entity id did not resolve inside a specific namespace.
73pub fn entity_id_not_found_in_namespace(id: i64, namespace: &str) -> String {
74    format!("entity id={id} not found in namespace '{namespace}'")
75}
76
77/// The SOURCE endpoint of an edge did not resolve.
78///
79/// Kept distinct from [`entity_named_not_found_in_namespace`] because an
80/// operator fixing a relation needs to know WHICH endpoint is missing.
81pub fn source_entity_not_found_in_namespace(name: &str, namespace: &str) -> String {
82    format!("source entity '{name}' not found in namespace '{namespace}'")
83}
84
85/// The TARGET endpoint of an edge did not resolve.
86pub fn target_entity_not_found_in_namespace(name: &str, namespace: &str) -> String {
87    format!("target entity '{name}' not found in namespace '{namespace}'")
88}
89
90// ── graph edges and chunks ────────────────────────────────────────────
91
92/// Both endpoints resolved but no edge carries `relation` between them.
93pub fn edge_not_found_in_namespace(
94    source: &str,
95    relation: &str,
96    target: &str,
97    namespace: &str,
98) -> String {
99    format!("edge '{source}' --[{relation}]--> '{target}' not found in namespace '{namespace}'")
100}
101
102/// A relationship row id did not resolve.
103pub fn relationship_id_not_found(id: i64) -> String {
104    format!("relationship {id} not found")
105}
106
107/// A chunk id did not resolve inside a specific namespace.
108pub fn chunk_id_not_found_in_namespace(id: i64, namespace: &str) -> String {
109    format!("chunk {id} not found in namespace '{namespace}'")
110}
111
112// ── host-side records ─────────────────────────────────────────────────
113
114/// A concurrency slot was asked to be released but holds no lock file.
115pub fn slot_not_held(slot_id: u32, path: &str) -> String {
116    format!("slot {slot_id} is not held (no file at {path})")
117}
118
119/// No stored API key matches the given fingerprint.
120pub fn api_key_fingerprint_not_found(fingerprint: &str) -> String {
121    format!("no key with fingerprint {fingerprint}")
122}
123
124/// Every builder in this module, evaluated with placeholder arguments.
125///
126/// Exposed so `src/i18n/tests.rs` can assert the Portuguese chain covers the
127/// whole catalog instead of whichever entries someone remembered to list.
128/// A new builder that is not added here is caught by
129/// `not_found_catalog_covers_every_builder`, which compares this length
130/// against the count of `pub fn` in the module source.
131#[cfg(test)]
132pub(crate) fn catalog_samples() -> Vec<String> {
133    vec![
134        memory_named_not_found("alpha"),
135        memory_named_not_found_in_namespace("alpha", "global"),
136        memory_id_in_other_namespace(7, "other", "global"),
137        entity_named_not_found("beta"),
138        entity_named_not_found_in_namespace("beta", "global"),
139        entity_named_not_found_with_suggestions("beta", "global", "beta-one, beta-two"),
140        entity_id_not_found_in_namespace(9, "global"),
141        source_entity_not_found_in_namespace("beta", "global"),
142        target_entity_not_found_in_namespace("gamma", "global"),
143        edge_not_found_in_namespace("beta", "uses", "gamma", "global"),
144        relationship_id_not_found(42),
145        chunk_id_not_found_in_namespace(3, "global"),
146        slot_not_held(2, "/tmp/slot-2.lock"),
147        api_key_fingerprint_not_found("ab12cd34"),
148    ]
149}