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
//! Temporary-council store wiring.
//!
//! Councils are a meerkat-mob capability: one `council` tool call seats forked
//! participants, runs bounded exchanges, merges and tears the temporary mob
//! down. `meerkat_mob_mcp::MobMcpState` owns the store and defaults it to an
//! IN-MEMORY implementation, so before this module a MobKit gateway lost every
//! council record on restart - including the unfinished ones that
//! `TemporaryCouncilStore::list_unfinished` exists to recover.
//!
//! MobKit supplies its own store rather than calling
//! `MobMcpState::with_persistent_storage_root`. That helper would also flip
//! forked-participant custody and realm profiles to durable in the same call:
//! three behaviour changes bundled as one, two of them unrelated to councils
//! and each with its own recovery semantics. Supplying one store keeps the
//! change to the thing it claims to change.
//!
//! The path comes from [`crate::MobKitStorageLayout::council_db`], which means
//! the file is a registered [`crate::storage_layout::DatabaseSlot`] and is seen
//! by `storage doctor` and `storage migrate` like every other MobKit database.
//! A durable store outside that enumeration would be a second authority.
use ;
use Arc;
use ;
/// Canonical file name for the temporary-council store.
pub const COUNCIL_STORE_FILE: &str = "council.sqlite3";
/// Open the durable council store for this layout.
///
/// # Absent is normal; unreadable is not
///
/// These two are deliberately NOT the same outcome, and the first version of
/// this function conflated them.
///
/// A store file that does not exist yet is the ordinary first-boot case. There
/// is nothing to recover, `open` creates it, and a gateway proceeds.
///
/// A store file that EXISTS and cannot be opened is a read/decode failure -
/// corruption, a permission fault, a truncated database. Meerkat's council
/// custody recovery (#1050) surfaces exactly that as a typed refusal, and its
/// owner was explicit: **read/decode failure is not emptiness and must never
/// fail soft**. Degrading to an in-memory store there would present a corrupt
/// durable store as "councils are process-bound today", which is precisely the
/// signal the recovery path exists to raise - swallowed at the boundary before
/// it ever reaches them.
///
/// So this returns `Err` when the file is present and unopenable, and the
/// caller refuses the boot. It returns `Ok(None)` only when councils are
/// legitimately unavailable without evidence of damage.
/// A durable council store that exists on disk and cannot be read.
///
/// Typed rather than a bare string so a caller can refuse on it without
/// pattern-matching a log line.
/// Resolve the council store path for a `store_path`-style root.
///
/// `MobKitStorageLayout::standalone_from_store_path` is the ONE place that
/// interprets the `store_path` escape hatch (a value with an extension names a
/// database and its parent is the state dir; otherwise it IS the state dir).
/// Re-deriving that rule here would create a second path authority, so this
/// goes through the layout even though it only reads `state_dir`.
///
/// `gateway_home` is immaterial to `council_db()`, which reads `state_dir`
/// alone; callers that need a real gateway home must build the layout properly
/// rather than reusing this helper.