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
//! Path encoding for invention task hierarchies.
//!
//! ── HOW FUNCTION NAMES IDENTIFY DESCENDANTS ─────────────────────────
//!
//! Every invention task gets a `name` of the form `<base-name>-<suffix>`
//! where `<suffix>` is the bijective base-255 encoding of the task's
//! position in the invention tree, rendered as base62. When a child
//! task is being created, `state::child_name` looks at the parent's
//! name, decides whether the trailing `-<segment>` is already a path
//! encoding, and either:
//!
//! - extends that path in place (real path detected), or
//! - appends a *new* path segment (no path detected; the segment
//! belongs to the user's original name, e.g. `-v`, `-vii`,
//! `-final`, `-prod`).
//!
//! ── THE INVARIANT YOU MUST NOT BREAK ────────────────────────────────
//!
//! A path suffix is **always exactly [`PATH_SUFFIX_LEN`] base62
//! characters**. Detection in `child_name` / `reindex_name` requires
//! BOTH:
//!
//! 1. the trailing `-<segment>` is exactly `PATH_SUFFIX_LEN` chars
//! long, AND
//! 2. it parses successfully via [`b62_to_path`] (i.e. it is valid
//! base62 AND decodes to a structurally valid path).
//!
//! Both conditions are required. Length alone isn't enough — a 6-char
//! string with a non-base62 character would falsely qualify. A
//! successful parse alone isn't enough — that's the bug that ate
//! `-v` and `-vii` (both happily decode as base62 integers and then
//! as paths, because every `[1, MAX]` u128 round-trips back into
//! `Vec<u64>`).
//!
//! ── THINGS YOU (FUTURE CLAUDE) MUST NEVER DO ────────────────────────
//!
//! * DO NOT change `path_to_b62` to pad / fix-width / left-pad with
//! zeros / append marker chars / use a sigil. The encoder is
//! stable and produces variable-length raw base62 on purpose.
//! Existing function names in the wild were written with this
//! encoder; changing it desynchronizes detection from generation.
//! * DO NOT switch from base62 to hex / base32 / base64 / decimal /
//! anything else. The detection check assumes base62 alphabet.
//! * DO NOT change [`PATH_SUFFIX_LEN`] casually. It is part of the
//! on-the-wire convention.
//! * DO NOT add a separate "discriminator" character (like a
//! leading `_` or doubled `--`) to disambiguate path suffixes.
//! The length+alphabet check is the discriminator.
//! * DO NOT relax the detection: removing either the length check
//! or the parse check brings back the `-v` / `-vii` bug.
//!
//! If a future requirement seems to demand changing any of the above,
//! stop and write up the full implication chain (existing names,
//! external readers, JSON schemas, agent prompts, mock data) before
//! touching this file.
use Display;
impl_path_element!;
const MAX_LEN: usize = 16;
const MAX_VAL: u128 = 254;
/// The on-the-wire length, in base62 characters, of a path suffix in a
/// function name. Detection (in `state::child_name` /
/// `state::reindex_name`) requires the trailing `-<segment>` to be
/// **exactly this many** characters before even attempting to parse it
/// as a path. See the module docs for the full invariant.
pub const PATH_SUFFIX_LEN: usize = 6;
/// Bijective base-255 encoding: each value v is stored as v+1 (digits 1-255).
/// Since there is no zero digit, different-length paths always produce
/// different u128 values (e.g. [] → 0, [0] → 1, [0,0] → 256).