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
//! Palace-name validation against project-slug enforcement rules.
//!
//! Why: Isolating validation from detection and pin-file I/O keeps each file
//! under the 500-SLOC cap and allows the validation logic to be tested without
//! touching the filesystem walker.
//! What: `validate_palace_name` — the single gate that enforces "palace name
//! must match the derived slug (or be `personal`)".
//! Test: `validate_palace_name_accepts_personal`,
//! `validate_palace_name_accepts_matching_slug`,
//! `validate_palace_name_rejects_mismatch`,
//! `validate_palace_name_rejects_non_personal_without_project`.
use Result;
use Path;
use PERSONAL_PALACE;
use project_slug_at;
/// Validate a proposed palace name against project-slug enforcement rules.
///
/// Why: palace creation in MCP tool calls and HTTP handlers must apply the
/// same enforcement logic. Centralising the check here keeps the rule in one
/// place and makes it easy to write exhaustive unit tests.
/// What: returns `Ok(())` when the name is valid; returns `Err` with a
/// human-readable message when it is not. The rules are:
/// 1. `personal` is always valid (the escape hatch for non-project
/// contexts).
/// 2. When a project root is detectable from `cwd`, the name must equal
/// the derived slug.
/// 3. When no project root is detectable, only `personal` is allowed.
///
/// Existing palaces are **not** affected by this check; it applies only to
/// *new* palace creation requests.
/// Test: `validate_palace_name_accepts_personal`,
/// `validate_palace_name_accepts_matching_slug`,
/// `validate_palace_name_rejects_mismatch`,
/// `validate_palace_name_rejects_non_personal_without_project`.