1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Bootstrap result types.
//!
//! Why: shared data structures used by both the scanner and the async entry
//! point. Keeping them in a separate file prevents circular dependencies and
//! keeps each module under the 500-SLOC cap.
//! What: `BootstrapTriple`, `ScannedFile`, `BootstrapResult`, plus the
//! `KG_EMPTY_HINT` / `KG_SUBJECT_NOT_FOUND_HINT` constants, the `KgMiss`
//! classifier behind `kg_query`'s `graph_state` field, and `result_to_json`.
//! Test: types are covered by the scanner and integration tests in sibling
//! modules.
use ;
use Serialize;
/// A single bootstrap discovery before it becomes a Triple.
///
/// Why: Keeping the scanner output as plain tuples (rather than full
/// `Triple`s) lets the unit tests verify the extraction logic without
/// constructing timestamps or worrying about confidence values. The async
/// caller converts these into `Triple`s with the live `chrono::Utc::now()`
/// timestamp right before assertion.
/// What: Carries subject, predicate, object, and the provenance tag that
/// identifies which scanner produced the fact.
/// Test: Each scanner test asserts the expected `BootstrapTriple`s land in
/// the result list.
/// Per-file scan summary returned to the MCP caller.
///
/// Why: Operators want to know *which* files contributed to the bootstrap
/// (and which were absent) without re-running the tool with verbose logging.
/// What: Filename + count of triples it produced; emitted as JSON in the
/// MCP response.
/// Test: `bootstrap_palace_returns_per_file_counts`.
/// Aggregate result of a bootstrap run.
///
/// Why: The MCP `kg_bootstrap` tool returns this verbatim so the model (or a
/// human operator) can see exactly what was asserted and which files were
/// scanned.
/// What: Total triple count + per-file summaries + the resolved project
/// subject. `Serialize` so it round-trips into the MCP JSON envelope.
/// Test: `bootstrap_palace_seeds_temporal_metadata_when_no_files`.
/// Hint string returned by `kg_query` when the palace KG holds no triples.
///
/// Why: Issue #60 — when a user calls `kg_query` against a brand-new palace
/// they get an empty triples array with no indication that `kg_bootstrap` /
/// `kg_assert` even exist. A short hint embedded in the response solves
/// this with one line of code at the call site.
/// What: Static string, kept in this module so tests can pin it.
/// Test: `kg_query_reports_graph_empty_when_graph_has_no_triples`.
pub const KG_EMPTY_HINT: &str =
"Knowledge graph is empty. Run kg_bootstrap to seed it from project files, \
or use kg_assert to add triples manually.";
/// Hint string returned by `kg_query` when the graph has triples but not for
/// the queried subject.
///
/// Why (#4775): the caller guessed a subject the graph does not hold. Telling
/// them to seed the graph is wrong — it is already seeded — and it sends them
/// to `kg_assert` when what they need is the list of subjects that do exist.
/// What: names `kg_list_subjects` (shipped in #4776) so the recovery step is a
/// tool call, not a second guess.
/// Test: `kg_query_reports_subject_not_found_when_graph_has_other_subjects`.
pub const KG_SUBJECT_NOT_FOUND_HINT: &str =
"No active triples for this subject. The knowledge graph is not empty — \
call kg_list_subjects to see which subjects it holds.";
/// Which of the two distinct "no triples came back" outcomes a `kg_query` hit.
///
/// Why (#4775): both outcomes returned the same "Knowledge graph is empty"
/// hint, and for the common case — a graph with facts, queried for a subject
/// it does not hold — that hint states something the handler can prove false.
/// A caller that believes it wastes a `kg_bootstrap` on an already-seeded
/// graph instead of listing the subjects that are there.
/// What: the discriminator behind `kg_query`'s `graph_state` response field.
/// [`Self::classify`] decides which one applies; [`Self::wire_value`] and
/// [`Self::hint`] are the two strings that reach the caller. Marked
/// `#[non_exhaustive]` so a future third outcome is not a breaking change.
/// Test: `kg_miss_classify_distinguishes_empty_graph_from_missing_subject`.
/// Helper: bubble up the bootstrap result as the MCP JSON envelope expects.
///
/// Why: `tools.rs` keeps the dispatcher branches small; converting the
/// `BootstrapResult` into a `serde_json::Value` here keeps the JSON shape
/// owned by this module and stable for tests.
/// What: Serialises the result via serde and wraps any failure in
/// `anyhow::Error` with context.
/// Test: round-tripped via the MCP dispatcher test.