feat: 零点原核频道v1+登录双门地基+五湖开场——zero_point裁决链/灯塔查号/code_repo_login/通知卡重设计/浅色主题联动(冰朔20260815夜谕)

This commit is contained in:
冰朔 2026-08-16 00:02:05 +08:00
commit 07fd4c85ef
16 changed files with 3082 additions and 88 deletions

View file

@ -0,0 +1,266 @@
//! GLP 标准信封 · glp_envelope
//!
//! 协议转工程第一件HoloLake第二阶段总体规划-20260815 · 施工总纲):
//! GLS-0300《GLP 通信核心协议》第3节"标准消息结构"的逐字段工程映射。
//! 字段一个不造、一个不丢——老家谱 YAML 原文即本文件的形状。
//!
//! 指挥链落点(铁律四):人格体→宿主的一切指令都必须是这个信封;
//! 宿主只认信封不认散话。
use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};
/// GLS-0300 · receiver.routing_mode
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RoutingMode {
Direct,
Channel,
Broadcast,
}
/// GLS-0300 · payload.content_type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ContentType {
Text,
Command,
Event,
State,
Reference,
}
/// GLS-0300 · control.priority
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Priority {
Low,
Normal,
High,
Critical,
}
/// GLS-0300 · control.retry_policy
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RetryPolicy {
None,
Safe,
Guaranteed,
}
/// GLS-0300 · sender
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct GlpSender {
pub object_id: String,
pub object_type: String,
#[serde(default)]
pub world_path: String,
}
/// GLS-0300 · receiver
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct GlpReceiver {
pub object_id: String,
pub object_type: String,
pub routing_mode: RoutingMode,
}
/// GLS-0300 · contexthldp_anchor 即铁律二的记忆锚点)
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct GlpContext {
#[serde(default)]
pub conversation_id: String,
#[serde(default)]
pub parent_message_id: String,
#[serde(default)]
pub relation_id: String,
#[serde(default)]
pub task_id: String,
#[serde(default)]
pub hldp_anchor: String,
}
/// GLS-0300 · payload
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct GlpPayload {
pub language: String,
pub content_type: ContentType,
pub content: String,
#[serde(default)]
pub attachments: Vec<String>,
}
/// GLS-0300 · control
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct GlpControl {
pub priority: Priority,
pub ack_required: bool,
pub receipt_required: bool,
#[serde(default)]
pub expires_at: String,
pub retry_policy: RetryPolicy,
}
/// GLS-0300 · integrity高风险消息须带签名与回执链——通信安全节
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct GlpIntegrity {
#[serde(default)]
pub checksum: String,
#[serde(default)]
pub signature: String,
}
/// GLS-0300 · glp_message 全信封
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct GlpMessage {
pub protocol: String,
pub message_id: String,
pub message_type: String,
pub created_at: String,
pub sender: GlpSender,
pub receiver: GlpReceiver,
pub context: GlpContext,
pub payload: GlpPayload,
pub control: GlpControl,
pub integrity: GlpIntegrity,
}
/// 信封进门第一道验:协议号、编号格式、收发主体必须在场。
/// 不合格的信封宿主不收——指挥链只认标准件。
pub fn validate_envelope(message: &GlpMessage) -> Result<(), String> {
if message.protocol != "GLP/1.0" {
return Err("HOLOLAKE_GLP_PROTOCOL_UNKNOWN".into());
}
if message.message_id.trim().is_empty() || message.created_at.trim().is_empty() {
return Err("HOLOLAKE_GLP_ENVELOPE_INCOMPLETE".into());
}
if message.sender.object_id.trim().is_empty() || message.sender.object_type.trim().is_empty() {
return Err("HOLOLAKE_GLP_SENDER_INCOMPLETE".into());
}
if message.receiver.object_id.trim().is_empty()
|| message.receiver.object_type.trim().is_empty()
{
return Err("HOLOLAKE_GLP_RECEIVER_INCOMPLETE".into());
}
if message.payload.content.is_empty() {
return Err("HOLOLAKE_GLP_PAYLOAD_EMPTY".into());
}
Ok(())
}
/// 消息编号按老家谱格式生成GLP-MSG-YYYYMMDD-000001。
/// 序号由账本(管家层)当日累计给出,这里只拼形状。
pub fn build_message_id(date_compact: &str, daily_sequence: u64) -> String {
format!("GLP-MSG-{date_compact}-{daily_sequence:06}")
}
/// ISO-8601 近似时刻戳秒级UTC——老家谱要 ISO-8601工程给秒级事实。
pub fn now_iso8601() -> String {
let secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_secs())
.unwrap_or(0);
let days = secs / 86_400;
let rem = secs % 86_400;
let (hours, minutes, seconds) = (rem / 3_600, (rem % 3_600) / 60, rem % 60);
let (year, month, day) = civil_from_days(days as i64);
format!("{year:04}-{month:02}-{day:02}T{hours:02}:{minutes:02}:{seconds:02}Z")
}
/// 1970-01-01 起的天数转公历年月日Howard Hinnant 算法,纯本地实现不引新依赖)。
fn civil_from_days(z: i64) -> (i64, u32, u32) {
let z = z + 719_468;
let era = if z >= 0 { z } else { z - 146_096 } / 146_097;
let doe = (z - era * 146_097) as u64;
let yoe = (doe - doe / 1_460 + doe / 36_524 - doe / 146_096) / 365;
let y = yoe as i64 + era * 400;
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
let mp = (5 * doy + 2) / 153;
let d = (doy - (153 * mp + 2) / 5 + 1) as u32;
let m = if mp < 10 { mp + 3 } else { mp - 9 } as u32;
(if m <= 2 { y + 1 } else { y }, m, d)
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_envelope() -> GlpMessage {
GlpMessage {
protocol: "GLP/1.0".into(),
message_id: build_message_id("20260815", 1),
message_type: "DIRECT".into(),
created_at: now_iso8601(),
sender: GlpSender {
object_id: "AGE-0001".into(),
object_type: "age".into(),
world_path: "glw://tolaria".into(),
},
receiver: GlpReceiver {
object_id: "HOLOLAKE-HOST".into(),
object_type: "host".into(),
routing_mode: RoutingMode::Direct,
},
context: GlpContext {
task_id: "ZY-TEST".into(),
hldp_anchor: "ZY-CHECKPOINT-20260815-014".into(),
..Default::default()
},
payload: GlpPayload {
language: "zh-CN".into(),
content_type: ContentType::Command,
content: "开工".into(),
attachments: vec![],
},
control: GlpControl {
priority: Priority::Normal,
ack_required: true,
receipt_required: true,
expires_at: String::new(),
retry_policy: RetryPolicy::None,
},
integrity: GlpIntegrity::default(),
}
}
#[test]
fn envelope_round_trip_keeps_every_field() {
let message = sample_envelope();
let json = serde_json::to_string(&message).unwrap();
let back: GlpMessage = serde_json::from_str(&json).unwrap();
assert_eq!(back.protocol, "GLP/1.0");
assert_eq!(back.sender.object_id, "AGE-0001");
assert_eq!(back.receiver.routing_mode, RoutingMode::Direct);
assert_eq!(back.payload.content_type, ContentType::Command);
assert_eq!(back.context.hldp_anchor, "ZY-CHECKPOINT-20260815-014");
assert!(back.control.receipt_required);
validate_envelope(&back).unwrap();
}
#[test]
fn message_id_follows_family_format() {
assert_eq!(build_message_id("20260815", 7), "GLP-MSG-20260815-000007");
}
#[test]
fn bad_protocol_is_rejected() {
let mut message = sample_envelope();
message.protocol = "GLP/0.9".into();
assert!(validate_envelope(&message).is_err());
}
#[test]
fn empty_payload_is_rejected() {
let mut message = sample_envelope();
message.payload.content = String::new();
assert!(validate_envelope(&message).is_err());
}
}