Skip to main content

Mountain/
LandFixTier.rs

1//! # LandFixTier
2//!
3//! Emits a single ISO-timestamped boot banner listing the compiled-in value of
4//! every tier variable. Because all `env!("Tier…")` calls are resolved by
5//! `build.rs::PropagateTierGating` at compile time, the banner always reflects
6//! the exact configuration baked into *this* binary - not whatever the host
7//! environment happens to export at runtime.
8//!
9//! ## Design Rationale
10//!
11//! Three distinct audiences depend on this banner:
12//!
13//! | Audience | Why it matters |
14//! |---|---|
15//! | Log readers (humans) | A pasted session log must show at-a-glance which tier was active when the problem occurred. |
16//! | Regression triage | Confirms the binary on disk was built from the same `.env.Land` that shipped. |
17//! | Cross-element agreement | Pairs with Cocoon's `[LandFix:Tier] Cocoon tier set resolved:` and Sky's `[LandFix:Tier] Sky tier set:`. A mismatch between any two signals configuration drift as the root cause. |
18//!
19//! ## Call Site
20//!
21//! `LogResolvedTiers()` is called unconditionally from
22//! `Binary::Main::Entry::Fn` before the Tokio runtime begins spawning tasks.
23//! `dev_log!` is synchronous, so the banner is guaranteed to land in the log
24//! before any extension code runs.
25//!
26//! Runtime overhead is zero - all `env!(...)` invocations become string
27//! literals at compile time and are inlined into a single write call.
28//!
29//! ## References
30//!
31//! See `Documentation/GitHub/Workflow/TierGatedImplementationSelection.md` for
32//! the end-to-end tier-gating workflow and the matching call sites in Cocoon,
33//! Wind, and Sky. Every capability listed in the boot banner maps to one or
34//! more `// Tier:<Capability>:<Value>` comments at its dispatch site.
35
36use crate::dev_log;
37
38/// Emits one ISO-timestamped line at boot listing the compiled-in value of all
39/// 17 build-baked tier variables + 1 runtime tier. Call once from
40/// `Binary::Main::Entry::Fn`, after the logging infrastructure is ready
41/// and before the Tokio runtime spawns any tasks.
42pub fn LogResolvedTiers() {
43	// Build-baked tiers use env!() - values are baked from .env.Land at build time.
44	dev_log!(
45		"lifecycle",
46		"[LandFix:Tier] Mountain tiers: RemoteProcedureCall={} HTTPProxy={} Logger={} FileSystem={} FindFiles={} \
47		 Glob={} FileWatcher={} SchemeAssets={} Configuration={} Diagnostics={} Clipboard={} OpenExternal={} \
48		 DocumentMirror={} ExtensionActivation={} ExtensionScan={} ModuleCache={} Telemetry={}",
49		env!("TierRemoteProcedureCall"),
50		env!("TierHTTPProxy"),
51		env!("TierLogger"),
52		env!("TierFileSystem"),
53		env!("TierFindFiles"),
54		env!("TierGlob"),
55		env!("TierFileWatcher"),
56		env!("TierSchemeAssets"),
57		env!("TierConfiguration"),
58		env!("TierDiagnostics"),
59		env!("TierClipboard"),
60		env!("TierOpenExternal"),
61		env!("TierDocumentMirror"),
62		env!("TierExtensionActivation"),
63		env!("TierExtensionScan"),
64		env!("TierModuleCache"),
65		env!("TierTelemetry"),
66	);
67
68	// Runtime-only tiers use std::env::var - readable without a rebuild.
69	// `env!()` baked the compile-time default; a shell `export TierX=Node`
70	// at launch overrides without requiring a new binary. mod.rs reads via
71	// the same fallback chain.
72	let IPC = std::env::var("TierIPC").unwrap_or_else(|_| env!("TierIPC", "Mountain").to_string());
73
74	let Terminal = std::env::var("TierTerminal").unwrap_or_else(|_| env!("TierTerminal", "Mountain").to_string());
75
76	let SCM = std::env::var("TierSCM").unwrap_or_else(|_| env!("TierSCM", "Mountain").to_string());
77
78	let Debug = std::env::var("TierDebug").unwrap_or_else(|_| env!("TierDebug", "Mountain").to_string());
79
80	let LanguageFeatures =
81		std::env::var("TierLanguageFeatures").unwrap_or_else(|_| env!("TierLanguageFeatures", "Mountain").to_string());
82
83	let Search = std::env::var("TierSearch").unwrap_or_else(|_| env!("TierSearch", "Mountain").to_string());
84
85	let OutputChannel =
86		std::env::var("TierOutputChannel").unwrap_or_else(|_| env!("TierOutputChannel", "Mountain").to_string());
87
88	let NativeHost = std::env::var("TierNativeHost").unwrap_or_else(|_| env!("TierNativeHost", "Mountain").to_string());
89
90	let TreeView = std::env::var("TierTreeView").unwrap_or_else(|_| env!("TierTreeView", "Mountain").to_string());
91
92	let Storage = std::env::var("TierStorage").unwrap_or_else(|_| env!("TierStorage", "Mountain").to_string());
93
94	let Model = std::env::var("TierModel").unwrap_or_else(|_| env!("TierModel", "Mountain").to_string());
95
96	let Tasks = std::env::var("TierTasks").unwrap_or_else(|_| env!("TierTasks", "Node").to_string());
97
98	let Auth = std::env::var("TierAuth").unwrap_or_else(|_| env!("TierAuth", "Node").to_string());
99
100	let Encryption = std::env::var("TierEncryption").unwrap_or_else(|_| env!("TierEncryption", "Mountain").to_string());
101
102	let ExtensionHost =
103		std::env::var("TierExtensionHost").unwrap_or_else(|_| env!("TierExtensionHost", "Process").to_string());
104
105	let WebSocket = std::env::var("TierWebSocket").unwrap_or_else(|_| env!("TierWebSocket", "Disabled").to_string());
106
107	let CommandEventBroadcast = std::env::var("TierCommandEventBroadcast")
108		.unwrap_or_else(|_| env!("TierCommandEventBroadcast", "Off").to_string());
109
110	dev_log!(
111		"lifecycle",
112		"[LandFix:Tier] Runtime: IPC={} Terminal={} SCM={} Debug={} LanguageFeatures={} Search={} OutputChannel={} \
113		 NativeHost={} TreeView={} Storage={} Model={} Tasks={} Auth={} Encryption={} ExtensionHost={} WebSocket={} \
114		 CommandEventBroadcast={}",
115		IPC,
116		Terminal,
117		SCM,
118		Debug,
119		LanguageFeatures,
120		Search,
121		OutputChannel,
122		NativeHost,
123		TreeView,
124		Storage,
125		Model,
126		Tasks,
127		Auth,
128		Encryption,
129		ExtensionHost,
130		WebSocket,
131		CommandEventBroadcast,
132	);
133}