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
146
147
148
149
150
151
152
153
154
//! Boot-side first-run scaffold of the user-level server config.
//!
//! Config LOAD is pure — discovery never creates anything (pinned by
//! `load_home_tests::unconfigured_paths_resolve_under_home_without_eager_creation`).
//! The scaffold therefore lives on the BOOT path: when discovery has found no
//! config at any layer, the server writes `<AION_HOME>/config.toml` from the
//! embedded template and loads again, so a first run boots with the deploy
//! surface and the outbox worker channel commissioned instead of dark.
use info;
use crateServerError;
use LoadedConfig;
use ;
/// The embedded first-run configuration: the exact bytes a first boot with no
/// discovered config writes to `<AION_HOME>/config.toml`.
///
/// Public so the `aion` launcher can recognise a config its spawned server
/// just scaffolded (byte comparison) instead of guessing from existence.
///
/// One truth, two crates: everything from the first section header onward
/// must stay byte-identical to `crates/aion-cli/templates/shared/aion.toml`
/// (the server config `aion new` scaffolds into a project) — only the leading
/// comment block differs, because each file speaks from its own seat. Each
/// crate embeds a copy living inside its own package because an
/// `include_str!` that escapes the crate breaks crates.io publishing (#173);
/// the identity is pinned by
/// `tests::the_embedded_template_matches_the_shared_cli_template`.
pub const FIRST_RUN_CONFIG: &str = include_str!;
/// What became of `<AION_HOME>/config.toml` when the scaffold ran.
pub
/// Load the merged server config, healing the discovered file's required
/// fields first and scaffolding `<AION_HOME>/config.toml` when discovery
/// finds no config at any layer.
///
/// The heal (ruled 2026-08-25, [`super::heal`]) runs BEFORE the merged load,
/// against exactly the file the load will read: a config from an older
/// version that lacks a newly-required field gets the field's declared
/// default inserted in place — previous file preserved beside it — instead of
/// refusing the boot at the door. A complete config passes byte-untouched. A
/// heal that cannot write refuses the boot; the server never proceeds on a
/// config it knows is missing required fields.
///
/// `BuiltInDefaults` is the only source that scaffolds: an explicit `--config`
/// naming a missing file has already refused inside [`ServerConfig::load_resolved`],
/// so a typo can never be papered over with a fresh file, and any discovered
/// file — explicit, project-local, or home — is used as-is.
///
/// # Errors
///
/// Returns [`ServerError::Config`] when the heal cannot write a needed fix,
/// when loading fails, or when the Aion home cannot be provisioned for the
/// scaffold write.
pub
/// On non-Unix targets nothing is scaffolded: the server cannot verify or
/// install a private ACL on the home directory (see
/// [`super::ConfigResolution::ensure_private_home`]), so writing a config into
/// that unverifiable directory would act on exactly the authority the non-Unix
/// path refuses. What the boot does next depends on the home's provenance:
/// with `AION_HOME` explicitly set, `ensure_private_home` treats the home as
/// operator-provisioned and the server boots on built-in defaults — deploy
/// and the outbox stay dark until the operator writes a config; with a
/// derived home, the boot stops at that path's explicit-provisioning refusal.
/// Write `<home>/config.toml` from the embedded template, claiming only what
/// is absent.
///
/// The home directory itself is provisioned owner-only (the same
/// [`crate::filesystem::ConfinedDir`] provisioning `ensure_private_home`
/// performs moments later) and the file lands with owner-only mode. An
/// existing file — including one that appeared between discovery and this
/// write, from a racing boot or the operator's own hand — is never touched:
/// `create_new` refuses it and the refusal is the answer, mirroring the
/// claim-only-when-empty idiom of the embedded update-check install.
pub