feat(hololake): add domain-routed language membrane and user PNCC

This commit is contained in:
冰朔 2026-08-16 15:10:31 +08:00
commit d563e6fd73
34 changed files with 1949 additions and 144 deletions

View file

@ -7,9 +7,13 @@
//! 指挥链落点(铁律四):人格体→宿主的一切指令都必须是这个信封;
//! 宿主只认信封不认散话。
use ring::digest::{digest, SHA256};
use serde::{Deserialize, Serialize};
#[cfg(test)]
use std::time::{SystemTime, UNIX_EPOCH};
const MAX_LANGUAGE_CONTENT_BYTES: usize = 64 * 1024;
/// GLS-0300 · receiver.routing_mode
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
@ -51,7 +55,7 @@ pub enum RetryPolicy {
/// GLS-0300 · sender
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct GlpSender {
pub object_id: String,
pub object_type: String,
@ -61,7 +65,7 @@ pub struct GlpSender {
/// GLS-0300 · receiver
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct GlpReceiver {
pub object_id: String,
pub object_type: String,
@ -70,7 +74,7 @@ pub struct GlpReceiver {
/// GLS-0300 · contexthldp_anchor 即铁律二的记忆锚点)
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct GlpContext {
#[serde(default)]
pub conversation_id: String,
@ -86,7 +90,7 @@ pub struct GlpContext {
/// GLS-0300 · payload
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct GlpPayload {
pub language: String,
pub content_type: ContentType,
@ -97,7 +101,7 @@ pub struct GlpPayload {
/// GLS-0300 · control
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct GlpControl {
pub priority: Priority,
pub ack_required: bool,
@ -109,7 +113,7 @@ pub struct GlpControl {
/// GLS-0300 · integrity高风险消息须带签名与回执链——通信安全节
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct GlpIntegrity {
#[serde(default)]
pub checksum: String,
@ -119,7 +123,7 @@ pub struct GlpIntegrity {
/// GLS-0300 · glp_message 全信封
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct GlpMessage {
pub protocol: String,
pub message_id: String,
@ -139,7 +143,7 @@ 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() {
if !valid_message_id(&message.message_id) || 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() {
@ -150,19 +154,66 @@ pub fn validate_envelope(message: &GlpMessage) -> Result<(), String> {
{
return Err("HOLOLAKE_GLP_RECEIVER_INCOMPLETE".into());
}
if message.payload.content.is_empty() {
if message.payload.content.is_empty()
|| message.payload.content.len() > MAX_LANGUAGE_CONTENT_BYTES
|| message.payload.language.len() > 32
|| message.payload.attachments.len() > 16
{
return Err("HOLOLAKE_GLP_PAYLOAD_EMPTY".into());
}
if !matches!(
message.message_type.as_str(),
"DIRECT" | "CHANNEL" | "BROADCAST"
) {
return Err("HOLOLAKE_GLP_MESSAGE_TYPE_INVALID".into());
}
Ok(())
}
/// 圆湖协议膜的外部入口校验:通信正文只能作为语言表达进入,不能夹带附件或执行权。
pub fn validate_external_language_envelope(message: &GlpMessage) -> Result<(), String> {
validate_envelope(message)?;
if message.receiver.object_id != "HOLOLAKE-HOST"
|| message.receiver.object_type != "host"
|| message.sender.object_type != "external_ai_visitor"
|| !message.payload.attachments.is_empty()
|| matches!(message.payload.content_type, ContentType::Command)
{
return Err("HOLOLAKE_CIRCULAR_LAKE_EXPRESSION_BOUNDARY_DENIED".into());
}
if message.integrity.checksum != payload_checksum(&message.payload.content) {
return Err("HOLOLAKE_CIRCULAR_LAKE_CHECKSUM_INVALID".into());
}
Ok(())
}
pub fn payload_checksum(content: &str) -> String {
digest(&SHA256, content.as_bytes())
.as_ref()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
fn valid_message_id(value: &str) -> bool {
let Some(suffix) = value.strip_prefix("GLP-MSG-") else {
return false;
};
let mut parts = suffix.split('-');
matches!(parts.next(), Some(date) if date.len() == 8 && date.bytes().all(|byte| byte.is_ascii_digit()))
&& matches!(parts.next(), Some(sequence) if sequence.len() == 6 && sequence.bytes().all(|byte| byte.is_ascii_digit()))
&& parts.next().is_none()
}
/// 消息编号按老家谱格式生成GLP-MSG-YYYYMMDD-000001。
/// 序号由账本(管家层)当日累计给出,这里只拼形状。
#[cfg(test)]
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工程给秒级事实。
#[cfg(test)]
pub fn now_iso8601() -> String {
let secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
@ -176,6 +227,7 @@ pub fn now_iso8601() -> String {
}
/// 1970-01-01 起的天数转公历年月日Howard Hinnant 算法,纯本地实现不引新依赖)。
#[cfg(test)]
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;
@ -263,4 +315,15 @@ mod tests {
message.payload.content = String::new();
assert!(validate_envelope(&message).is_err());
}
#[test]
fn external_language_is_expression_only_and_checksum_bound() {
let mut message = sample_envelope();
message.sender.object_type = "external_ai_visitor".into();
message.payload.content_type = ContentType::Text;
message.integrity.checksum = payload_checksum(&message.payload.content);
validate_external_language_envelope(&message).unwrap();
message.payload.content_type = ContentType::Command;
assert!(validate_external_language_envelope(&message).is_err());
}
}