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
// SPDX-License-Identifier: Apache-2.0 OR MIT
//! Plan 12: regeneration knobs and reports.
//!
//! Public option/report types for the regeneration primitives. The
//! consuming methods on [`crate::Memory`] are
//! `subjects_to_regenerate(scope, opts)` (shipped) and the deferred
//! `reindex(scope)`, `regenerate_embeddings(scope, embedder)`, and
//! `gc(opts)` (designed in Plan 12).
use std::time::Duration;
use crate::summarizer::SummaryStyle;
/// Caller-tunable knobs on [`crate::Memory::subjects_to_regenerate`].
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct RegenSubjectOpts {
/// When `true`, every subject under scope is yielded regardless of
/// the stale flag. Used for mass re-summarisation after a model
/// upgrade. Default `false`.
pub force: bool,
/// Style filter — only yield subjects whose target style matches.
pub style: SummaryStyle,
}
impl Default for RegenSubjectOpts {
fn default() -> Self {
Self {
force: false,
style: SummaryStyle::Compact,
}
}
}
impl RegenSubjectOpts {
/// Set the force flag.
#[must_use]
pub fn with_force(mut self, force: bool) -> Self {
self.force = force;
self
}
/// Set the style filter.
#[must_use]
pub fn with_style(mut self, style: SummaryStyle) -> Self {
self.style = style;
self
}
}
/// Report from a future `Memory::reindex(scope)` (deferred — see Plan 12).
#[non_exhaustive]
#[derive(Debug, Clone, Default)]
pub struct ReindexReport {
/// Number of `partition_index` rows whose disk index was rebuilt.
pub indices_rebuilt: u64,
/// Number of memory rows whose embedding was re-shipped to a
/// rebuilt leaf index.
pub memories_indexed: u64,
/// Number of child summaries shipped into a rebuilt internal/tenant
/// index.
pub child_summaries_indexed: u64,
/// Wall-clock duration in millis.
pub duration_ms: u64,
}
/// Report from a future `Memory::regenerate_embeddings(scope, embedder)`
/// (deferred — see Plan 12).
#[non_exhaustive]
#[derive(Debug, Clone, Default)]
pub struct RegenReport {
/// Number of memories successfully re-embedded.
pub processed: u64,
/// Number of memories skipped (e.g. already at target embedder).
pub skipped: u64,
/// Number of memories that failed to re-embed.
pub failed: u64,
/// Wall-clock duration in millis.
pub duration_ms: u64,
/// First 32 errors in `(subject_id, message)` form.
pub errors: Vec<(String, String)>,
}
/// Caller-tunable knobs on a future `Memory::gc(opts)` (deferred — see Plan 12).
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct GcOpts {
/// Retention window. Orphan blobs younger than `retain_for` are
/// preserved. Default 24 hours.
pub retain_for: Duration,
/// When `true`, returns the report without removing anything.
pub dry_run: bool,
}
impl Default for GcOpts {
fn default() -> Self {
Self {
retain_for: Duration::from_secs(24 * 3600),
dry_run: false,
}
}
}
impl GcOpts {
/// Set the retention window. Orphan blobs younger than `dur` are
/// preserved.
#[must_use]
pub fn with_retain_for(mut self, dur: Duration) -> Self {
self.retain_for = dur;
self
}
/// Toggle dry-run mode.
#[must_use]
pub fn with_dry_run(mut self, dry: bool) -> Self {
self.dry_run = dry;
self
}
}
/// Report from a future `Memory::gc(opts)` (deferred — see Plan 12).
#[non_exhaustive]
#[derive(Debug, Clone, Default)]
pub struct GcReport {
/// Number of `data/` blobs reaped (or marked, if `dry_run`).
pub data_blobs_removed: u64,
/// Number of `metadata/<path>/summaries/` blobs reaped.
pub summary_blobs_removed: u64,
/// Number of orphan `metadata/snapshots/*.manifest.json` reaped.
pub manifest_blobs_removed: u64,
/// Total bytes freed.
pub bytes_freed: u64,
}