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
//! Length, size and count ceilings enforced on stored data.
//!
//! Split out of the former single-file `constants.rs` in v1.2.5;
//! every item is re-exported by the parent module, so `crate::constants::X`
//! resolves exactly as before.
/// Maximum byte length for a memory `name` field in kebab-case.
pub const MAX_MEMORY_NAME_LEN: usize = 80;
/// Maximum byte length for an `ingest`-derived kebab-case name.
///
/// Stricter than `MAX_MEMORY_NAME_LEN` (80) to leave headroom for collision
/// suffixes (`-2`, `-10`, ...) when multiple files derive to the same base.
/// Used exclusively by `src/commands/ingest.rs`.
pub const DERIVED_NAME_MAX_LEN: usize = 60;
/// Maximum character length for a memory `description` field.
pub const MAX_MEMORY_DESCRIPTION_LEN: usize = 500;
/// Hard upper bound on memory `body` length in bytes.
pub const MAX_MEMORY_BODY_LEN: usize = 512_000;
/// Body character count above which the body is split into chunks.
pub const MAX_BODY_CHARS_BEFORE_CHUNK: usize = 8_000;
/// Maximum length, in characters, of an `entities.type` label.
///
/// v1.2.8 opened the entity vocabulary: `type` is now free text and the SQL
/// `CHECK` that used to bound it is gone (V017). The only remaining guard is
/// shape, and this is its size half — it exists so a runaway LLM completion
/// cannot land a paragraph in a column meant to hold a word. Generous on
/// purpose: the longest canonical kind is `issue_tracker` at 13 characters.
pub const MAX_ENTITY_TYPE_LEN: usize = 64;
/// Default upper bound on distinct entities persisted per memory.
///
/// Bumped from 30 → 50 in v1.0.43 to reduce semantic loss on rich documents.
/// Configurable at runtime via XDG / runtime_config (not product env).
pub const MAX_ENTITIES_PER_MEMORY: usize = 50;
/// Resolves the per-memory entity cap (flag/XDG/`runtime_config`).
///
/// v1.0.43: makes the cap (default 50) configurable without product env.
/// Stress tests showed inputs with 33-46 candidates being truncated at the old cap of 30.
/// Values outside [1, 1000] fall back to the default.
/// Upper bound on distinct relationships persisted per memory.
pub const MAX_RELATIONSHIPS_PER_MEMORY: usize = 50;
/// Resolves the per-memory relationship cap (flag/XDG/`runtime_config`).
///
/// v1.0.22: makes the cap (default 50) configurable without product env.
/// Audit found that rich documents silently hit the cap; users with dense technical corpora
/// can raise it via XDG. Values outside [1, 10000] fall back to the default.
/// Character length of the description preview shown in `list` output.
pub const TEXT_DESCRIPTION_PREVIEW_LEN: usize = 100;
/// Chunk size expressed in tokens for body splitting.
pub const CHUNK_SIZE_TOKENS: usize = 400;
/// Token overlap between consecutive chunks.
pub const CHUNK_OVERLAP_TOKENS: usize = 50;
/// Explicit operational guard for multi-chunk documents in `remember`.
///
/// The multi-chunk path uses serial embeddings to avoid ONNX memory amplification.
/// This limit preserves a clear operational ceiling for agents and scripts.
pub const REMEMBER_MAX_SAFE_MULTI_CHUNKS: usize = 512;
/// Ceiling on chunks per controlled micro-batch in `remember`.
///
/// The `fastembed` runtime uses `BatchLongest` padding, so oversized batches amplify
/// the cost of the longest chunk. This ceiling keeps batches small even when chunks are short.
pub const REMEMBER_MAX_CONTROLLED_BATCH_CHUNKS: usize = 4;
/// Maximum padded-token budget per controlled micro-batch in `remember`.
///
/// The budget uses `max_tokens_no_batch * batch_size`, approximating the real cost of
/// `BatchLongest` padding. Values exceeding this fall back to smaller batches or serialisation.
pub const REMEMBER_MAX_CONTROLLED_BATCH_PADDED_TOKENS: usize = 512;
/// PRD-canonical regex that validates names and namespaces. Allows 1 char `[a-z0-9]`
/// OR a 2-80 char string starting with a letter and ending with a letter/digit,
/// containing only `[a-z0-9-]`. Rejects the `__` prefix (internal reserved).
pub const NAME_SLUG_REGEX: &str = r"^[a-z][a-z0-9-]{0,78}[a-z0-9]$|^[a-z0-9]$";
static NAME_SLUG_RE: OnceLock = new;
/// Returns a reference to the compiled [`NAME_SLUG_REGEX`] pattern.
/// Compiled once on first call, cached via `OnceLock`.
// expect_used (audited v1.0.97): NAME_SLUG_REGEX is a const literal; a parse
// failure would be a compile-reproducible bug, never a runtime condition.
/// Default retention period (days) used by `purge` when `--retention-days` is omitted.
pub const PURGE_RETENTION_DAYS_DEFAULT: u32 = 90;
/// Maximum number of simultaneously active namespaces (deleted_at IS NULL). Exit 5 when exceeded.
pub const MAX_NAMESPACES_ACTIVE: u32 = 100;
/// Byte budget for one auto-split partition (sub-memory) in `ingest`
/// (GAP-SG-04/07).
///
/// Chosen below the 127 KB body margin so each partition also stays under
/// [`REMEMBER_MAX_SAFE_MULTI_CHUNKS`] chunks and [`crate::constants::EMBEDDING_REQUEST_MAX_TOKENS`]
/// tokens, even for multibyte/CJK text (~1 cl100k token per UTF-8 char, so
/// 80 KiB / 3 bytes-per-char yields about 27K tokens, below the 30K ceiling).
pub const AUTOSPLIT_PARTITION_MAX_BYTES: usize = 80 * 1024;
/// Degree above which `health` reports an entity as a super-hub.
///
/// A hub this wide makes graph traversal fan out badly, so the check exists to
/// prompt a `prune-relations` or `merge-entities` pass.
pub const HEALTH_SUPER_HUB_DEGREE_THRESHOLD: i64 = 50;
/// How many super-hubs `health` names in its warning string.
///
/// This bounds the *sample* shown to a human. It must never bound the reported
/// count, which is measured separately over the whole graph.
pub const HEALTH_SUPER_HUB_SAMPLE_LIMIT: usize = 5;
/// Character size of the body preview emitted in text/markdown formats.
pub const TEXT_BODY_PREVIEW_LEN: usize = 200;