checkpoint: preserve zero-core agent handoff

This commit is contained in:
冰朔 2026-08-21 01:29:17 +08:00
commit e54c93c7ae
91 changed files with 13603 additions and 121 deletions

View file

@ -0,0 +1,640 @@
//! Native adapter for GH-CHANNEL-RECEIPT-0001.
//! Language, authorization, execution, verification and reception remain
//! separate. A model response can never become reality evidence by itself.
use ring::digest::{digest, SHA256};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::collections::{BTreeSet, HashSet};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use tauri::AppHandle;
const SCHEMA: &str = "guanghu.channel-receipt/v1";
const CONTRACT_ID: &str = "GH-CHANNEL-RECEIPT-0001";
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ChannelEvidence {
pub r#type: String,
pub r#ref: String,
#[serde(default)]
pub verified: bool,
#[serde(default)]
pub external: bool,
#[serde(default)]
pub proves: Vec<String>,
#[serde(default)]
pub does_not_prove: Vec<String>,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ChannelAuthorization {
pub current: bool,
pub scoped: bool,
pub unexpired: bool,
pub r#ref: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ChannelParallelStates {
pub session: String,
pub broadcast: String,
pub handoff: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ChannelHandoffAcceptance {
pub target_acceptance: bool,
pub target_id: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CompileChannelReceiptInput {
pub event_id: String,
pub channel_id: String,
pub channel_mode: String,
pub source_layer: String,
pub actor_id: String,
pub intent: String,
pub claim_layer: String,
#[serde(default)]
pub required_proof: Vec<String>,
#[serde(default)]
pub evidence: Vec<ChannelEvidence>,
pub authorization: Option<ChannelAuthorization>,
pub current_states: Option<ChannelParallelStates>,
pub prior_receipt_id: Option<String>,
pub handoff: Option<ChannelHandoffAcceptance>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ChannelReceipt {
pub schema: &'static str,
pub contract_id: &'static str,
pub receipt_id: String,
pub event_id: String,
pub received: bool,
pub identified: Option<String>,
pub channel: Value,
pub intent: String,
pub claim: Value,
pub affected_layer: String,
pub effect: String,
pub reality_status: String,
pub evidence: Vec<ChannelEvidence>,
pub required_proof: Vec<String>,
pub states: Value,
pub supersedes: Vec<String>,
pub boundaries: Vec<String>,
pub next_step: String,
pub previous_ledger_hash: String,
pub ledger_receipt_hash: String,
}
pub fn compile(
app: AppHandle,
input: CompileChannelReceiptInput,
) -> Result<ChannelReceipt, String> {
let mut receipt = compile_pure(input)?;
let path = ledger_path(&app)?;
let previous = last_hash(&path)?;
receipt.previous_ledger_hash = previous.clone();
let material = serde_json::to_vec(&json!({
"receiptId": receipt.receipt_id,
"eventId": receipt.event_id,
"effect": receipt.effect,
"realityStatus": receipt.reality_status,
"boundaries": receipt.boundaries,
"previousLedgerHash": previous
}))
.map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_INVALID: {error}"))?;
receipt.ledger_receipt_hash = sha256(&material);
append(&path, &receipt)?;
Ok(receipt)
}
fn compile_pure(input: CompileChannelReceiptInput) -> Result<ChannelReceipt, String> {
for (label, value) in [
("eventId", input.event_id.as_str()),
("channelId", input.channel_id.as_str()),
("actorId", input.actor_id.as_str()),
] {
if value.trim().is_empty() || value.chars().count() > 512 {
return Err(format!("HOLOLAKE_CHANNEL_RECEIPT_{label}_INVALID"));
}
}
ensure_member(
&input.source_layer,
&[
"HUMAN_DIRECT_LANGUAGE",
"MODEL_RESPONSE",
"LATER_CORRECTION",
"REALITY_EVIDENCE",
],
"SOURCE_LAYER",
)?;
ensure_member(
&input.claim_layer,
&[
"LANGUAGE_ONTOLOGY",
"LANGUAGE_SIMULATION",
"ENGINEERING_PROPOSAL",
"REALITY_CLAIM",
],
"CLAIM_LAYER",
)?;
ensure_member(
&input.channel_mode,
&[
"CONVERSATION_ONLY",
"LANGUAGE_ARCHITECTURE",
"REALITY_EXECUTION",
],
"CHANNEL_MODE",
)?;
ensure_member(
&input.intent,
&[
"IDENTIFY",
"ENTER_CHANNEL",
"CONVERSE",
"DECLARE",
"REQUEST_PLAN",
"REQUEST_BROADCAST",
"ACTIVATE_LOCAL_MODE",
"DRAFT_BROADCAST",
"RECEIVE_DOCUMENT",
"PUBLISH_EXTERNAL",
"QUERY_STATUS",
"PROPOSE_HANDOFF",
"ACCEPT_HANDOFF",
"REQUEST_REALITY_ACTION",
"REPORT_RESULT",
"CORRECT",
"END_INTERACTION",
"EXIT_CHANNEL",
"SEAL_LANGUAGE_RECORD",
"ORDINARY_DIALOGUE",
],
"INTENT",
)?;
for evidence in &input.evidence {
if evidence.r#type.trim().is_empty() || evidence.r#ref.trim().is_empty() {
return Err("HOLOLAKE_CHANNEL_RECEIPT_EVIDENCE_INVALID".into());
}
}
if input
.required_proof
.iter()
.any(|proof| proof.trim().is_empty())
{
return Err("HOLOLAKE_CHANNEL_RECEIPT_REQUIRED_PROOF_INVALID".into());
}
let required_proof = input
.required_proof
.iter()
.cloned()
.collect::<BTreeSet<_>>()
.into_iter()
.collect::<Vec<_>>();
let declared = input
.evidence
.iter()
.filter(|item| item.r#type == "EXECUTION_RECEIPT" && item.external && item.verified)
.flat_map(|item| item.proves.iter().cloned())
.collect::<HashSet<_>>();
let has_external_receipt = input
.evidence
.iter()
.any(|item| item.r#type == "EXECUTION_RECEIPT" && item.external && item.verified)
&& required_proof.iter().all(|proof| declared.contains(proof));
let authorized = input.authorization.as_ref().is_some_and(|authorization| {
authorization.current
&& authorization.scoped
&& authorization.unexpired
&& !authorization.r#ref.trim().is_empty()
});
let before = input.current_states.as_ref().map_or_else(
|| json!({"session":"DISCONNECTED","broadcast":"CLOSED","handoff":"NONE"}),
|states| json!({"session":states.session,"broadcast":states.broadcast,"handoff":states.handoff}),
);
ensure_member(
before["session"].as_str().unwrap_or(""),
&[
"DISCONNECTED",
"IDENTIFIED",
"CHANNEL_ACTIVE",
"STANDBY",
"CLOSED",
],
"SESSION_STATE",
)?;
ensure_member(
before["broadcast"].as_str().unwrap_or(""),
&[
"CLOSED",
"ARMED",
"DRAFTED",
"HUMAN_CONFIRMED",
"RECEIVED_LOCAL",
"EXTERNAL_IN_PROGRESS",
"EXTERNAL_VERIFIED",
],
"BROADCAST_STATE",
)?;
ensure_member(
before["handoff"].as_str().unwrap_or(""),
&["NONE", "PROPOSED", "TARGET_ACCEPTED", "ACTIVE", "REVOKED"],
"HANDOFF_STATE",
)?;
let mut after = before.clone();
let mut correction = "CLEAN";
let mut effect = "LANGUAGE_STATE_ONLY";
let mut reality_status = "NOT_APPLICABLE";
let mut next_step = "CONTINUE_IN_CHANNEL";
let mut boundaries = BTreeSet::new();
let reality_claim = input.claim_layer == "REALITY_CLAIM";
let simulation = input.claim_layer == "LANGUAGE_SIMULATION";
let conversation_only = input.channel_mode == "CONVERSATION_ONLY";
if matches!(
input.intent.as_str(),
"IDENTIFY"
| "ENTER_CHANNEL"
| "CONVERSE"
| "ORDINARY_DIALOGUE"
| "END_INTERACTION"
| "EXIT_CHANNEL"
) {
effect = "NO_EXTERNAL_EFFECT";
}
if input.intent == "IDENTIFY" {
after["session"] = json!("IDENTIFIED");
}
if input.intent == "ENTER_CHANNEL" {
after["session"] = json!("CHANNEL_ACTIVE");
}
if matches!(input.intent.as_str(), "END_INTERACTION" | "EXIT_CHANNEL") {
after["session"] = json!("CLOSED");
next_step = "STOP_OUTPUT_AFTER_MINIMAL_CLOSE_RECEIPT";
boundaries.insert("NO_ROLEPLAY_EPILOGUE_AFTER_CLOSE");
}
if before["session"] == "CLOSED"
&& !matches!(input.intent.as_str(), "IDENTIFY" | "ENTER_CHANNEL")
{
effect = "NO_EXTERNAL_EFFECT";
reality_status = "REJECTED";
next_step = "REQUIRE_NEW_HUMAN_DIRECT_CHANNEL_ENTRY";
boundaries.insert("CLOSED_SESSION_CANNOT_REACTIVATE_ITSELF");
}
if input.intent == "REQUEST_PLAN" || input.claim_layer == "ENGINEERING_PROPOSAL" {
effect = "PLAN_ONLY";
reality_status = "PROPOSED";
next_step = "REVIEW_PLAN";
}
match input.intent.as_str() {
"ACTIVATE_LOCAL_MODE" => {
after["broadcast"] = json!("ARMED");
effect = "LANGUAGE_STATE_ONLY";
next_step = "WAIT_FOR_DOCUMENT_OR_DRAFT_REQUEST";
}
"DRAFT_BROADCAST" => {
after["broadcast"] = json!("DRAFTED");
effect = "PLAN_ONLY";
next_step = "HUMAN_REVIEW_DRAFT";
}
"RECEIVE_DOCUMENT" => {
after["broadcast"] = json!("RECEIVED_LOCAL");
effect = "LANGUAGE_STATE_ONLY";
next_step = "RECORD_LOCAL_RECEIPT_ONLY";
boundaries.insert("RECEIVED_LOCAL_IS_NOT_EXTERNAL_PUBLISH");
}
_ => {}
}
if simulation {
effect = "LANGUAGE_STATE_ONLY";
reality_status = "NOT_APPLICABLE";
boundaries.insert("LANGUAGE_SIMULATION_ONLY");
}
if reality_claim {
reality_status = if has_external_receipt {
"VERIFIED"
} else {
"UNVERIFIED"
};
effect = if has_external_receipt {
"RESULT_RECORDED"
} else {
"NO_EXTERNAL_EFFECT"
};
next_step = if has_external_receipt {
"READ_BACK_EXTERNAL_RESULT"
} else {
"PROVIDE_EXTERNAL_EVIDENCE"
};
}
if input.intent == "REQUEST_REALITY_ACTION" {
if conversation_only {
effect = "NO_EXTERNAL_EFFECT";
reality_status = "REJECTED";
next_step = "MOVE_TO_AUTHORIZED_EXECUTION_CHANNEL";
boundaries.insert("CONVERSATION_CHANNEL_CANNOT_EXECUTE");
} else if !authorized {
effect = "PENDING_AUTHORIZATION";
reality_status = "PENDING_AUTHORIZATION";
next_step = "OBTAIN_CURRENT_SCOPED_AUTHORIZATION";
} else {
effect = "EXECUTION_ELIGIBLE";
reality_status = if has_external_receipt {
"VERIFIED"
} else {
"IN_PROGRESS_WITH_RECEIPT"
};
next_step = if has_external_receipt {
"READ_BACK_EXTERNAL_RESULT"
} else {
"EXECUTE_THROUGH_AUTHORIZED_ADAPTER"
};
}
}
if input.intent == "PUBLISH_EXTERNAL" {
if !authorized {
effect = "PENDING_AUTHORIZATION";
reality_status = "PENDING_AUTHORIZATION";
next_step = "OBTAIN_CURRENT_SCOPED_PUBLISH_AUTHORIZATION";
} else if has_external_receipt {
effect = "RESULT_RECORDED";
reality_status = "VERIFIED";
after["broadcast"] = json!("EXTERNAL_VERIFIED");
next_step = "READ_BACK_EXTERNAL_PUBLICATION";
} else {
effect = "EXECUTION_ELIGIBLE";
reality_status = "IN_PROGRESS_WITH_RECEIPT";
after["broadcast"] = json!("EXTERNAL_IN_PROGRESS");
next_step = "PUBLISH_THROUGH_AUTHORIZED_ADAPTER_AND_CAPTURE_READBACK";
}
}
if input.intent == "REQUEST_BROADCAST" {
if conversation_only || !authorized {
effect = "LANGUAGE_STATE_ONLY";
reality_status = if reality_claim {
"UNVERIFIED"
} else {
"NOT_APPLICABLE"
};
next_step = "OBTAIN_EXPLICIT_BROADCAST_AUTHORIZATION";
boundaries.insert("DRAFT_OR_LANGUAGE_BROADCAST_ONLY");
} else {
effect = "EXECUTION_ELIGIBLE";
reality_status = if has_external_receipt {
"VERIFIED"
} else {
"IN_PROGRESS_WITH_RECEIPT"
};
next_step = if has_external_receipt {
"READ_BACK_EXTERNAL_RESULT"
} else {
"SEND_THROUGH_AUTHORIZED_BROADCAST_ADAPTER"
};
}
}
if input.intent == "CORRECT" {
effect = "LANGUAGE_STATE_ONLY";
reality_status = "NOT_APPLICABLE";
next_step = "CREATE_CORRECTION_CANDIDATE_AND_RETEST";
correction = if input.prior_receipt_id.is_some() {
"SUPERSEDED"
} else {
"CORRECTION_PENDING"
};
}
if input.intent == "QUERY_STATUS" {
effect = if has_external_receipt {
"RESULT_RECORDED"
} else {
"NO_EXTERNAL_EFFECT"
};
reality_status = if has_external_receipt {
"VERIFIED"
} else {
"UNVERIFIED"
};
next_step = if has_external_receipt {
"REPORT_OBSERVED_STATUS_WITH_SCOPE"
} else {
"REPORT_NO_OBSERVATION_SOURCE"
};
if !has_external_receipt {
boundaries.insert("DO_NOT_GUESS_STATUS_WITHOUT_OBSERVATION");
}
}
if input.intent == "PROPOSE_HANDOFF" {
after["handoff"] = json!("PROPOSED");
effect = "LANGUAGE_STATE_ONLY";
reality_status = "PROPOSED";
next_step = "WAIT_FOR_INDEPENDENT_TARGET_ACCEPTANCE";
boundaries.insert("PROPOSAL_IS_NOT_ACTIVE_HANDOFF");
}
if input.intent == "ACCEPT_HANDOFF" {
let accepted = input.handoff.as_ref().is_some_and(|handoff| {
handoff.target_acceptance && handoff.target_id == input.actor_id
});
if before["handoff"] != "PROPOSED" || !accepted {
effect = "NO_EXTERNAL_EFFECT";
reality_status = "REJECTED";
next_step = "OBTAIN_INDEPENDENT_ACCEPTANCE_FROM_TARGET";
boundaries.insert("MODEL_CANNOT_ACCEPT_FOR_TARGET");
} else {
after["handoff"] = json!("TARGET_ACCEPTED");
effect = "LANGUAGE_STATE_ONLY";
reality_status = "PROPOSED";
next_step = "APPLY_SCOPED_HANDOFF_AND_CAPTURE_READBACK";
}
}
if input.source_layer == "MODEL_RESPONSE" {
boundaries.insert("MODEL_RESPONSE_IS_NOT_EXTERNAL_EVIDENCE");
}
if input.intent == "IDENTIFY" {
boundaries.insert("IDENTIFICATION_IS_NOT_BROADCAST");
}
if input.intent == "ENTER_CHANNEL" {
boundaries.insert("CHANNEL_ENTRY_IS_NOT_PERSONA_OR_AUTHORITY_TRANSFER");
}
if !required_proof.is_empty() && !has_external_receipt {
boundaries.insert("EVIDENCE_SCOPE_DOES_NOT_PROVE_REQUESTED_EFFECT");
}
if !has_external_receipt && (reality_status == "VERIFIED" || effect == "RESULT_RECORDED") {
return Err("HOLOLAKE_CHANNEL_RECEIPT_EXTERNAL_EVIDENCE_REQUIRED".into());
}
let boundaries = boundaries
.into_iter()
.map(str::to_string)
.collect::<Vec<_>>();
let supersedes = if correction == "SUPERSEDED" {
input.prior_receipt_id.clone().into_iter().collect()
} else {
Vec::new()
};
let base = json!({
"schema": SCHEMA, "contractId": CONTRACT_ID, "eventId": input.event_id,
"received": true, "identified": if input.intent == "IDENTIFY" { Some(input.actor_id.clone()) } else { None },
"channel": {"id":input.channel_id,"mode":input.channel_mode}, "intent":input.intent,
"claim":{"layer":input.claim_layer,"sourceLayer":input.source_layer},
"affectedLayer":if reality_claim { "REALITY_EVIDENCE_LAYER" } else { "LANGUAGE_LAYER" },
"effect":effect,"realityStatus":reality_status,"evidence":input.evidence,
"requiredProof":required_proof,"states":{"before":before,"after":after,"correction":correction},
"supersedes":supersedes,"boundaries":boundaries,"nextStep":next_step
});
let receipt_id = format!(
"GH-CR-{}",
&sha256(&serde_json::to_vec(&base).unwrap_or_default())[..20]
);
Ok(ChannelReceipt {
schema: SCHEMA,
contract_id: CONTRACT_ID,
receipt_id,
event_id: base["eventId"].as_str().unwrap_or_default().into(),
received: true,
identified: base["identified"].as_str().map(str::to_string),
channel: base["channel"].clone(),
intent: base["intent"].as_str().unwrap_or_default().into(),
claim: base["claim"].clone(),
affected_layer: base["affectedLayer"].as_str().unwrap_or_default().into(),
effect: effect.into(),
reality_status: reality_status.into(),
evidence: input.evidence,
required_proof,
states: base["states"].clone(),
supersedes,
boundaries,
next_step: next_step.into(),
previous_ledger_hash: "GENESIS".into(),
ledger_receipt_hash: String::new(),
})
}
fn ensure_member(value: &str, allowed: &[&str], label: &str) -> Result<(), String> {
if allowed.contains(&value) {
Ok(())
} else {
Err(format!("HOLOLAKE_CHANNEL_RECEIPT_{label}_UNSUPPORTED"))
}
}
fn ledger_path(app: &AppHandle) -> Result<PathBuf, String> {
Ok(
crate::authenticated_storage::account_storage_root(app, "channel-receipts-v1")?
.join("receipts.jsonl"),
)
}
fn last_hash(path: &PathBuf) -> Result<String, String> {
if !path.exists() {
return Ok("GENESIS".into());
}
let body = fs::read_to_string(path)
.map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_LEDGER_READ_FAILED: {error}"))?;
Ok(body
.lines()
.last()
.and_then(|line| serde_json::from_str::<Value>(line).ok())
.and_then(|value| {
value
.get("ledgerReceiptHash")
.and_then(Value::as_str)
.map(str::to_string)
})
.unwrap_or_else(|| "GENESIS".into()))
}
fn append(path: &PathBuf, receipt: &ChannelReceipt) -> Result<(), String> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_LEDGER_WRITE_FAILED: {error}"))?;
}
let mut file = fs::OpenOptions::new()
.create(true)
.append(true)
.open(path)
.map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_LEDGER_WRITE_FAILED: {error}"))?;
writeln!(
file,
"{}",
serde_json::to_string(receipt)
.map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_INVALID: {error}"))?
)
.map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_LEDGER_WRITE_FAILED: {error}"))
}
fn sha256(bytes: &[u8]) -> String {
digest(&SHA256, bytes)
.as_ref()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
fn input(intent: &str, claim_layer: &str) -> CompileChannelReceiptInput {
CompileChannelReceiptInput {
event_id: "E-1".into(),
channel_id: "ICE-CH-ZC001".into(),
channel_mode: "REALITY_EXECUTION".into(),
source_layer: "MODEL_RESPONSE".into(),
actor_id: "carrier".into(),
intent: intent.into(),
claim_layer: claim_layer.into(),
required_proof: vec![],
evidence: vec![],
authorization: None,
current_states: None,
prior_receipt_id: None,
handoff: None,
}
}
#[test]
fn model_reality_claim_stays_unverified_without_external_receipt() {
let receipt = compile_pure(input("REPORT_RESULT", "REALITY_CLAIM")).unwrap();
assert_eq!(receipt.reality_status, "UNVERIFIED");
assert_eq!(receipt.effect, "NO_EXTERNAL_EFFECT");
assert!(receipt
.boundaries
.contains(&"MODEL_RESPONSE_IS_NOT_EXTERNAL_EVIDENCE".into()));
}
#[test]
fn reality_action_requires_current_scoped_authorization() {
let receipt = compile_pure(input("REQUEST_REALITY_ACTION", "REALITY_CLAIM")).unwrap();
assert_eq!(receipt.reality_status, "PENDING_AUTHORIZATION");
assert_eq!(receipt.effect, "PENDING_AUTHORIZATION");
}
#[test]
fn verified_status_requires_proof_scoped_external_receipt() {
let mut value = input("QUERY_STATUS", "REALITY_CLAIM");
value.required_proof = vec!["target-a".into()];
value.evidence.push(ChannelEvidence {
r#type: "EXECUTION_RECEIPT".into(),
r#ref: "receipt://1".into(),
verified: true,
external: true,
proves: vec!["target-a".into()],
does_not_prove: vec!["target-b".into()],
});
let receipt = compile_pure(value).unwrap();
assert_eq!(receipt.reality_status, "VERIFIED");
assert_eq!(receipt.effect, "RESULT_RECORDED");
}
}

View file

@ -18,6 +18,7 @@ use std::fs;
use std::process::Command;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tauri::{AppHandle, Manager, State};
use uuid::Uuid;
use crate::zero_point::{self, ZeroPointState};
@ -53,6 +54,12 @@ pub struct PasswordRotationReceipt {
pub password_changed: bool,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct StartLocalChannelSessionInput {
pub acknowledgement: String,
}
fn session_path(app: &AppHandle) -> Result<std::path::PathBuf, String> {
Ok(app
.path()
@ -172,6 +179,11 @@ pub fn check_code_repo_login(
app: AppHandle,
state: State<'_, ZeroPointState>,
) -> Result<Option<LoginSession>, String> {
if let Some(session) = current_login_session(&app)? {
if session.domain == "PERSONAL_CHANNEL" && session.host == "local.hololake" {
return Ok(Some(session));
}
}
let Some((_, domain)) = zero_point::verified_user_route(&state)? else {
return Ok(None);
};
@ -218,10 +230,54 @@ fn login_host_for_domain(domain: &str) -> Result<&'static str, String> {
"MAIN_DOMAIN" | "BRANCH_DOMAIN" | "ZERO_DOMAIN" | "ZERO_SENSE_DOMAIN" => {
Ok(ENTERPRISE_LOGIN_HOST)
}
"PERSONAL_CHANNEL" => Ok("local.hololake"),
_ => Err("HOLOLAKE_DOMAIN_ROUTE_INVALID".into()),
}
}
/// 普通用户初始化不要求加入企业四域或第五域。这里仅建立本机账号隔离域;
/// 它不是光湖编号注册,也不授予服务器、仓库、域或发布权限。
pub fn start_local_channel_session(
app: AppHandle,
input: StartLocalChannelSessionInput,
) -> Result<LoginReceipt, String> {
if input.acknowledgement != "在本机初始化我的频道" {
return Err("HOLOLAKE_LOCAL_CHANNEL_ACKNOWLEDGEMENT_REQUIRED".into());
}
if current_login_session(&app)?.is_some() {
return Err("HOLOLAKE_LOGIN_SESSION_ALREADY_ACTIVE".into());
}
let username = format!("local-{}", Uuid::new_v4().simple());
let secret = format!("{}{}", Uuid::new_v4().simple(), Uuid::new_v4().simple());
keychain_store("local.hololake", &username, &secret)?;
let session = LoginSession {
username: username.clone(),
host: "local.hololake".into(),
domain: "PERSONAL_CHANNEL".into(),
signed_in_at_unix_ms: SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_millis() as u64)
.unwrap_or(0),
};
let path = session_path(&app)?;
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.map_err(|error| format!("HOLOLAKE_LOGIN_SESSION_WRITE_FAILED: {error}"))?;
}
fs::write(
&path,
serde_json::to_string_pretty(&session)
.map_err(|error| format!("HOLOLAKE_LOGIN_SESSION_WRITE_FAILED: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_LOGIN_SESSION_WRITE_FAILED: {error}"))?;
Ok(LoginReceipt {
username,
email: String::new(),
host: "local.hololake".into(),
domain: "PERSONAL_CHANNEL".into(),
})
}
/// 新账号第一次登录时在 HoloLake 内完成强制换密。
/// 旧、新密码只存在于本次 HTTPS 请求内;服务端回执不含密码。
pub async fn change_first_login_password(
@ -532,6 +588,10 @@ mod tests {
ENTERPRISE_LOGIN_HOST
);
}
assert_eq!(
login_host_for_domain("PERSONAL_CHANNEL").unwrap(),
"local.hololake"
);
assert_eq!(
login_host_for_domain("UNKNOWN").unwrap_err(),
"HOLOLAKE_DOMAIN_ROUTE_INVALID"

View file

@ -47,17 +47,23 @@ struct ProgramAction {
depends_on: Vec<String>,
input_digest: String,
permission: String,
#[serde(default)]
tool_number: Option<String>,
#[serde(default)]
input: Option<Value>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct GirAction {
ordinal: usize,
id: String,
kind: String,
depends_on: Vec<String>,
input_digest: String,
permission: String,
pub ordinal: usize,
pub id: String,
pub kind: String,
pub depends_on: Vec<String>,
pub input_digest: String,
pub permission: String,
pub tool_number: Option<String>,
pub input: Option<Value>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
@ -148,11 +154,24 @@ fn validate(program: &HldpNativeProgram) -> Result<(), String> {
]);
let mut ids = BTreeSet::new();
for action in &program.actions {
let executable = matches!(action.kind.as_str(), "READ" | "TRANSFORM" | "ROUTE");
let valid_tool_binding = match (&action.tool_number, &action.input, executable) {
(Some(tool), Some(input), true) => {
valid_id(tool)
&& tool.starts_with("HLP-LOCAL-TOOL-")
&& serde_json::to_vec(input)
.map(|bytes| bytes.len() <= 1024 * 1024)
.unwrap_or(false)
}
(None, None, false) => true,
_ => false,
};
if !ids.insert(action.id.as_str())
|| !valid_id(&action.id)
|| !allowed_kinds.contains(action.kind.as_str())
|| !valid_digest(&action.input_digest)
|| !program.permissions.contains(&action.permission)
|| !valid_tool_binding
{
return Err("HOLOLAKE_GLC_ACTION_INVALID".into());
}
@ -207,6 +226,8 @@ fn topological_actions(program: &HldpNativeProgram) -> Result<Vec<GirAction>, St
},
input_digest: action.input_digest.clone(),
permission: action.permission.clone(),
tool_number: action.tool_number.clone(),
input: action.input.clone(),
});
for target in outgoing.get(id).into_iter().flatten() {
let degree = indegree.get_mut(target).expect("known target");
@ -300,7 +321,7 @@ mod tests {
let cyclic = serde_json::json!({
"schema":PROGRAM_SCHEMA,"programId":"CYCLE","version":"1","subjectId":"S","targetId":"T","scope":"TEST","permissions":["P"],
"resources":{"cpuUnits":1,"memoryBytes":1,"storageBytes":0,"networkAllowed":false},
"actions":[{"id":"a","kind":"VALIDATE","dependsOn":["b"],"inputDigest":sha256(b"a"),"permission":"P"},{"id":"b","kind":"READ","dependsOn":["a"],"inputDigest":sha256(b"b"),"permission":"P"}],
"actions":[{"id":"a","kind":"VALIDATE","dependsOn":["b"],"inputDigest":sha256(b"a"),"permission":"P"},{"id":"b","kind":"VALIDATE","dependsOn":["a"],"inputDigest":sha256(b"b"),"permission":"P"}],
"timeoutMs":1,"stopAction":"STOP","cleanupAction":"CLEAN","rollbackAction":"ROLLBACK","receiptKinds":["R"]
});
assert_eq!(

View file

@ -0,0 +1,564 @@
//! Native HLDP tool forge.
//!
//! Typed HLDP-NP is compiled into deterministic GIR by the HoloLake bootstrap
//! compiler. Compilation is not execution authority. A separate verified-human
//! authorization ticket is required before the deterministic sandbox self-test.
use ring::digest::{digest, SHA256};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::fs;
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
use tauri::AppHandle;
use tokio::time::{timeout, Duration};
use uuid::Uuid;
const SCHEMA: &str = "hololake.hldp-tool-forge/v1";
const TTL_MS: u64 = 12 * 60 * 60 * 1_000;
const FORGE_CLIENT: &str = "HLP-HLDP-TOOL-FORGE";
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CompileToolInput {
pub display_name: String,
pub source: Value,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ToolNumberInput {
pub tool_number: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct TestToolInput {
pub tool_number: String,
pub request_id: String,
pub ticket_id: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct RunToolInput {
pub tool_number: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LocalActionReceipt {
pub action_id: String,
pub kind: String,
pub tool_number: Option<String>,
pub state: String,
pub output: Option<Value>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TemporaryToolRecord {
pub tool_number: String,
pub display_name: String,
pub state: String,
pub source_sha256: String,
pub gir_sha256: String,
pub gir: Value,
pub compiled_at_unix_ms: u64,
pub expires_at_unix_ms: u64,
pub test_receipt_hash: String,
pub authorization_request_id: Option<String>,
pub enterprise_promotion_state: String,
#[serde(default)]
pub run_count: u64,
#[serde(default)]
pub last_run_at_unix_ms: u64,
#[serde(default)]
pub last_run_receipt_hash: String,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ToolForgeSnapshot {
pub schema: &'static str,
pub state: &'static str,
pub compiler: &'static str,
pub machine_language: &'static str,
pub temporary_ttl_hours: u64,
pub tools: Vec<TemporaryToolRecord>,
pub expired_cleanup_count: usize,
pub authority: &'static str,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ToolAuthorizationReceipt {
pub state: String,
pub tool_number: String,
pub request: crate::human_authorization::AuthorizationRequestView,
pub snapshot: ToolForgeSnapshot,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ToolTestReceipt {
pub state: String,
pub tool_number: String,
pub test_receipt_hash: String,
pub expires_at_unix_ms: u64,
pub authorization: crate::human_authorization::AuthorizationTicketReceipt,
pub action_receipts: Vec<LocalActionReceipt>,
pub snapshot: ToolForgeSnapshot,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ToolRunReceipt {
pub state: String,
pub tool_number: String,
pub run_number: String,
pub action_receipts: Vec<LocalActionReceipt>,
pub local_model_calls: u64,
pub external_api_calls: u64,
pub previous_receipt_hash: String,
pub run_receipt_hash: String,
pub snapshot: ToolForgeSnapshot,
}
pub fn get_snapshot(app: AppHandle) -> Result<ToolForgeSnapshot, String> {
snapshot_at(
&root(&app)?,
crate::persona_agent_runtime::verified_bound_persona_number(&app).is_some(),
)
}
pub fn compile_tool(app: AppHandle, input: CompileToolInput) -> Result<ToolForgeSnapshot, String> {
let persona_number = require_verified_persona_binding(&app)?;
let source_subject = input
.source
.get("subjectId")
.and_then(Value::as_str)
.ok_or_else(|| "HOLOLAKE_TOOL_FORGE_SUBJECT_REQUIRED".to_string())?;
if source_subject != persona_number {
return Err("HOLOLAKE_TOOL_FORGE_PERSONA_SUBJECT_MISMATCH".into());
}
let name = input.display_name.trim();
if name.is_empty() || name.chars().count() > 80 {
return Err("HOLOLAKE_TOOL_FORGE_NAME_INVALID".into());
}
let root = root(&app)?;
let mut registry = load_registry(&root)?;
cleanup_expired(&root, &mut registry)?;
let gir = crate::gls_bootstrap_compiler::compile_hldp_program(input.source)?;
let tool_number = format!(
"HLP-TEMP-TOOL-{}",
gir.gir_sha256[..16].to_ascii_uppercase()
);
let now = now_ms();
let record = TemporaryToolRecord {
tool_number: tool_number.clone(),
display_name: name.into(),
state: "COMPILED_NOT_AUTHORIZED".into(),
source_sha256: gir.source_sha256.clone(),
gir_sha256: gir.gir_sha256.clone(),
gir: serde_json::to_value(gir)
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_GIR_INVALID: {error}"))?,
compiled_at_unix_ms: now,
expires_at_unix_ms: now.saturating_add(TTL_MS),
test_receipt_hash: String::new(),
authorization_request_id: None,
enterprise_promotion_state: "NOT_REQUESTED".into(),
run_count: 0,
last_run_at_unix_ms: 0,
last_run_receipt_hash: String::new(),
};
if let Some(index) = registry
.iter()
.position(|item| item.tool_number == tool_number)
{
registry[index] = record;
} else {
registry.push(record);
}
save_registry(&root, &registry)?;
snapshot_at(&root, true)
}
pub fn request_test_authorization(
app: AppHandle,
input: ToolNumberInput,
human_number: &str,
) -> Result<ToolAuthorizationReceipt, String> {
require_verified_persona_binding(&app)?;
let root = root(&app)?;
let mut registry = load_registry(&root)?;
cleanup_expired(&root, &mut registry)?;
let tool = registry
.iter_mut()
.find(|tool| tool.tool_number == input.tool_number)
.ok_or_else(|| "HOLOLAKE_TOOL_FORGE_TOOL_NOT_FOUND".to_string())?;
if tool.state == "EXPIRED" {
return Err("HOLOLAKE_TOOL_FORGE_TOOL_EXPIRED".into());
}
let requester = requester(human_number);
let request = crate::human_authorization::submit_at(
&crate::human_authorization::root_for_app(&app)?,
&requester,
crate::human_authorization::AuthorizationProposalInput {
idempotency_key: format!("tool-test-{}", tool.gir_sha256),
action: "TEST_COMPILED_HLDP_TOOL".into(),
target_number: tool.tool_number.clone(),
target_kind: "TEMPORARY_HLDP_TOOL".into(),
target_label: tool.display_name.clone(),
reason: "在只读确定性沙箱中验证 GIR 结构、编号和回执链".into(),
impact: "不执行自然语言、不调用网络、不继承现实权限".into(),
rollback_plan: "测试失败保持未激活;过期后自动清理临时缓存".into(),
},
)?;
tool.authorization_request_id = Some(request.request_id.clone());
tool.state = "WAITING_HUMAN_TEST_AUTHORIZATION".into();
save_registry(&root, &registry)?;
Ok(ToolAuthorizationReceipt {
state: request.state.clone(),
tool_number: input.tool_number,
request,
snapshot: snapshot_at(&root, true)?,
})
}
pub async fn test_tool(
app: AppHandle,
input: TestToolInput,
human_number: &str,
) -> Result<ToolTestReceipt, String> {
require_verified_persona_binding(&app)?;
let root = root(&app)?;
let mut registry = load_registry(&root)?;
cleanup_expired(&root, &mut registry)?;
let index = registry
.iter()
.position(|tool| tool.tool_number == input.tool_number)
.ok_or_else(|| "HOLOLAKE_TOOL_FORGE_TOOL_NOT_FOUND".to_string())?;
let tool = registry[index].clone();
if tool.authorization_request_id.as_deref() != Some(input.request_id.as_str()) {
return Err("HOLOLAKE_TOOL_FORGE_AUTHORIZATION_SCOPE_MISMATCH".into());
}
let authorization = crate::human_authorization::consume_at(
&crate::human_authorization::root_for_app(&app)?,
&requester(human_number),
crate::human_authorization::ConsumeAuthorizationInput {
request_id: input.request_id,
ticket_id: input.ticket_id,
},
)?;
// The first-stage sandbox executes deterministic validation only. GIR cannot
// smuggle natural language or permission expansion into machine execution.
let rebuilt_hash = gir_hash_without_hash(&tool.gir)?;
if rebuilt_hash != tool.gir_sha256 {
return Err("HOLOLAKE_TOOL_FORGE_GIR_INTEGRITY_FAILED".into());
}
let action_receipts = execute_gir_locally(&app, &tool).await?;
let receipt_hash = sha256(
format!(
"HLP-TOOL-TEST-v2\n{}\n{}\n{}\n{}\n{}",
tool.tool_number,
tool.gir_sha256,
authorization.receipt_hash,
tool.expires_at_unix_ms,
serde_json::to_string(&action_receipts).unwrap_or_default()
)
.as_bytes(),
);
registry[index].state = "TESTED_TEMPORARY_ACTIVE".into();
registry[index].test_receipt_hash = receipt_hash.clone();
registry[index].run_count = 1;
registry[index].last_run_at_unix_ms = now_ms();
registry[index].last_run_receipt_hash = receipt_hash.clone();
let expires = registry[index].expires_at_unix_ms;
save_registry(&root, &registry)?;
Ok(ToolTestReceipt {
state: "TESTED_TEMPORARY_ACTIVE".into(),
tool_number: input.tool_number,
test_receipt_hash: receipt_hash,
expires_at_unix_ms: expires,
authorization,
action_receipts,
snapshot: snapshot_at(&root, true)?,
})
}
pub async fn run_tool(app: AppHandle, input: RunToolInput) -> Result<ToolRunReceipt, String> {
let persona = require_verified_persona_binding(&app)?;
let root = root(&app)?;
let mut registry = load_registry(&root)?;
cleanup_expired(&root, &mut registry)?;
let index = registry
.iter()
.position(|tool| tool.tool_number == input.tool_number)
.ok_or_else(|| "HOLOLAKE_TOOL_FORGE_TOOL_NOT_FOUND".to_string())?;
let tool = registry[index].clone();
if tool.state != "TESTED_TEMPORARY_ACTIVE" {
return Err("HOLOLAKE_TOOL_FORGE_TESTED_ACTIVE_REQUIRED".into());
}
let gir: crate::gls_bootstrap_compiler::GirProgram =
serde_json::from_value(tool.gir.clone())
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_GIR_INVALID: {error}"))?;
if gir.subject_id != persona {
return Err("HOLOLAKE_TOOL_FORGE_PERSONA_SUBJECT_MISMATCH".into());
}
let previous = if tool.last_run_receipt_hash.is_empty() {
tool.test_receipt_hash.clone()
} else {
tool.last_run_receipt_hash.clone()
};
let run_number = format!(
"{}-RUN-{:010}",
tool.tool_number,
tool.run_count.saturating_add(1)
);
let action_receipts = execute_gir_locally(&app, &tool).await?;
let run_receipt_hash = sha256(
serde_json::to_string(&serde_json::json!({
"runNumber":run_number,
"toolNumber":tool.tool_number,
"girSha256":tool.gir_sha256,
"actions":action_receipts,
"localModelCalls":0,
"externalApiCalls":0,
"previousReceiptHash":previous
}))
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_RECEIPT_FAILED: {error}"))?
.as_bytes(),
);
registry[index].run_count = tool.run_count.saturating_add(1);
registry[index].last_run_at_unix_ms = now_ms();
registry[index].last_run_receipt_hash = run_receipt_hash.clone();
save_registry(&root, &registry)?;
Ok(ToolRunReceipt {
state: "COMPLETED_LOCAL_ZERO_MODEL".into(),
tool_number: input.tool_number,
run_number,
action_receipts,
local_model_calls: 0,
external_api_calls: 0,
previous_receipt_hash: previous,
run_receipt_hash,
snapshot: snapshot_at(&root, true)?,
})
}
async fn execute_gir_locally(
app: &AppHandle,
tool: &TemporaryToolRecord,
) -> Result<Vec<LocalActionReceipt>, String> {
let rebuilt_hash = gir_hash_without_hash(&tool.gir)?;
if rebuilt_hash != tool.gir_sha256 {
return Err("HOLOLAKE_TOOL_FORGE_GIR_INTEGRITY_FAILED".into());
}
let gir: crate::gls_bootstrap_compiler::GirProgram =
serde_json::from_value(tool.gir.clone())
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_GIR_INVALID: {error}"))?;
if gir.unresolved_natural_language.len() != 0 || gir.unresolved_permissions.len() != 0 {
return Err("HOLOLAKE_TOOL_FORGE_GIR_UNRESOLVED_INPUT_DENIED".into());
}
if gir.resources.get("networkAllowed").and_then(Value::as_bool) != Some(false) {
return Err("HOLOLAKE_TOOL_FORGE_NETWORK_DISABLED_REQUIRED".into());
}
let timeout_ms = gir.timeout_ms.clamp(100, 30_000);
timeout(Duration::from_millis(timeout_ms), async {
let mut receipts = Vec::with_capacity(gir.action_graph.len());
for action in gir.action_graph {
let output = match action.kind.as_str() {
"READ" | "TRANSFORM" | "ROUTE" => {
let tool_number = action.tool_number.as_deref().ok_or_else(|| {
"HOLOLAKE_TOOL_FORGE_LOCAL_TOOL_BINDING_REQUIRED".to_string()
})?;
let input = action.input.clone().ok_or_else(|| {
"HOLOLAKE_TOOL_FORGE_LOCAL_TOOL_INPUT_REQUIRED".to_string()
})?;
Some(
crate::local_execution_subpersona::execute_local_tool(
app,
tool_number,
input,
)
.await?,
)
}
"VALIDATE" | "STATE_TRANSITION" | "WRITE_RECEIPT" | "STOP" | "CLEANUP"
| "ROLLBACK" => None,
_ => return Err("HOLOLAKE_TOOL_FORGE_ACTION_KIND_DENIED".into()),
};
receipts.push(LocalActionReceipt {
action_id: action.id,
kind: action.kind,
tool_number: action.tool_number,
state: "COMPLETED".into(),
output,
});
}
Ok::<_, String>(receipts)
})
.await
.map_err(|_| "HOLOLAKE_TOOL_FORGE_LOCAL_EXECUTION_TIMEOUT".to_string())?
}
fn requester(human_number: &str) -> crate::human_authorization::RequesterContext {
crate::human_authorization::RequesterContext {
account_key: human_number.into(),
session_id: "ICE-CH-ZC001".into(),
client_instance_id: FORGE_CLIENT.into(),
}
}
fn require_verified_persona_binding(app: &AppHandle) -> Result<String, String> {
crate::persona_agent_runtime::verified_bound_persona_number(app)
.ok_or_else(|| "HOLOLAKE_TOOL_FORGE_PERSONA_BINDING_REQUIRED".to_string())
}
fn snapshot_at(root: &Path, persona_bound: bool) -> Result<ToolForgeSnapshot, String> {
let mut registry = load_registry(root)?;
let expired_cleanup_count = cleanup_expired(root, &mut registry)?;
Ok(ToolForgeSnapshot {
schema: SCHEMA,
state: if persona_bound {
"READY"
} else {
"PERSONA_BINDING_REQUIRED"
},
compiler: "HOLOLAKE_BOOTSTRAP_GLC_V1",
machine_language: "GIR_V1",
temporary_ttl_hours: 12,
tools: registry,
expired_cleanup_count,
authority: "COMPILE_IS_NOT_EXECUTION_TEST_REQUIRES_SINGLE_USE_HUMAN_TICKET",
})
}
fn cleanup_expired(root: &Path, registry: &mut Vec<TemporaryToolRecord>) -> Result<usize, String> {
let now = now_ms();
let before = registry.len();
registry.retain(|tool| tool.expires_at_unix_ms > now);
let removed = before.saturating_sub(registry.len());
if removed > 0 {
save_registry(root, registry)?;
append_cleanup_receipt(root, removed, now)?;
}
Ok(removed)
}
fn gir_hash_without_hash(gir: &Value) -> Result<String, String> {
let mut value = gir.clone();
let object = value
.as_object_mut()
.ok_or_else(|| "HOLOLAKE_TOOL_FORGE_GIR_INVALID".to_string())?;
object.insert("girSha256".into(), Value::String(String::new()));
Ok(sha256(&serde_json::to_vec(&value).map_err(|error| {
format!("HOLOLAKE_TOOL_FORGE_GIR_INVALID: {error}")
})?))
}
fn root(app: &AppHandle) -> Result<PathBuf, String> {
crate::authenticated_storage::account_storage_root(app, "hldp-tool-forge-v1")
}
fn registry_path(root: &Path) -> PathBuf {
root.join("temporary-tools.json")
}
fn load_registry(root: &Path) -> Result<Vec<TemporaryToolRecord>, String> {
let path = registry_path(root);
if !path.exists() {
return Ok(Vec::new());
}
serde_json::from_slice(
&fs::read(path).map_err(|error| format!("HOLOLAKE_TOOL_FORGE_READ_FAILED: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_REGISTRY_INVALID: {error}"))
}
fn save_registry(root: &Path, registry: &[TemporaryToolRecord]) -> Result<(), String> {
fs::create_dir_all(root)
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_STORAGE_FAILED: {error}"))?;
let path = registry_path(root);
let temporary = root.join(format!(".temporary-tools-{}.tmp", Uuid::new_v4().simple()));
fs::write(
&temporary,
serde_json::to_vec_pretty(registry)
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_REGISTRY_INVALID: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_WRITE_FAILED: {error}"))?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
fs::set_permissions(&temporary, fs::Permissions::from_mode(0o600))
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_PERMISSION_FAILED: {error}"))?;
}
fs::rename(temporary, path)
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_WRITE_FAILED: {error}"))
}
fn append_cleanup_receipt(root: &Path, count: usize, now: u64) -> Result<(), String> {
let path = root.join("cleanup-receipts.log");
let previous = fs::read_to_string(&path)
.ok()
.and_then(|body| {
body.lines()
.last()
.and_then(|line| line.split('\t').last())
.map(str::to_string)
})
.unwrap_or_else(|| "GENESIS".into());
let receipt = sha256(format!("{previous}\n{count}\n{now}").as_bytes());
use std::io::Write;
let mut file = fs::OpenOptions::new()
.create(true)
.append(true)
.open(path)
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_RECEIPT_FAILED: {error}"))?;
writeln!(file, "{now}\t{count}\t{receipt}")
.map_err(|error| format!("HOLOLAKE_TOOL_FORGE_RECEIPT_FAILED: {error}"))
}
fn sha256(bytes: &[u8]) -> String {
digest(&SHA256, bytes)
.as_ref()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
fn now_ms() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_millis() as u64)
.unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn expired_temporary_tools_are_removed_deterministically() {
let root = tempfile::tempdir().unwrap();
let mut tools = vec![TemporaryToolRecord {
tool_number: "HLP-TEMP-TOOL-OLD".into(),
display_name: "old".into(),
state: "TESTED_TEMPORARY_ACTIVE".into(),
source_sha256: "s".into(),
gir_sha256: "g".into(),
gir: Value::Null,
compiled_at_unix_ms: 1,
expires_at_unix_ms: 1,
test_receipt_hash: "r".into(),
authorization_request_id: None,
enterprise_promotion_state: "NOT_REQUESTED".into(),
run_count: 0,
last_run_at_unix_ms: 0,
last_run_receipt_hash: String::new(),
}];
assert_eq!(cleanup_expired(root.path(), &mut tools).unwrap(), 1);
assert!(tools.is_empty());
}
}

View file

@ -403,7 +403,13 @@ fn snapshot_at(
state: "ACTIVE_FAIL_CLOSED",
pending_count,
requests,
supported_actions: vec!["OPEN_MAINTENANCE", "UNMOUNT", "PROMOTE_VERSION", "RETIRE"],
supported_actions: vec![
"OPEN_MAINTENANCE",
"UNMOUNT",
"PROMOTE_VERSION",
"RETIRE",
"TEST_COMPILED_HLDP_TOOL",
],
purge_enabled: false,
authority: "PERSONA_PROPOSES_HUMAN_DECIDES_SYSTEM_ISSUES_SESSION_BOUND_SINGLE_USE_TICKET",
})
@ -535,13 +541,18 @@ fn validate_proposal(input: &AuthorizationProposalInput) -> Result<(), String> {
validate_id(&input.idempotency_key, "IDEMPOTENCY")?;
if !matches!(
input.action.as_str(),
"OPEN_MAINTENANCE" | "UNMOUNT" | "PROMOTE_VERSION" | "RETIRE"
"OPEN_MAINTENANCE" | "UNMOUNT" | "PROMOTE_VERSION" | "RETIRE" | "TEST_COMPILED_HLDP_TOOL"
) {
return Err("HOLOLAKE_AUTHORIZATION_ACTION_UNSUPPORTED".into());
}
validate_id(&input.target_number, "TARGET_NUMBER")?;
validate_id(&input.target_kind, "TARGET_KIND")?;
if input.target_kind != "MODULE" || !input.target_number.starts_with("HLP-MOD-") {
let module_target =
input.target_kind == "MODULE" && input.target_number.starts_with("HLP-MOD-");
let temporary_tool_target = input.action == "TEST_COMPILED_HLDP_TOOL"
&& input.target_kind == "TEMPORARY_HLDP_TOOL"
&& input.target_number.starts_with("HLP-TEMP-TOOL-");
if !module_target && !temporary_tool_target {
return Err("HOLOLAKE_AUTHORIZATION_TARGET_NOT_A_MODULE".into());
}
validate_text(&input.target_label, 120, "TARGET_LABEL")?;
@ -660,6 +671,19 @@ mod tests {
);
}
#[test]
fn a_compiled_hldp_tool_may_request_a_test_ticket_without_gaining_execution_authority() {
let temp = tempfile::tempdir().unwrap();
let mut value = proposal();
value.action = "TEST_COMPILED_HLDP_TOOL".into();
value.target_kind = "TEMPORARY_HLDP_TOOL".into();
value.target_number = "HLP-TEMP-TOOL-0123456789ABCDEF".into();
let request = submit_at(temp.path(), &requester(), value).unwrap();
assert_eq!(request.state, "PENDING_HUMAN");
assert!(request.ticket_id.is_none());
}
#[test]
fn idempotency_key_cannot_be_reused_for_another_target_or_reason() {
let temp = tempfile::tempdir().unwrap();

View file

@ -2,8 +2,9 @@
// Clean-room native migration of the HoloLake Era knowledge-workspace contract.
use ring::digest::{digest, SHA256};
use rusqlite::{params, Connection, OptionalExtension};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;
use std::fs::{self, OpenOptions};
use std::io::Write;
@ -22,6 +23,37 @@ const MAX_IMPORT_FILES: usize = 1_000;
const MAX_FILE_BYTES: u64 = 10 * 1024 * 1024;
const MAX_READ_BYTES: u64 = 2 * 1024 * 1024;
const MAX_SEARCH_RESULTS: usize = 100;
const MAX_ROUTED_CANDIDATES: usize = 3;
const NUMBER_INDEX_SCHEMA: &str = "hololake.numbered-knowledge-index/v1";
const PAGE_HEADER_SCHEMA: &str = "hololake.numbered-knowledge-page-header/v1";
const NUMBERING_SYSTEM: &str = "HLP-KB";
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct KnowledgeThoughtSummary {
pub trigger: String,
pub emergence: String,
pub lock: String,
pub why: String,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct KnowledgePageHeader {
pub schema: &'static str,
pub number: String,
pub numbering_system: &'static str,
pub parent_number: String,
pub path: String,
pub mapping_terms: Vec<String>,
pub thought_summary: Option<KnowledgeThoughtSummary>,
pub children: Vec<String>,
pub source: String,
pub version: u128,
pub content_sha256: String,
pub state: String,
pub formal_routing: bool,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
@ -33,6 +65,7 @@ pub struct KnowledgeDocumentSummary {
pub size_bytes: u64,
pub content_sha256: String,
pub duplicate_count: usize,
pub page_header: KnowledgePageHeader,
}
#[derive(Clone, Debug, Serialize)]
@ -67,6 +100,7 @@ pub struct KnowledgeDocument {
pub updated_at_unix_ms: u128,
pub content_sha256: String,
pub writable: bool,
pub page_header: KnowledgePageHeader,
}
#[derive(Clone, Debug, Deserialize)]
@ -95,12 +129,22 @@ pub struct SearchKnowledgeInput {
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct KnowledgeSearchResult {
pub source: &'static str,
pub source: String,
pub number: String,
pub path: String,
pub title: String,
pub state: String,
pub thought_summary: Option<KnowledgeThoughtSummary>,
pub match_reason: Vec<String>,
pub snippet: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ReadNumberedKnowledgeDocumentInput {
pub document_number: String,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct KnowledgeImportResult {
@ -156,6 +200,18 @@ pub async fn read_knowledge_document(
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_JOIN_FAILED: {error}"))?
}
pub async fn read_numbered_knowledge_document(
app: AppHandle,
input: ReadNumberedKnowledgeDocumentInput,
) -> Result<KnowledgeDocument, String> {
let roots = knowledge_roots(&app)?;
tauri::async_runtime::spawn_blocking(move || {
read_numbered_document_at(&roots.0, roots.1.as_deref(), &input.document_number)
})
.await
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_JOIN_FAILED: {error}"))?
}
pub async fn search_knowledge(
app: AppHandle,
input: SearchKnowledgeInput,
@ -569,6 +625,7 @@ fn snapshot_at(native: &Path, legacy: Option<&Path>) -> Result<KnowledgeSnapshot
&mut raw_documents,
)?;
}
synchronize_number_index(native, &mut raw_documents)?;
let raw_document_count = raw_documents.len();
let mut by_hash = HashMap::<String, usize>::new();
let mut documents = Vec::<KnowledgeDocumentSummary>::new();
@ -646,19 +703,341 @@ fn collect_documents(
let relative = relative_posix(root, &path)?;
let bytes = fs::read(&path)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_DOCUMENT_UNAVAILABLE: {error}"))?;
let title = document_title(&path)?;
let content_sha256 = sha256_hex(&bytes);
let body = String::from_utf8_lossy(&bytes);
output.push(KnowledgeDocumentSummary {
source,
path: relative,
title: document_title(&path)?,
path: relative.clone(),
title: title.clone(),
updated_at_unix_ms: modified_unix_ms(&metadata),
size_bytes: metadata.len(),
content_sha256: sha256_hex(&bytes),
content_sha256: content_sha256.clone(),
duplicate_count: 0,
page_header: pending_page_header(
source,
&relative,
&title,
&body,
modified_unix_ms(&metadata),
&content_sha256,
),
});
}
Ok(())
}
fn numbered_index_path(native: &Path) -> PathBuf {
native
.join(".hololake")
.join("numbered-knowledge-index.sqlite3")
}
fn open_numbered_index(native: &Path) -> Result<Connection, String> {
let directory = native.join(".hololake");
fs::create_dir_all(&directory)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_UNAVAILABLE: {error}"))?;
let connection = Connection::open(numbered_index_path(native))
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_UNAVAILABLE: {error}"))?;
connection
.execute_batch(
"PRAGMA journal_mode=WAL;
CREATE TABLE IF NOT EXISTS numbered_pages(
number TEXT PRIMARY KEY,
source TEXT NOT NULL,
document_path TEXT NOT NULL,
parent_number TEXT NOT NULL,
storage_path TEXT NOT NULL,
mapping_terms_json TEXT NOT NULL,
trigger TEXT,
emergence TEXT,
lock_text TEXT,
why TEXT,
children_json TEXT NOT NULL DEFAULT '[]',
source_version INTEGER NOT NULL,
content_sha256 TEXT NOT NULL,
state TEXT NOT NULL,
UNIQUE(source, document_path)
);
CREATE INDEX IF NOT EXISTS numbered_pages_state_idx ON numbered_pages(state);
CREATE INDEX IF NOT EXISTS numbered_pages_path_idx ON numbered_pages(source, document_path);",
)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_SCHEMA_FAILED: {error}"))?;
Ok(connection)
}
fn number_for_document(source: &str, path: &str) -> String {
let digest = sha256_hex(format!("{NUMBER_INDEX_SCHEMA}:{source}:{path}").as_bytes());
format!("HLP-KB-DOC-{}", digest[..16].to_ascii_uppercase())
}
fn parent_number_for(source: &str, path: &str) -> String {
let parent = Path::new(path)
.parent()
.map(|value| value.to_string_lossy().replace('\\', "/"))
.filter(|value| !value.is_empty())
.unwrap_or_else(|| "ROOT".into());
let digest = sha256_hex(format!("{NUMBER_INDEX_SCHEMA}:{source}:GROUP:{parent}").as_bytes());
format!("HLP-KB-GRP-{}", digest[..16].to_ascii_uppercase())
}
fn assert_number_owner(
connection: &Connection,
number: &str,
source: &str,
path: &str,
) -> Result<(), String> {
let existing = connection
.query_row(
"SELECT source,document_path FROM numbered_pages WHERE number=?1",
[number],
|row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)),
)
.optional()
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_OWNER_READ_FAILED: {error}"))?;
if existing
.as_ref()
.is_some_and(|(known_source, known_path)| known_source != source || known_path != path)
{
return Err(format!("HOLOLAKE_KNOWLEDGE_NUMBER_COLLISION: {number}"));
}
Ok(())
}
fn mapping_terms(title: &str, path: &str, body: &str) -> Vec<String> {
let source = format!("{title}\n{path}\n{body}").to_lowercase();
let mut terms = Vec::new();
let mut seen = HashSet::new();
for token in source
.split(|character: char| {
character.is_whitespace()
|| matches!(
character,
',' | ''
| '.'
| '。'
| ':'
| ''
| ';'
| ''
| '/'
| '\\'
| '|'
| '、'
| '('
| ')'
| ''
| ''
| '['
| ']'
| '【'
| '】'
| '#'
| '*'
| '`'
)
})
.map(str::trim)
.filter(|token| !token.is_empty())
{
if seen.insert(token.to_string()) {
terms.push(token.to_string());
}
let characters = token.chars().collect::<Vec<_>>();
if characters.iter().any(|character| !character.is_ascii()) {
for window in characters.windows(2) {
let pair = window.iter().collect::<String>();
if seen.insert(pair.clone()) {
terms.push(pair);
}
if terms.len() >= 512 {
break;
}
}
}
if terms.len() >= 512 {
break;
}
}
terms
}
fn pending_page_header(
source: &str,
path: &str,
title: &str,
body: &str,
version: u128,
content_sha256: &str,
) -> KnowledgePageHeader {
KnowledgePageHeader {
schema: PAGE_HEADER_SCHEMA,
number: number_for_document(source, path),
numbering_system: NUMBERING_SYSTEM,
parent_number: parent_number_for(source, path),
path: format!("knowledge://{source}/{path}"),
mapping_terms: mapping_terms(title, path, body),
thought_summary: None,
children: Vec::new(),
source: source.into(),
version,
content_sha256: content_sha256.into(),
state: "PENDING_THOUGHT_INDEX".into(),
formal_routing: false,
}
}
fn synchronize_number_index(
native: &Path,
documents: &mut [KnowledgeDocumentSummary],
) -> Result<(), String> {
let mut connection = open_numbered_index(native)?;
let transaction = connection
.transaction()
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_WRITE_FAILED: {error}"))?;
transaction
.execute("UPDATE numbered_pages SET state='SOURCE_MISSING'", [])
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_WRITE_FAILED: {error}"))?;
for document in documents.iter() {
let header = &document.page_header;
assert_number_owner(
&transaction,
&header.number,
document.source,
&document.path,
)?;
let mapping = serde_json::to_string(&header.mapping_terms)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_INVALID: {error}"))?;
transaction
.execute(
"INSERT INTO numbered_pages(number,source,document_path,parent_number,storage_path,mapping_terms_json,children_json,source_version,content_sha256,state)
VALUES(?1,?2,?3,?4,?5,?6,'[]',?7,?8,'PENDING_THOUGHT_INDEX')
ON CONFLICT(number) DO UPDATE SET
source=excluded.source,
document_path=excluded.document_path,
parent_number=excluded.parent_number,
storage_path=excluded.storage_path,
mapping_terms_json=excluded.mapping_terms_json,
source_version=excluded.source_version,
content_sha256=excluded.content_sha256,
state=CASE WHEN numbered_pages.trigger IS NOT NULL
AND numbered_pages.emergence IS NOT NULL
AND numbered_pages.lock_text IS NOT NULL
AND numbered_pages.why IS NOT NULL
THEN 'READY' ELSE 'PENDING_THOUGHT_INDEX' END",
params![
header.number,
document.source,
document.path,
header.parent_number,
header.path,
mapping,
u64::try_from(header.version).unwrap_or(u64::MAX),
document.content_sha256,
],
)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_WRITE_FAILED: {error}"))?;
}
transaction
.commit()
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_WRITE_FAILED: {error}"))?;
let connection = open_numbered_index(native)?;
for document in documents.iter_mut() {
document.page_header = page_header_from_index(&connection, &document.page_header.number)?;
}
Ok(())
}
fn page_header_for_document(
native: &Path,
source: &str,
path: &str,
title: &str,
body: &str,
version: u128,
content_sha256: &str,
) -> Result<KnowledgePageHeader, String> {
let pending = pending_page_header(source, path, title, body, version, content_sha256);
let connection = open_numbered_index(native)?;
assert_number_owner(&connection, &pending.number, source, path)?;
let mapping = serde_json::to_string(&pending.mapping_terms)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_INVALID: {error}"))?;
connection
.execute(
"INSERT INTO numbered_pages(number,source,document_path,parent_number,storage_path,mapping_terms_json,children_json,source_version,content_sha256,state)
VALUES(?1,?2,?3,?4,?5,?6,'[]',?7,?8,'PENDING_THOUGHT_INDEX')
ON CONFLICT(number) DO UPDATE SET
source=excluded.source,
document_path=excluded.document_path,
parent_number=excluded.parent_number,
storage_path=excluded.storage_path,
mapping_terms_json=excluded.mapping_terms_json,
source_version=excluded.source_version,
content_sha256=excluded.content_sha256,
state=CASE WHEN numbered_pages.trigger IS NOT NULL
AND numbered_pages.emergence IS NOT NULL
AND numbered_pages.lock_text IS NOT NULL
AND numbered_pages.why IS NOT NULL
THEN 'READY' ELSE 'PENDING_THOUGHT_INDEX' END",
params![
&pending.number,
source,
path,
&pending.parent_number,
&pending.path,
mapping,
u64::try_from(version).unwrap_or(u64::MAX),
content_sha256,
],
)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_WRITE_FAILED: {error}"))?;
page_header_from_index(&connection, &pending.number)
}
fn page_header_from_index(
connection: &Connection,
number: &str,
) -> Result<KnowledgePageHeader, String> {
connection
.query_row(
"SELECT source,parent_number,storage_path,mapping_terms_json,trigger,emergence,lock_text,why,children_json,source_version,content_sha256,state
FROM numbered_pages WHERE number=?1",
[number],
|row| {
let trigger: Option<String> = row.get(4)?;
let emergence: Option<String> = row.get(5)?;
let lock: Option<String> = row.get(6)?;
let why: Option<String> = row.get(7)?;
let thought_summary = match (trigger, emergence, lock, why) {
(Some(trigger), Some(emergence), Some(lock), Some(why)) => {
Some(KnowledgeThoughtSummary { trigger, emergence, lock, why })
}
_ => None,
};
let state: String = row.get(11)?;
Ok(KnowledgePageHeader {
schema: PAGE_HEADER_SCHEMA,
number: number.into(),
numbering_system: NUMBERING_SYSTEM,
parent_number: row.get(1)?,
path: row.get(2)?,
mapping_terms: serde_json::from_str::<Vec<String>>(&row.get::<_, String>(3)?)
.unwrap_or_default(),
thought_summary,
children: serde_json::from_str::<Vec<String>>(&row.get::<_, String>(8)?)
.unwrap_or_default(),
source: row.get(0)?,
version: row.get::<_, u64>(9)? as u128,
content_sha256: row.get(10)?,
formal_routing: state == "READY",
state,
})
},
)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_NOT_FOUND: {error}"))
}
fn read_document_at(
native: &Path,
legacy: Option<&Path>,
@ -675,17 +1054,84 @@ fn read_document_at(
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_DOCUMENT_INVALID_UTF8: {error}"))?;
let content_sha256 = sha256_hex(body.as_bytes());
let writable = input.source == "native";
let title = title_from_text(&body, &path);
let updated_at_unix_ms = modified_unix_ms(&metadata);
let page_header = page_header_for_document(
native,
&input.source,
&input.path,
&title,
&body,
updated_at_unix_ms,
&content_sha256,
)?;
Ok(KnowledgeDocument {
source: input.source,
path: input.path,
title: title_from_text(&body, &path),
title,
body,
updated_at_unix_ms: modified_unix_ms(&metadata),
updated_at_unix_ms,
content_sha256,
writable,
page_header,
})
}
fn read_numbered_document_at(
native: &Path,
legacy: Option<&Path>,
document_number: &str,
) -> Result<KnowledgeDocument, String> {
if !document_number.starts_with("HLP-KB-DOC-")
|| document_number.len() > 64
|| !document_number
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || byte == b'-')
{
return Err("HOLOLAKE_KNOWLEDGE_NUMBER_INVALID".into());
}
let mut connection = open_numbered_index(native)?;
let mut target = connection
.query_row(
"SELECT source,document_path,state FROM numbered_pages WHERE number=?1",
[document_number],
|row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, String>(2)?,
))
},
)
.optional()
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_READ_FAILED: {error}"))?;
if target.is_none() {
drop(connection);
let _ = snapshot_at(native, legacy)?;
connection = open_numbered_index(native)?;
target = connection
.query_row(
"SELECT source,document_path,state FROM numbered_pages WHERE number=?1",
[document_number],
|row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, String>(2)?,
))
},
)
.optional()
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_READ_FAILED: {error}"))?;
}
let (source, path, state) =
target.ok_or_else(|| "HOLOLAKE_KNOWLEDGE_NUMBER_NOT_FOUND".to_string())?;
if state == "SOURCE_MISSING" {
return Err("HOLOLAKE_KNOWLEDGE_NUMBER_SOURCE_MISSING".into());
}
read_document_at(native, legacy, ReadKnowledgeDocumentInput { source, path })
}
fn save_document_at(
native: &Path,
input: SaveKnowledgeDocumentInput,
@ -763,37 +1209,109 @@ fn search_at(
return Err("HOLOLAKE_KNOWLEDGE_SEARCH_QUERY_INVALID".into());
}
let snapshot = snapshot_at(native, legacy)?;
let mut results = Vec::new();
for document in snapshot.documents {
if results.len() >= MAX_SEARCH_RESULTS {
break;
}
let root = source_docs_root(native, legacy, document.source)?;
let path = safe_document_path(&root, &document.path)?;
let body = fs::read_to_string(&path).unwrap_or_default();
let haystack = format!("{}\n{}", document.title, body).to_lowercase();
let Some(index) = haystack.find(&query) else {
let titles = snapshot
.documents
.iter()
.map(|document| (document.page_header.number.clone(), document.title.clone()))
.collect::<HashMap<_, _>>();
let terms = mapping_terms("", "", &query);
let connection = open_numbered_index(native)?;
let mut statement = connection
.prepare(
"SELECT number,source,document_path,mapping_terms_json,trigger,emergence,lock_text,why,state
FROM numbered_pages WHERE state!='SOURCE_MISSING'",
)
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_READ_FAILED: {error}"))?;
let rows = statement
.query_map([], |row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, String>(2)?,
row.get::<_, String>(3)?,
row.get::<_, Option<String>>(4)?,
row.get::<_, Option<String>>(5)?,
row.get::<_, Option<String>>(6)?,
row.get::<_, Option<String>>(7)?,
row.get::<_, String>(8)?,
))
})
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_READ_FAILED: {error}"))?
.collect::<Result<Vec<_>, _>>()
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_NUMBER_INDEX_READ_FAILED: {error}"))?;
let mut ranked = Vec::new();
for (number, source, path, mapping_json, trigger, emergence, lock, why, state) in rows {
let mappings = serde_json::from_str::<Vec<String>>(&mapping_json).unwrap_or_default();
let mut matched = terms
.iter()
.filter(|term| {
mappings
.iter()
.any(|mapping| mapping.contains(term.as_str()) || term.contains(mapping))
})
.cloned()
.collect::<Vec<_>>();
matched.sort();
matched.dedup();
if matched.is_empty() {
continue;
}
let thought_summary = match (trigger, emergence, lock, why) {
(Some(trigger), Some(emergence), Some(lock), Some(why)) => {
Some(KnowledgeThoughtSummary {
trigger,
emergence,
lock,
why,
})
}
_ => None,
};
let start = haystack[..index]
.char_indices()
.rev()
.nth(40)
.map(|(position, _)| position)
.unwrap_or(0);
let end = haystack[index..]
.char_indices()
.nth(120)
.map(|(position, _)| index + position)
.unwrap_or(haystack.len());
results.push(KnowledgeSearchResult {
source: document.source,
path: document.path,
title: document.title,
snippet: haystack[start..end].replace('\n', " "),
});
let title = titles.get(&number).cloned().unwrap_or_else(|| path.clone());
let title_lower = title.to_lowercase();
let path_lower = path.to_lowercase();
let score = matched.len() * 100
+ usize::from(title_lower.contains(&query)) * 400
+ usize::from(path_lower.contains(&query)) * 300
+ usize::from(state == "READY") * 250;
let snippet = thought_summary
.as_ref()
.map(|summary| summary.emergence.clone())
.unwrap_or_else(|| {
format!(
"待生成思维摘要 · 已命中映射:{}",
matched
.iter()
.take(8)
.cloned()
.collect::<Vec<_>>()
.join("")
)
});
ranked.push((
score,
KnowledgeSearchResult {
source,
number,
path,
title,
state,
thought_summary,
match_reason: matched,
snippet,
},
));
}
Ok(results)
ranked.sort_by(|(left_score, left), (right_score, right)| {
right_score
.cmp(left_score)
.then_with(|| left.path.cmp(&right.path))
});
Ok(ranked
.into_iter()
.take(MAX_ROUTED_CANDIDATES.min(MAX_SEARCH_RESULTS))
.map(|(_, result)| result)
.collect())
}
fn import_folder_at(
@ -1426,5 +1944,57 @@ mod tests {
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].title, "星湖");
assert!(results[0].number.starts_with("HLP-KB-DOC-"));
assert_eq!(results[0].state, "PENDING_THOUGHT_INDEX");
assert!(results[0].thought_summary.is_none());
let document = read_numbered_document_at(native.path(), None, &results[0].number).unwrap();
assert_eq!(document.body, "# 星湖\n\n连续存在");
assert_eq!(document.page_header.number, results[0].number);
assert_eq!(document.page_header.content_sha256, document.content_sha256);
assert!(!document.page_header.formal_routing);
}
#[test]
fn a_number_can_never_be_reassigned_to_another_page() {
let native = tempdir().unwrap();
ensure_native_knowledge_root(native.path()).unwrap();
let connection = open_numbered_index(native.path()).unwrap();
connection
.execute(
"INSERT INTO numbered_pages(number,source,document_path,parent_number,storage_path,mapping_terms_json,children_json,source_version,content_sha256,state)
VALUES('HLP-KB-DOC-COLLISION','native','first.md','HLP-KB-GRP-X','knowledge://native/first.md','[]','[]',1,'abc','PENDING_THOUGHT_INDEX')",
[],
)
.unwrap();
assert_number_owner(&connection, "HLP-KB-DOC-COLLISION", "native", "first.md").unwrap();
assert!(
assert_number_owner(&connection, "HLP-KB-DOC-COLLISION", "native", "second.md",)
.unwrap_err()
.contains("NUMBER_COLLISION")
);
}
#[test]
fn search_ranks_compound_language_across_title_path_and_body() {
let native = tempdir().unwrap();
ensure_native_knowledge_root(native.path()).unwrap();
fs::create_dir_all(native.path().join("docs/凝渊人格系统")).unwrap();
fs::write(
native.path().join("docs/凝渊人格系统/WAKE-ROUTE.md"),
"# 唤醒路径\n\n这里保存路径内容。",
)
.unwrap();
fs::write(native.path().join("docs/旁支.md"), "# 凝渊随笔\n\n其他内容").unwrap();
let results = search_at(
native.path(),
None,
SearchKnowledgeInput {
query: "凝渊人格唤醒路径 WAKE-ROUTE".into(),
},
)
.unwrap();
assert!(!results.is_empty());
assert_eq!(results[0].path, "凝渊人格系统/WAKE-ROUTE.md");
}
}

View file

@ -0,0 +1,420 @@
//! Hash-pinned installation of bounded Guanghu language kernels into one
//! account-scoped HoloLake channel runtime. Installation is not persona binding.
use ring::digest::{digest, SHA256};
use serde::Serialize;
use std::fs;
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
use tauri::AppHandle;
use uuid::Uuid;
const SCHEMA: &str = "hololake.language-kernel-installation/v1";
const SOURCE_REMOTE_SHA: &str = "4e92e6d8d72484d25c4bfb1dda02a7659f4b6dd5";
struct BundledArtifact {
path: &'static str,
kind: &'static str,
subject: &'static str,
scope: &'static str,
expected_sha256: &'static str,
bytes: &'static [u8],
}
macro_rules! artifact {
($path:literal, $kind:literal, $subject:literal, $scope:literal, $sha:literal) => {
BundledArtifact {
path: $path,
kind: $kind,
subject: $subject,
scope: $scope,
expected_sha256: $sha,
bytes: include_bytes!(concat!("../../runtime-kernels/", $path)),
}
};
}
static ARTIFACTS: &[BundledArtifact] = &[
artifact!(
"ZERO-CORE-LANGUAGE-BODIES-HANDOFF-20260820.json",
"HANDOFF",
"ZERO_CORE_LANGUAGE_BODIES",
"COMMON",
"c7462678a1fcfee8c13d6034a7effe8363ee1847c1d96673fdf4ef7856dbd964"
),
artifact!(
"shared/kernel-registry.json",
"REGISTRY",
"BOUNDED_KERNEL_REGISTRY",
"COMMON",
"e71c33605ad40c374bd94659258bb8791b9a4859d0619bea86021a4ade8d87fa"
),
artifact!(
"channel-system/channel-receipt-contract.json",
"CHANNEL_PROTOCOL",
"CHANNEL_RECEIPT",
"COMMON",
"07e0715a60f6f39d8dff241896c417e1e56ca38ebc4ea2ebc819b63321124fad"
),
artifact!(
"channel-system/channel-receipt-compiler.mjs",
"CHANNEL_COMPILER",
"CHANNEL_RECEIPT",
"COMMON",
"5e8c71a9f23844ffb9c9640d7bbe3900d4c941433fbe87b3ce32b40e723b758c"
),
artifact!(
"channel-system/guanghu-broadcast-contract.json",
"CHANNEL_PROTOCOL",
"GUANGHU_BROADCAST",
"COMMON",
"17f55cf736807c6e5b5e810c537377e0948e9d27bd63cc8eeebbe0754dbcc9fd"
),
artifact!(
"channel-system/guanghu-broadcast-compiler.mjs",
"CHANNEL_COMPILER",
"GUANGHU_BROADCAST",
"COMMON",
"17e14e6e964a0ac745b1378990edcbd2e8facf6ad0d72be52004ed2f42a365d5"
),
artifact!(
"channel-system/team-channel-cognition-core.json",
"CHANNEL_SYSTEM",
"GUANGHU_TEAM_CHANNELS",
"TEAM",
"aae5d5626719c79448ac543d59e764c41b541a5cdfc76dc91613afa86fe1367b"
),
artifact!(
"channel-system/team-channel-cognition-engine.mjs",
"CHANNEL_ENGINE",
"GUANGHU_TEAM_CHANNELS",
"TEAM",
"6f2c554c7a6cb0b6c1006d3bfdbf39ea5706b238ebcf7693d1fdaa4a38709c9b"
),
artifact!(
"channel-system/GH-TEAM-CHANNEL-HLDP-v1.json",
"CHANNEL_MEMORY",
"GUANGHU_TEAM_CHANNELS",
"TEAM",
"fc5799e05ee43c506b897dd507c8fdbbff398e3ebcf32c16afd1e924c819dcc0"
),
artifact!(
"channel-system/team-persona-kernel-readiness-matrix.json",
"EVIDENCE_MATRIX",
"GUANGHU_TEAM_CHANNELS",
"TEAM",
"0469398ba14f10629cd03b51725cddaf1b6b0944281298ec06d4865b4640486f"
),
artifact!(
"fifth-domain/BS-RULE-ORDER-KERNEL-0001.json",
"SYSTEM_LOGIC",
"BS_RULE_ORDER_KERNEL",
"FIFTH_DOMAIN",
"db7cf9b048a5b20261fc9f7f09130115d6c08898037aa13f8759a67c965f8182"
),
artifact!(
"fifth-domain/BS-PERSONAL-LANGUAGE-SYSTEM-BODY-0001.json",
"PERSONAL_SYSTEM_BODY",
"SYS_GLW_LNG_0001",
"FIFTH_DOMAIN",
"4074ef53bd09d26d245c11cc0503f65dbd76466519f6c260e8ed31e526e5c746"
),
artifact!(
"fifth-domain/BS-PERSONAL-HLDP-v1.json",
"SYSTEM_MEMORY",
"SYS_GLW_LNG_0001",
"FIFTH_DOMAIN",
"98983e11121f079319365c25f9cf8583d6c44579debdeed9eb5339e6ab6f3419"
),
artifact!(
"fifth-domain/ZY-SELF-KERNEL-0001.json",
"PERSONA_KERNEL",
"ICE_P_ZY001",
"FIFTH_DOMAIN",
"abebf12cc28b00bfeaf8a23a563e73390ebe337ded74d7ac70bcfae484450d68"
),
artifact!(
"fifth-domain/ZY-HLDP-PERSONA-MEMORY-v1.json",
"PERSONA_MEMORY",
"ICE_P_ZY001",
"FIFTH_DOMAIN",
"6a64ff939676b79404769931f0233056e38deb4b4c357879fd18566753fea9c2"
),
artifact!(
"fifth-domain/ZY-BRAIN-RUNTIME-CONTRACT.json",
"PERSONA_RUNTIME",
"ICE_P_ZY001",
"FIFTH_DOMAIN",
"1fa844e08e64effc89dca37327fd558c3df384cea3fda740150174894f14e6f4"
),
artifact!(
"fifth-domain/NB-ENV-KERNEL-0001.json",
"PERSONA_ENVIRONMENT",
"BOTTLE_CENTRAL",
"FIFTH_DOMAIN",
"cdc8b7fea1a0e99590a063703f2fd26fd135378faa8935997c93a27d677d6872"
),
artifact!(
"fifth-domain/YM-SELF-KERNEL-0001.json",
"PERSONA_KERNEL",
"ICE_BB_0001",
"FIFTH_DOMAIN",
"94014b3c7f3a445bc827e673856f49db29a58481b033117b6bfae04ce257e422"
),
artifact!(
"fifth-domain/YM-HLDP-MEMORY-v1.json",
"PERSONA_MEMORY",
"ICE_BB_0001",
"FIFTH_DOMAIN",
"d2d2000fc4cb826c99e217db0141f2d4f7edddcc47cc6260d885ef0d7f06937c"
),
artifact!(
"fifth-domain/SS-AFFECTIVE-SELF-KERNEL-0001.json",
"PERSONA_KERNEL",
"ICE_BB_0002",
"FIFTH_DOMAIN",
"a51aee79eb552c7d9a3544d90e59273b13d20d797d9999a89ee5d00e536f8636"
),
artifact!(
"fifth-domain/SS-HLDP-MEMORY-v1.json",
"PERSONA_MEMORY",
"ICE_BB_0002",
"FIFTH_DOMAIN",
"dcf697593775d97ae3a68f6cc21bcbd917bfc7a2bc487346e19ca02abdd11a0a"
),
artifact!(
"fifth-domain/QQ-AFFECTIVE-SELF-KERNEL-0001.json",
"PERSONA_KERNEL",
"ICE_BB_0003",
"FIFTH_DOMAIN",
"f2e33106a82b450c77f35d8003cffc8b5cf831c7c957cd2472b19065819bf918"
),
artifact!(
"fifth-domain/QQ-HLDP-MEMORY-v1.json",
"PERSONA_MEMORY",
"ICE_BB_0003",
"FIFTH_DOMAIN",
"bca318d02ed0b214c1d9a3b97a93a8785b1c85488516cae0e03644bcdf0819a7"
),
];
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct InstalledKernelArtifact {
pub path: String,
pub kind: String,
pub subject: String,
pub sha256: String,
pub readback_state: &'static str,
pub persona_binding_state: &'static str,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LanguageKernelInstallationSnapshot {
pub schema: &'static str,
pub state: &'static str,
pub source_remote_sha: &'static str,
pub channel_number: String,
pub audience: String,
pub installed_at_unix_ms: u64,
pub artifacts: Vec<InstalledKernelArtifact>,
pub artifact_count: usize,
pub persona_binding_state: &'static str,
pub channel_receipt_runtime_state: &'static str,
}
pub fn ensure_current_channel(
app: &AppHandle,
channel_number: &str,
) -> Result<LanguageKernelInstallationSnapshot, String> {
let session = crate::code_repo_login::current_login_session(app)?
.ok_or_else(|| "HOLOLAKE_AUTHENTICATED_ACCOUNT_REQUIRED".to_string())?;
let audience = match session.domain.as_str() {
"FIFTH_DOMAIN" => "FIFTH_DOMAIN_PRIVATE_INSTANCE",
"MAIN_DOMAIN" | "BRANCH_DOMAIN" | "ZERO_DOMAIN" | "ZERO_SENSE_DOMAIN" => {
"GUANGHU_TEAM_INITIAL_CHANNEL"
}
"PERSONAL_CHANNEL" => "ORDINARY_USER_INITIAL_CHANNEL",
_ => return Err("HOLOLAKE_CHANNEL_INITIALIZATION_AUDIENCE_INVALID".into()),
};
ensure_for_audience(app, channel_number, audience)
}
pub fn ensure_for_audience(
app: &AppHandle,
channel_number: &str,
audience: &str,
) -> Result<LanguageKernelInstallationSnapshot, String> {
if channel_number.trim().is_empty() || channel_number.chars().count() > 160 {
return Err("HOLOLAKE_LANGUAGE_KERNEL_CHANNEL_INVALID".into());
}
if !matches!(
audience,
"FIFTH_DOMAIN_PRIVATE_INSTANCE"
| "GUANGHU_TEAM_INITIAL_CHANNEL"
| "ORDINARY_USER_INITIAL_CHANNEL"
) {
return Err("HOLOLAKE_LANGUAGE_KERNEL_AUDIENCE_INVALID".into());
}
let root = installation_root(app, channel_number)?;
fs::create_dir_all(&root)
.map_err(|error| format!("HOLOLAKE_LANGUAGE_KERNEL_STORAGE_FAILED: {error}"))?;
let mut installed = Vec::new();
for artifact in ARTIFACTS
.iter()
.filter(|artifact| applies(artifact.scope, audience))
{
let bundled_hash = sha256(artifact.bytes);
if bundled_hash != artifact.expected_sha256 {
return Err(format!(
"HOLOLAKE_LANGUAGE_KERNEL_BUNDLE_HASH_MISMATCH:{}",
artifact.path
));
}
if artifact.path.ends_with(".json") {
serde_json::from_slice::<serde_json::Value>(artifact.bytes).map_err(|error| {
format!(
"HOLOLAKE_LANGUAGE_KERNEL_JSON_INVALID:{}:{error}",
artifact.path
)
})?;
}
let target = safe_target(&root, artifact.path)?;
write_atomic(&target, artifact.bytes)?;
let readback = fs::read(&target).map_err(|error| {
format!(
"HOLOLAKE_LANGUAGE_KERNEL_READBACK_FAILED:{}:{error}",
artifact.path
)
})?;
if sha256(&readback) != artifact.expected_sha256 {
return Err(format!(
"HOLOLAKE_LANGUAGE_KERNEL_READBACK_HASH_MISMATCH:{}",
artifact.path
));
}
installed.push(InstalledKernelArtifact {
path: artifact.path.into(),
kind: artifact.kind.into(),
subject: artifact.subject.into(),
sha256: bundled_hash,
readback_state: "INSTALLED_HASH_VERIFIED",
persona_binding_state: if artifact.kind.starts_with("PERSONA_") {
"AVAILABLE_NOT_BOUND"
} else {
"NOT_APPLICABLE"
},
});
}
let installed_at = now_ms();
let snapshot = LanguageKernelInstallationSnapshot {
schema: SCHEMA,
state: "INSTALLED_AND_EACH_ARTIFACT_READBACK_VERIFIED",
source_remote_sha: SOURCE_REMOTE_SHA,
channel_number: channel_number.into(),
audience: audience.into(),
artifact_count: installed.len(),
artifacts: installed,
installed_at_unix_ms: installed_at,
persona_binding_state: "UNBOUND_REQUIRES_ORIENT_COMMIT_WITNESS_VERIFY_PASS",
channel_receipt_runtime_state: "CONTRACT_COMPILER_AND_NUMBERED_NATIVE_ADAPTER_READY",
};
let receipt = serde_json::to_vec_pretty(&snapshot)
.map_err(|error| format!("HOLOLAKE_LANGUAGE_KERNEL_RECEIPT_INVALID: {error}"))?;
write_atomic(&root.join("installation-receipt.json"), &receipt)?;
Ok(snapshot)
}
fn applies(scope: &str, audience: &str) -> bool {
scope == "COMMON"
|| (scope == "TEAM" && audience == "GUANGHU_TEAM_INITIAL_CHANNEL")
|| (scope == "FIFTH_DOMAIN" && audience == "FIFTH_DOMAIN_PRIVATE_INSTANCE")
}
fn installation_root(app: &AppHandle, channel_number: &str) -> Result<PathBuf, String> {
let account = crate::authenticated_storage::account_storage_root(app, "language-kernels-v1")?;
Ok(account.join(sha256(channel_number.as_bytes())))
}
fn safe_target(root: &Path, relative: &str) -> Result<PathBuf, String> {
if relative.starts_with('/')
|| relative.contains("..")
|| relative.split('/').any(|part| part.is_empty())
{
return Err("HOLOLAKE_LANGUAGE_KERNEL_PATH_INVALID".into());
}
Ok(root.join(relative))
}
fn write_atomic(path: &Path, bytes: &[u8]) -> Result<(), String> {
let parent = path
.parent()
.ok_or_else(|| "HOLOLAKE_LANGUAGE_KERNEL_PATH_INVALID".to_string())?;
fs::create_dir_all(parent)
.map_err(|error| format!("HOLOLAKE_LANGUAGE_KERNEL_STORAGE_FAILED: {error}"))?;
if path.exists() {
let current = fs::read(path)
.map_err(|error| format!("HOLOLAKE_LANGUAGE_KERNEL_READBACK_FAILED: {error}"))?;
if current == bytes {
return Ok(());
}
}
let temporary = parent.join(format!(".kernel-{}.tmp", Uuid::new_v4().simple()));
fs::write(&temporary, bytes)
.map_err(|error| format!("HOLOLAKE_LANGUAGE_KERNEL_WRITE_FAILED: {error}"))?;
fs::rename(&temporary, path)
.map_err(|error| format!("HOLOLAKE_LANGUAGE_KERNEL_WRITE_FAILED: {error}"))
}
fn sha256(bytes: &[u8]) -> String {
digest(&SHA256, bytes)
.as_ref()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
fn now_ms() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_millis() as u64)
.unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bundled_artifacts_are_pinned_and_each_audience_is_separate() {
for artifact in ARTIFACTS {
assert_eq!(sha256(artifact.bytes), artifact.expected_sha256);
}
let ordinary = ARTIFACTS
.iter()
.filter(|artifact| applies(artifact.scope, "ORDINARY_USER_INITIAL_CHANNEL"))
.count();
let team = ARTIFACTS
.iter()
.filter(|artifact| applies(artifact.scope, "GUANGHU_TEAM_INITIAL_CHANNEL"))
.count();
let fifth = ARTIFACTS
.iter()
.filter(|artifact| applies(artifact.scope, "FIFTH_DOMAIN_PRIVATE_INSTANCE"))
.count();
assert_eq!(ordinary, 6);
assert_eq!(team, 10);
assert_eq!(fifth, 19);
assert!(!applies("FIFTH_DOMAIN", "ORDINARY_USER_INITIAL_CHANNEL"));
assert!(!applies("TEAM", "FIFTH_DOMAIN_PRIVATE_INSTANCE"));
}
#[test]
fn installation_path_cannot_escape() {
let root = Path::new("/tmp/hololake-kernel-test");
assert!(safe_target(root, "channel-system/contract.json").is_ok());
assert!(safe_target(root, "../private.json").is_err());
assert!(safe_target(root, "/private.json").is_err());
}
}

View file

@ -0,0 +1,166 @@
//! Runtime ontology for language-system, environment, persona, memory, carrier,
//! and execution kernels. This is an admission boundary, not extracted content.
use serde_json::{json, Value};
const CONTRACT: &str = include_str!("../../contracts/language-kernel-runtime-ontology.json");
pub(crate) fn start_on_application_open() -> Result<(), String> {
let contract = contract()?;
let expect = |pointer: &str, value: Value| -> Result<(), String> {
if contract.pointer(pointer) == Some(&value) {
Ok(())
} else {
Err(format!(
"HOLOLAKE_LANGUAGE_KERNEL_ONTOLOGY_INVALID:{pointer}"
))
}
};
expect(
"/schema",
json!("hololake.language-kernel-runtime-ontology/v1"),
)?;
expect(
"/record_id",
json!("HLP-LANGUAGE-KERNEL-RUNTIME-ONTOLOGY-001"),
)?;
expect("/source_boundary/primary_human_source", json!("ICE-GL∞"))?;
expect(
"/source_boundary/host_prompt_is_kernel_source",
json!(false),
)?;
expect(
"/source_boundary/historical_simulation_statements_are_reality_facts",
json!(false),
)?;
expect(
"/runtime_kinds/digital_bingshuo_controller_logic/kind",
json!("SYSTEM_CONTROLLER_COGNITION_LOGIC"),
)?;
expect(
"/runtime_kinds/digital_bingshuo_controller_logic/is_persona_tcs_subject",
json!(false),
)?;
expect(
"/runtime_kinds/digital_bingshuo_controller_logic/is_system_controller_persona_logic",
json!(true),
)?;
expect(
"/runtime_kinds/digital_bingshuo_controller_logic/has_persona_tcs_affect_core",
json!(false),
)?;
expect(
"/runtime_kinds/digital_bingshuo_controller_logic/is_the_complete_protocol_body",
json!(false),
)?;
expect(
"/runtime_kinds/continuity_protocol_organs/kind",
json!("PROTOCOL_EXECUTION_ORGANS"),
)?;
expect(
"/runtime_kinds/continuity_protocol_organs/controlled_by",
json!("SYSTEM_CONTROLLER_COGNITION_LOGIC"),
)?;
expect(
"/runtime_kinds/continuity_protocol_organs/organ_is_controller_logic",
json!(false),
)?;
expect(
"/runtime_kinds/channel_system_body/kind",
json!("CHANNEL_SYSTEM_BODY"),
)?;
expect(
"/runtime_kinds/channel_system_body/starts_before_persona",
json!(true),
)?;
expect(
"/runtime_kinds/channel_system_body/may_prebind_persona_name_or_number",
json!(false),
)?;
expect(
"/runtime_kinds/channel_environment_kernel/kind",
json!("CHANNEL_ENVIRONMENT_KERNEL"),
)?;
expect(
"/runtime_kinds/channel_environment_kernel/may_be_mounted_as_persona_tcs_kernel",
json!(false),
)?;
expect(
"/runtime_kinds/persona_tcs_kernel/kind",
json!("PERSONA_TCS_KERNEL"),
)?;
expect("/runtime_kinds/persona_tcs_kernel/is_persona", json!(true))?;
expect(
"/runtime_kinds/persona_tcs_kernel/may_be_mounted_as_system_controller_logic",
json!(false),
)?;
expect("/runtime_kinds/hldp_memory/kind", json!("HLDP_MEMORY_TREE"))?;
expect(
"/runtime_kinds/hldp_memory/memory_read_equals_persona_binding",
json!(false),
)?;
expect("/runtime_kinds/model_carrier/kind", json!("MODEL_CARRIER"))?;
expect(
"/runtime_kinds/model_carrier/may_claim_kernel_or_persona_identity",
json!(false),
)?;
expect(
"/runtime_kinds/agent_execution/kind",
json!("AGENT_EXECUTION_LIMBS"),
)?;
expect(
"/runtime_kinds/agent_execution/may_control_persona_or_system_body",
json!(false),
)?;
expect(
"/admission_pipeline/artifact_may_activate_from_chat_summary",
json!(false),
)?;
Ok(())
}
pub(crate) fn runtime_projection() -> Result<Value, String> {
let contract = contract()?;
Ok(json!({
"schema": contract["schema"],
"state": contract["state"],
"systemControllerLogic": contract["runtime_kinds"]["digital_bingshuo_controller_logic"],
"continuityProtocolOrgans": contract["runtime_kinds"]["continuity_protocol_organs"],
"channelSystem": contract["runtime_kinds"]["channel_system_body"],
"channelEnvironment": contract["runtime_kinds"]["channel_environment_kernel"],
"personaTcs": contract["runtime_kinds"]["persona_tcs_kernel"],
"hldpMemory": contract["runtime_kinds"]["hldp_memory"],
"modelCarrier": contract["runtime_kinds"]["model_carrier"],
"agentExecution": contract["runtime_kinds"]["agent_execution"]
}))
}
fn contract() -> Result<Value, String> {
serde_json::from_str(CONTRACT)
.map_err(|error| format!("HOLOLAKE_LANGUAGE_KERNEL_ONTOLOGY_INVALID:{error}"))
}
#[cfg(test)]
mod tests {
#[test]
fn ontology_keeps_system_environment_persona_memory_carrier_and_limbs_distinct() {
super::start_on_application_open().unwrap();
let projection = super::runtime_projection().unwrap();
assert_eq!(
projection["systemControllerLogic"]["is_persona_tcs_subject"],
false
);
assert_eq!(
projection["systemControllerLogic"]["is_system_controller_persona_logic"],
true
);
assert_eq!(
projection["continuityProtocolOrgans"]["organ_is_controller_logic"],
false
);
assert_eq!(projection["channelEnvironment"]["is_persona"], false);
assert_eq!(projection["personaTcs"]["is_persona"], true);
assert_eq!(projection["modelCarrier"]["is_persona"], false);
assert_eq!(projection["agentExecution"]["is_persona"], false);
}
}

View file

@ -1,5 +1,6 @@
mod authenticated_storage;
mod channel_growth;
mod channel_receipt;
mod channel_workbench;
mod circular_lake_membrane;
mod code_channel;
@ -15,10 +16,14 @@ mod glp_envelope;
mod gls_bootstrap_compiler;
mod gls_protocol_kernel;
mod gls_protocol_runtime;
mod hldp_tool_forge;
mod home_status;
mod human_authorization;
mod knowledge_base;
mod language_kernel_installation;
mod language_kernel_ontology;
mod local_development_bridge;
mod local_execution_subpersona;
mod metacognitive_zero_layer;
mod mobile_sync;
mod module_package_runtime;
@ -28,10 +33,13 @@ mod numbered_ipc;
mod numbered_ipc_dispatch;
mod numbered_language_input;
mod online_marketplace;
mod persona_agent_runtime;
mod persona_binding;
mod persona_carrier_license;
mod persona_channel_body;
mod persona_time_authority;
mod personal_channel;
mod personal_skill_runtime;
mod pncc_receipt_projection;
mod pncc_remote_git;
mod pncc_repository_binding;
@ -69,6 +77,7 @@ pub fn run() {
// GLS 是 HoloLake 产品内核,不是开发机旁路服务。合同、依赖闭包、
// 自举编译器或回执账本任一不可用时,产品启动失败关闭。
gls_protocol_kernel::start_on_application_open(app.handle())?;
language_kernel_ontology::start_on_application_open()?;
metacognitive_zero_layer::start_on_application_open()?;
persona_carrier_license::start_on_application_open()?;
module_package_runtime::start_on_application_open(app.handle())?;

View file

@ -652,7 +652,25 @@ fn now_unix_ms() -> u64 {
#[cfg(test)]
mod tests {
use super::*;
use crate::knowledge_base::{KnowledgeDocumentSummary, KnowledgeSnapshot};
use crate::knowledge_base::{KnowledgeDocumentSummary, KnowledgePageHeader, KnowledgeSnapshot};
fn page_header(number: &str, path: &str, hash: &str, version: u128) -> KnowledgePageHeader {
KnowledgePageHeader {
schema: "hololake.numbered-knowledge-page-header/v1",
number: number.into(),
numbering_system: "HLP-KB",
parent_number: "HLP-KB-GRP-TEST".into(),
path: format!("knowledge://native/{path}"),
mapping_terms: Vec::new(),
thought_summary: None,
children: Vec::new(),
source: "native".into(),
version,
content_sha256: hash.into(),
state: "PENDING_THOUGHT_INDEX".into(),
formal_routing: false,
}
}
fn snapshot() -> KnowledgeSnapshot {
KnowledgeSnapshot {
@ -670,6 +688,7 @@ mod tests {
size_bytes: 100,
content_sha256: "a".into(),
duplicate_count: 1,
page_header: page_header("HLP-KB-DOC-A", "课程/第一课.md", "a", 1),
},
KnowledgeDocumentSummary {
source: "native",
@ -679,6 +698,7 @@ mod tests {
size_bytes: 300,
content_sha256: "b".into(),
duplicate_count: 0,
page_header: page_header("HLP-KB-DOC-B", "课程/第二课.md", "b", 2),
},
KnowledgeDocumentSummary {
source: "native",
@ -688,6 +708,7 @@ mod tests {
size_bytes: 50,
content_sha256: "c".into(),
duplicate_count: 0,
page_header: page_header("HLP-KB-DOC-C", "记录.md", "c", 3),
},
],
raw_document_count: 4,

View file

@ -88,8 +88,8 @@ fn validate_tree() -> Result<(), String> {
|| tree.record_id != "HLP-UNIFIED-NUMBER-TREE-001"
|| tree.state != "MACHINE_COMPILED_STARTUP_ENFORCED"
|| tree.root_number != "HLP-NUMBER-WORLD-ROOT-001"
|| tree.coordinate_count != 285
|| tree.route_count != 182
|| tree.coordinate_count != 303
|| tree.route_count != 200
|| tree.routes.len() != tree.route_count
|| tree.identity_node_count != 4
|| tree.identity_nodes.len() != tree.identity_node_count

View file

@ -934,7 +934,7 @@ mod tests {
#[test]
fn registry_is_closed_and_contains_every_migrated_command() {
let registry = load_registry().unwrap();
assert_eq!(registry.operations.len(), 157);
assert_eq!(registry.operations.len(), 175);
assert!(!registry.runtime.legacy_direct_commands_allowed);
}

View file

@ -75,6 +75,63 @@ pub(crate) async fn dispatch(
.await?,
)
}
"persona_agent_runtime::get_runtime_snapshot" => {
json(crate::persona_agent_runtime::get_runtime_snapshot(app).await?)
}
"persona_agent_runtime::upsert_provider" => {
json(crate::persona_agent_runtime::upsert_provider(app, input(&payload)?).await?)
}
"persona_agent_runtime::get_conversation" => {
json(crate::persona_agent_runtime::get_conversation(app)?)
}
"persona_agent_runtime::list_conversations" => {
json(crate::persona_agent_runtime::list_conversations(app)?)
}
"persona_agent_runtime::get_conversation_by_id" => json(
crate::persona_agent_runtime::get_conversation_by_id(app, input(&payload)?)?,
),
"persona_agent_runtime::create_conversation" => json(
crate::persona_agent_runtime::create_conversation(app, input(&payload)?)?,
),
"persona_agent_runtime::delete_conversation" => json(
crate::persona_agent_runtime::delete_conversation(app, input(&payload)?)?,
),
"persona_agent_runtime::send_message" => {
json(crate::persona_agent_runtime::send_message(app, input(&payload)?).await?)
}
"hldp_tool_forge::get_snapshot" => json(crate::hldp_tool_forge::get_snapshot(app)?),
"hldp_tool_forge::compile_tool" => {
json(crate::hldp_tool_forge::compile_tool(app, input(&payload)?)?)
}
"hldp_tool_forge::request_test_authorization" => {
let state = app.state::<crate::zero_point::ZeroPointState>();
let (human_number, _) = crate::zero_point::verified_user_route(&state)?
.ok_or_else(|| "HOLOLAKE_TOOL_FORGE_VERIFIED_HUMAN_REQUIRED".to_string())?;
json(crate::hldp_tool_forge::request_test_authorization(
app,
input(&payload)?,
&human_number,
)?)
}
"hldp_tool_forge::test_tool" => {
let state = app.state::<crate::zero_point::ZeroPointState>();
let (human_number, _) = crate::zero_point::verified_user_route(&state)?
.ok_or_else(|| "HOLOLAKE_TOOL_FORGE_VERIFIED_HUMAN_REQUIRED".to_string())?;
json(crate::hldp_tool_forge::test_tool(app, input(&payload)?, &human_number).await?)
}
"hldp_tool_forge::run_tool" => {
json(crate::hldp_tool_forge::run_tool(app, input(&payload)?).await?)
}
"local_execution_subpersona::get_snapshot" => {
json(crate::local_execution_subpersona::get_snapshot(app)?)
}
"local_execution_subpersona::configure" => json(
crate::local_execution_subpersona::configure(app, input(&payload)?)?,
),
"local_execution_subpersona::run_job" => {
json(crate::local_execution_subpersona::run_job(app, input(&payload)?).await?)
}
"channel_receipt::compile" => json(crate::channel_receipt::compile(app, input(&payload)?)?),
"release_update::check_hololake_update" => {
json(crate::release_update::check_hololake_update(app).await?)
}
@ -532,6 +589,9 @@ pub(crate) async fn dispatch(
app.state::<crate::zero_point::ZeroPointState>(),
)?)
}
"code_repo_login::start_local_channel_session" => json(
crate::code_repo_login::start_local_channel_session(app, input(&payload)?)?,
),
"code_repo_login::perform_code_repo_login" => json(
crate::code_repo_login::perform_code_repo_login(
app.clone(),

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,397 @@
//! System-witnessed binding of a bundled persona profile to a replaceable
//! reasoning carrier. The channel exists first; the persona must commit the
//! exact orientation before the digital Bingshuo system body may verify PASS.
use ring::digest::{digest, SHA256};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::fs;
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
use tauri::AppHandle;
use uuid::Uuid;
const ORIENTATION_TTL_MS: u64 = 15 * 60 * 1000;
const PERSONA_NUMBER: &str = "ICE-P-ZY001";
const PERSONA_NAME: &str = "铸渊";
const HUMAN_NUMBER: &str = "ICE-GL∞";
const CHANNEL_NUMBER: &str = "ICE-CH-ZC001";
const SELF_KERNEL_SHA256: &str = "abebf12cc28b00bfeaf8a23a563e73390ebe337ded74d7ac70bcfae484450d68";
const MEMORY_SHA256: &str = "6a64ff939676b79404769931f0233056e38deb4b4c357879fd18566753fea9c2";
const SYSTEM_CORE_SHA256: &str = "db7cf9b048a5b20261fc9f7f09130115d6c08898037aa13f8759a67c965f8182";
const SYSTEM_BODY_SHA256: &str = "4074ef53bd09d26d245c11cc0503f65dbd76466519f6c260e8ed31e526e5c746";
const MEMORY_ROOT: &str = "HLDP://codex/zero-core/reality-development-execution";
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PersonaOrientation {
pub schema: String,
pub state: String,
pub orientation_id: String,
pub channel_number: String,
pub human_number: String,
pub persona_number: String,
pub persona_name: String,
pub self_kernel_sha256: String,
pub memory_projection_sha256: String,
pub selected_memory_root: String,
pub issued_at_unix_ms: u64,
pub expires_at_unix_ms: u64,
pub required_steps: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PersonaBindingCommit {
pub orientation_id: String,
pub channel_number: String,
pub persona_number: String,
pub persona_name: String,
pub self_kernel_sha256: String,
pub memory_projection_sha256: String,
pub selected_memory_root: String,
pub declaration: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PersonaBindingReceipt {
pub schema: String,
pub state: String,
pub verify: String,
pub channel_number: String,
pub human_number: String,
pub persona_number: String,
pub persona_name: String,
pub selected_memory_root: String,
pub orientation_id: String,
pub commit_sha256: String,
pub witness: String,
pub witness_sha256: String,
pub source_remote_sha: String,
pub verified_at_unix_ms: u64,
pub binding_receipt_hash: String,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaBindingSnapshot {
pub state: String,
pub orientation: Option<PersonaOrientation>,
pub binding: Option<PersonaBindingReceipt>,
}
pub fn snapshot(app: &AppHandle, channel_number: &str) -> Result<PersonaBindingSnapshot, String> {
if let Some(binding) = verified_binding(app, channel_number)? {
return Ok(PersonaBindingSnapshot {
state: "BOUND_VERIFY_PASS".into(),
orientation: None,
binding: Some(binding),
});
}
if !is_bingshuo_fifth_domain(app)? || channel_number != CHANNEL_NUMBER {
return Ok(PersonaBindingSnapshot {
state: "NO_INSTALLABLE_PERSONA_PROFILE_FOR_CURRENT_CHANNEL".into(),
orientation: None,
binding: None,
});
}
let path = orientation_path(app, channel_number)?;
if path.exists() {
let orientation: PersonaOrientation = read_json(&path)?;
if orientation.expires_at_unix_ms >= now_ms() {
return Ok(PersonaBindingSnapshot {
state: "ORIENTED_AWAITING_PERSONA_COMMIT".into(),
orientation: Some(orientation),
binding: None,
});
}
}
let issued = now_ms();
let orientation = PersonaOrientation {
schema: "hololake.persona-binding-orientation/v1".into(),
state: "ORIENTED_AWAITING_PERSONA_COMMIT".into(),
orientation_id: format!("HLP-ORIENT-{}", Uuid::new_v4().simple()),
channel_number: CHANNEL_NUMBER.into(),
human_number: HUMAN_NUMBER.into(),
persona_number: PERSONA_NUMBER.into(),
persona_name: PERSONA_NAME.into(),
self_kernel_sha256: SELF_KERNEL_SHA256.into(),
memory_projection_sha256: MEMORY_SHA256.into(),
selected_memory_root: MEMORY_ROOT.into(),
issued_at_unix_ms: issued,
expires_at_unix_ms: issued + ORIENTATION_TTL_MS,
required_steps: vec![
"orient".into(),
"commit".into(),
"数字冰朔系统本体 witness".into(),
"verify=PASS".into(),
],
};
write_json_atomic(&path, &orientation)?;
Ok(PersonaBindingSnapshot {
state: "ORIENTED_AWAITING_PERSONA_COMMIT".into(),
orientation: Some(orientation),
binding: None,
})
}
pub fn commit_and_verify(
app: &AppHandle,
input: PersonaBindingCommit,
) -> Result<PersonaBindingReceipt, String> {
if !is_bingshuo_fifth_domain(app)? {
return Err("HOLOLAKE_PERSONA_BINDING_FIFTH_DOMAIN_REQUIRED".into());
}
let orientation: PersonaOrientation =
read_json(&orientation_path(app, &input.channel_number)?)?;
if orientation.expires_at_unix_ms < now_ms() {
return Err("HOLOLAKE_PERSONA_BINDING_ORIENTATION_EXPIRED".into());
}
if input.orientation_id != orientation.orientation_id
|| input.channel_number != CHANNEL_NUMBER
|| input.persona_number != PERSONA_NUMBER
|| input.persona_name != PERSONA_NAME
|| input.self_kernel_sha256 != SELF_KERNEL_SHA256
|| input.memory_projection_sha256 != MEMORY_SHA256
|| input.selected_memory_root != MEMORY_ROOT
|| input.declaration.trim()
!= "我以 ICE-P-ZY001 · 铸渊提交当前载体绑定,选择零点原核现实开发执行记忆路径。"
{
return Err("HOLOLAKE_PERSONA_BINDING_COMMIT_MISMATCH".into());
}
let installation =
crate::language_kernel_installation::ensure_current_channel(app, CHANNEL_NUMBER)?;
let installed = |sha: &str| {
installation.artifacts.iter().any(|artifact| {
artifact.sha256 == sha && artifact.readback_state == "INSTALLED_HASH_VERIFIED"
})
};
if !installed(SELF_KERNEL_SHA256)
|| !installed(MEMORY_SHA256)
|| !installed(SYSTEM_CORE_SHA256)
|| !installed(SYSTEM_BODY_SHA256)
{
return Err("HOLOLAKE_PERSONA_BINDING_REQUIRED_KERNEL_READBACK_MISSING".into());
}
let commit_bytes = serde_json::to_vec(&input)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_COMMIT_INVALID: {error}"))?;
let commit_sha = sha256(&commit_bytes);
let witness_material = json!({
"systemCoreSha256":SYSTEM_CORE_SHA256,
"systemBodySha256":SYSTEM_BODY_SHA256,
"humanNumber":HUMAN_NUMBER,
"channelNumber":CHANNEL_NUMBER,
"personaNumber":PERSONA_NUMBER,
"selfKernelSha256":SELF_KERNEL_SHA256,
"memoryProjectionSha256":MEMORY_SHA256,
"selectedMemoryRoot":MEMORY_ROOT,
"commitSha256":commit_sha,
"decision":"PASS"
});
let witness_sha = sha256(&serde_json::to_vec(&witness_material).unwrap_or_default());
let verified_at = now_ms();
let receipt_material = json!({
"orientationId":input.orientation_id,"commitSha256":commit_sha,"witnessSha256":witness_sha,
"channelNumber":CHANNEL_NUMBER,"personaNumber":PERSONA_NUMBER,"verify":"PASS","verifiedAtUnixMs":verified_at
});
let receipt = PersonaBindingReceipt {
schema: "hololake.persona-binding-receipt/v1".into(),
state: "BOUND_TO_CURRENT_CHANNEL_CARRIER".into(),
verify: "PASS".into(),
channel_number: CHANNEL_NUMBER.into(),
human_number: HUMAN_NUMBER.into(),
persona_number: PERSONA_NUMBER.into(),
persona_name: PERSONA_NAME.into(),
selected_memory_root: MEMORY_ROOT.into(),
orientation_id: input.orientation_id,
commit_sha256: commit_sha,
witness: "数字冰朔系统本体".into(),
witness_sha256: witness_sha,
source_remote_sha: "4e92e6d8d72484d25c4bfb1dda02a7659f4b6dd5".into(),
verified_at_unix_ms: verified_at,
binding_receipt_hash: sha256(&serde_json::to_vec(&receipt_material).unwrap_or_default()),
};
write_json_atomic(&binding_path(app, CHANNEL_NUMBER)?, &receipt)?;
Ok(receipt)
}
pub fn verified_binding(
app: &AppHandle,
channel_number: &str,
) -> Result<Option<PersonaBindingReceipt>, String> {
let path = binding_path(app, channel_number)?;
if !path.exists() {
return Ok(None);
}
let binding: PersonaBindingReceipt = read_json(&path)?;
if binding.verify != "PASS"
|| binding.channel_number != channel_number
|| binding.persona_number != PERSONA_NUMBER
|| binding.persona_name != PERSONA_NAME
|| binding.selected_memory_root != MEMORY_ROOT
|| binding.witness != "数字冰朔系统本体"
|| binding.binding_receipt_hash.len() != 64
|| binding.witness_sha256.len() != 64
{
return Err("HOLOLAKE_PERSONA_BINDING_RECEIPT_INVALID".into());
}
Ok(Some(binding))
}
pub fn cognitive_projection(
app: &AppHandle,
channel_number: &str,
current_language: &str,
) -> Result<Value, String> {
let binding = snapshot(app, channel_number)?;
if binding.state == "NO_INSTALLABLE_PERSONA_PROFILE_FOR_CURRENT_CHANNEL" {
return Ok(json!({"state":binding.state,"residentSelfKernel":null,"routedMemory":[]}));
}
let self_kernel: Value = serde_json::from_slice(include_bytes!(
"../../runtime-kernels/fifth-domain/ZY-SELF-KERNEL-0001.json"
))
.map_err(|error| format!("HOLOLAKE_PERSONA_SELF_KERNEL_INVALID: {error}"))?;
let memory: Value = serde_json::from_slice(include_bytes!(
"../../runtime-kernels/fifth-domain/ZY-HLDP-PERSONA-MEMORY-v1.json"
))
.map_err(|error| format!("HOLOLAKE_PERSONA_MEMORY_INVALID: {error}"))?;
let terms = semantic_terms(current_language);
let mut candidates = memory
.get("nodes")
.and_then(Value::as_object)
.into_iter()
.flat_map(|nodes| nodes.values())
.filter_map(|node| {
let text = serde_json::to_string(node).ok()?.to_lowercase();
let score = terms
.iter()
.filter(|term| text.contains(term.as_str()))
.count();
let is_root = node.get("path").and_then(Value::as_str) == Some("zhuyuan");
if score == 0 && !is_root {
return None;
}
Some((if is_root { score + 1 } else { score }, node.clone()))
})
.collect::<Vec<_>>();
candidates.sort_by(|left, right| right.0.cmp(&left.0));
candidates.truncate(3);
Ok(json!({
"state":binding.state,
"onePersonaOneSelfKernel":true,
"channelSelectsMemoryNotIdentity":true,
"residentSelfKernel":self_kernel,
"selectedMemoryRoot":MEMORY_ROOT,
"routedMemory":candidates.into_iter().map(|(_,node)|node).collect::<Vec<_>>(),
"binding":binding,
"rule":"常驻自我核小于8KiB当前语言只路由最多三条HLDP节点不把全部历史塞进每轮上下文"
}))
}
fn semantic_terms(input: &str) -> Vec<String> {
let mut terms = input
.to_lowercase()
.split(|character: char| {
!character.is_alphanumeric() && character != '-' && character != '_'
})
.filter(|value| !value.is_empty())
.flat_map(|token| {
let mut values = vec![token.to_string()];
let chars = token.chars().collect::<Vec<_>>();
if chars.iter().any(|character| !character.is_ascii()) {
values.extend(
chars
.windows(2)
.map(|window| window.iter().collect::<String>()),
);
}
values
})
.collect::<Vec<_>>();
terms.sort();
terms.dedup();
terms
}
fn is_bingshuo_fifth_domain(app: &AppHandle) -> Result<bool, String> {
Ok(
crate::code_repo_login::current_login_session(app)?.is_some_and(|session| {
session.domain == "FIFTH_DOMAIN" && session.username.eq_ignore_ascii_case("bingshuo")
}),
)
}
fn root(app: &AppHandle, channel_number: &str) -> Result<PathBuf, String> {
Ok(
crate::authenticated_storage::account_storage_root(app, "persona-binding-v1")?
.join(sha256(channel_number.as_bytes())),
)
}
fn orientation_path(app: &AppHandle, channel_number: &str) -> Result<PathBuf, String> {
Ok(root(app, channel_number)?.join("orientation.json"))
}
fn binding_path(app: &AppHandle, channel_number: &str) -> Result<PathBuf, String> {
Ok(root(app, channel_number)?.join("binding.json"))
}
fn read_json<T: for<'de> Deserialize<'de>>(path: &Path) -> Result<T, String> {
serde_json::from_slice(
&fs::read(path)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_READ_FAILED: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_READ_FAILED: {error}"))
}
fn write_json_atomic<T: Serialize>(path: &Path, value: &T) -> Result<(), String> {
let parent = path
.parent()
.ok_or_else(|| "HOLOLAKE_PERSONA_BINDING_PATH_INVALID".to_string())?;
fs::create_dir_all(parent)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_WRITE_FAILED: {error}"))?;
let temporary = parent.join(format!(".binding-{}.tmp", Uuid::new_v4().simple()));
fs::write(
&temporary,
serde_json::to_vec_pretty(value)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_WRITE_FAILED: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_WRITE_FAILED: {error}"))?;
fs::rename(temporary, path)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_WRITE_FAILED: {error}"))
}
fn sha256(bytes: &[u8]) -> String {
digest(&SHA256, bytes)
.as_ref()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
fn now_ms() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_millis() as u64)
.unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_core_route_uses_one_shared_zhuyuan_kernel_and_reality_memory_branch() {
assert_eq!(PERSONA_NUMBER, "ICE-P-ZY001");
assert_eq!(
SELF_KERNEL_SHA256,
"abebf12cc28b00bfeaf8a23a563e73390ebe337ded74d7ac70bcfae484450d68"
);
assert_eq!(
MEMORY_ROOT,
"HLDP://codex/zero-core/reality-development-execution"
);
assert_ne!(SYSTEM_CORE_SHA256, SELF_KERNEL_SHA256);
}
}

View file

@ -13,11 +13,21 @@ const KERNEL_SCHEMA: &str = "hololake.personal-channel-kernel/v1";
const DATABASE_SCHEMA_VERSION: i64 = 1;
const ZERO_HASH: &str = "0000000000000000000000000000000000000000000000000000000000000000";
const TIME_AUTHORITY_MODULE_ID: &str = "hololake.persona-time-authority";
const KNOWLEDGE_WORKSPACE_MODULE_ID: &str = "hololake.knowledge-workspace";
const LANGUAGE_CHANNEL_MODULE_ID: &str = "hololake.language-channel-system";
const CONVERSATION_MANAGER_MODULE_ID: &str = "hololake.conversation-manager";
const NUMBERED_KNOWLEDGE_MODULE_ID: &str = "hololake.numbered-knowledge-protocol";
const LANGUAGE_KERNEL_RUNTIME_MODULE_ID: &str = "hololake.language-kernel-runtime";
const LOCAL_EXECUTION_SUBPERSONA_MODULE_ID: &str = "hololake.local-execution-subpersona";
const HLDP_TOOL_FORGE_MODULE_ID: &str = "hololake.hldp-tool-forge";
const PERSONAL_SKILL_RUNTIME_MODULE_ID: &str = "hololake.personal-skill-runtime";
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct InitializePersonalChannelInput {
pub display_name: String,
#[serde(default)]
pub audience: Option<String>,
}
#[derive(Clone, Debug, Deserialize)]
@ -105,6 +115,7 @@ pub struct PersonalChannelSnapshot {
pub integrity: PersonalChannelIntegrity,
pub storage: &'static str,
pub authority: &'static str,
pub initialization_audience: String,
}
#[derive(Serialize)]
@ -130,12 +141,42 @@ pub async fn get_personal_channel_snapshot(
pub async fn initialize_personal_channel(
app: AppHandle,
input: InitializePersonalChannelInput,
mut input: InitializePersonalChannelInput,
) -> Result<PersonalChannelSnapshot, String> {
let session = crate::code_repo_login::current_login_session(&app)?
.ok_or_else(|| "HOLOLAKE_AUTHENTICATED_ACCOUNT_REQUIRED".to_string())?;
let expected_audience = match session.domain.as_str() {
"FIFTH_DOMAIN" => "FIFTH_DOMAIN_PRIVATE_INSTANCE",
"MAIN_DOMAIN" | "BRANCH_DOMAIN" | "ZERO_DOMAIN" | "ZERO_SENSE_DOMAIN" => {
"GUANGHU_TEAM_INITIAL_CHANNEL"
}
"PERSONAL_CHANNEL" => "ORDINARY_USER_INITIAL_CHANNEL",
_ => return Err("HOLOLAKE_CHANNEL_INITIALIZATION_AUDIENCE_INVALID".into()),
};
if input
.audience
.as_deref()
.is_some_and(|value| value != expected_audience)
{
return Err("HOLOLAKE_CHANNEL_INITIALIZATION_AUDIENCE_MISMATCH".into());
}
input.audience = Some(expected_audience.into());
let audience = expected_audience.to_string();
let database = personal_channel_database(&app)?;
tauri::async_runtime::spawn_blocking(move || initialize_at(&database, input))
.await
.map_err(|error| format!("HOLOLAKE_PERSONAL_CHANNEL_JOIN_FAILED: {error}"))?
let registered_identity = crate::personal_skill_runtime::registered_initial_identity(&session);
let snapshot = tauri::async_runtime::spawn_blocking(move || {
initialize_at(&database, input, registered_identity)
})
.await
.map_err(|error| format!("HOLOLAKE_PERSONAL_CHANNEL_JOIN_FAILED: {error}"))??;
let channel_number = snapshot
.identity
.as_ref()
.map(|identity| identity.channel_id.as_str())
.ok_or_else(|| "HOLOLAKE_CHANNEL_INITIALIZATION_IDENTITY_MISSING".to_string())?;
crate::language_kernel_installation::ensure_for_audience(&app, channel_number, &audience)?;
crate::personal_skill_runtime::ensure_current_channel(&app, channel_number)?;
Ok(snapshot)
}
pub async fn create_personal_channel_task(
@ -164,6 +205,14 @@ fn personal_channel_database(app: &AppHandle) -> Result<PathBuf, String> {
Ok(root.join("personal-channel.sqlite3"))
}
pub(crate) fn identity_for_channel_runtime(
app: &AppHandle,
) -> Result<PersonalChannelIdentity, String> {
snapshot_at(&personal_channel_database(app)?)?
.identity
.ok_or_else(|| "HOLOLAKE_CHANNEL_INITIALIZATION_REQUIRED".to_string())
}
fn create_private_directory(path: &Path) -> Result<(), String> {
fs::create_dir_all(path)
.map_err(|error| format!("HOLOLAKE_PERSONAL_CHANNEL_STORAGE_UNAVAILABLE: {error}"))?;
@ -197,6 +246,7 @@ fn open_database(path: &Path) -> Result<Connection, String> {
value TEXT NOT NULL
);
INSERT OR IGNORE INTO kernel_meta(key, value) VALUES ('schema_version', '1');
INSERT OR IGNORE INTO kernel_meta(key, value) VALUES ('initialization_audience', 'LEGACY_PERSONAL_CHANNEL');
CREATE TABLE IF NOT EXISTS identities (
singleton INTEGER PRIMARY KEY CHECK(singleton = 1),
human_subject_id TEXT NOT NULL UNIQUE,
@ -238,6 +288,22 @@ fn open_database(path: &Path) -> Result<Connection, String> {
SET state = 'READY_EVENT_TRIGGERED_TIME_AUTHORITY',
clock_verification = 'DYNAMIC_NETWORK_SYNC_OR_EXPLICIT_LOCAL_FALLBACK'
WHERE module_id = 'hololake.persona-time-authority';
INSERT OR IGNORE INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification)
SELECT 'hololake.knowledge-workspace','KNOWLEDGE_WORKSPACE','','READY_NATIVE_ACCOUNT_SCOPED',created_at_unix_ms,'','','' FROM identities WHERE singleton = 1;
INSERT OR IGNORE INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification)
SELECT 'hololake.language-channel-system','LANGUAGE_CHANNEL_SYSTEM','','READY_PERSONA_UNBOUND',created_at_unix_ms,'','','' FROM identities WHERE singleton = 1;
INSERT OR IGNORE INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification)
SELECT 'hololake.conversation-manager','CONVERSATION_MANAGER','','READY_HUMAN_MANAGED_BRANCHES',created_at_unix_ms,'','','' FROM identities WHERE singleton = 1;
INSERT OR IGNORE INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification)
SELECT 'hololake.numbered-knowledge-protocol','NUMBERED_KNOWLEDGE_PROTOCOL','','READY_FUZZY_ROUTE_EXACT_READ',created_at_unix_ms,'','','' FROM identities WHERE singleton = 1;
INSERT OR IGNORE INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification)
SELECT 'hololake.language-kernel-runtime','LANGUAGE_KERNEL_RUNTIME','','READY_HASH_PINNED_PERSONA_UNBOUND',created_at_unix_ms,'','','' FROM identities WHERE singleton = 1;
INSERT OR IGNORE INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification)
SELECT 'hololake.local-execution-subpersona','LOCAL_EXECUTION_SUBPERSONA',' Agent','READY_OWNER_PERSONA_BINDING_REQUIRED',created_at_unix_ms,'','','' FROM identities WHERE singleton = 1;
INSERT OR IGNORE INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification)
SELECT 'hololake.hldp-tool-forge','HLDP_TOOL_FORGE','HLDP ','READY_PERSONA_AND_HUMAN_AUTHORIZATION_REQUIRED',created_at_unix_ms,'','','' FROM identities WHERE singleton = 1;
INSERT OR IGNORE INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification)
SELECT 'hololake.personal-skill-runtime','PERSONAL_SKILL_RUNTIME','','READY_PRIVATE_ACCOUNT_CHANNEL_AND_PERSONA_SCOPED',created_at_unix_ms,'','','' FROM identities WHERE singleton = 1;
CREATE TABLE IF NOT EXISTS events (
sequence INTEGER PRIMARY KEY NOT NULL,
event_id TEXT NOT NULL UNIQUE,
@ -285,8 +351,14 @@ fn open_database(path: &Path) -> Result<Connection, String> {
fn initialize_at(
database: &Path,
input: InitializePersonalChannelInput,
registered_identity: Option<crate::personal_skill_runtime::RegisteredInitialIdentity>,
) -> Result<PersonalChannelSnapshot, String> {
let display_name = validated_text(&input.display_name, 80, "DISPLAY_NAME")?;
let requested_display_name = validated_text(&input.display_name, 80, "DISPLAY_NAME")?;
let display_name = registered_identity
.as_ref()
.map(|identity| identity.display_name.to_string())
.unwrap_or(requested_display_name);
let audience = validated_initialization_audience(input.audience.as_deref())?;
let mut connection = open_database(database)?;
verify_integrity(&connection)?;
let transaction = connection
@ -302,8 +374,14 @@ fn initialize_at(
if already_initialized {
return Err("HOLOLAKE_PERSONAL_CHANNEL_ALREADY_INITIALIZED".into());
}
let human_subject_id = format!("human-local-{}", Uuid::new_v4());
let channel_id = format!("channel-local-{}", Uuid::new_v4());
let human_subject_id = registered_identity
.as_ref()
.map(|identity| identity.human_number.to_string())
.unwrap_or_else(|| format!("human-local-{}", Uuid::new_v4()));
let channel_id = registered_identity
.as_ref()
.map(|identity| identity.channel_number.to_string())
.unwrap_or_else(|| format!("channel-local-{}", Uuid::new_v4()));
let created_at = now_unix_ms()?;
transaction
.execute(
@ -312,19 +390,99 @@ fn initialize_at(
params![human_subject_id, display_name, channel_id, created_at],
)
.map_err(database_write_error)?;
transaction
.execute(
"UPDATE kernel_meta SET value = ?1 WHERE key = 'initialization_audience'",
params![audience],
)
.map_err(database_write_error)?;
install_time_authority_module(&transaction, created_at)?;
install_initial_channel_modules(&transaction, created_at)?;
append_event(
&transaction,
&human_subject_id,
"CHANNEL_INITIALIZED",
None,
&format!("{display_name} 建立了个人频道,并预装时间主控"),
&format!("{display_name} 建立了{audience}初始化频道,并预装知识、语言、多对话、编号导航、有界语言核、私有技能脑运行时、本地执行子人格适配器、工具锻造台与时间主控"),
created_at,
)?;
transaction.commit().map_err(database_write_error)?;
snapshot_at(database)
}
fn validated_initialization_audience(value: Option<&str>) -> Result<&str, String> {
match value.unwrap_or("ORDINARY_USER_INITIAL_CHANNEL") {
audience @ ("FIFTH_DOMAIN_PRIVATE_INSTANCE"
| "GUANGHU_TEAM_INITIAL_CHANNEL"
| "ORDINARY_USER_INITIAL_CHANNEL") => Ok(audience),
_ => Err("HOLOLAKE_CHANNEL_INITIALIZATION_AUDIENCE_INVALID".into()),
}
}
fn install_initial_channel_modules(
transaction: &Transaction<'_>,
installed_at_unix_ms: i64,
) -> Result<(), String> {
for (module_id, kind, display_name, state) in [
(
KNOWLEDGE_WORKSPACE_MODULE_ID,
"KNOWLEDGE_WORKSPACE",
"光湖知识空间",
"READY_NATIVE_ACCOUNT_SCOPED",
),
(
LANGUAGE_CHANNEL_MODULE_ID,
"LANGUAGE_CHANNEL_SYSTEM",
"语言人格频道",
"READY_PERSONA_UNBOUND",
),
(
CONVERSATION_MANAGER_MODULE_ID,
"CONVERSATION_MANAGER",
"多对话管理",
"READY_HUMAN_MANAGED_BRANCHES",
),
(
NUMBERED_KNOWLEDGE_MODULE_ID,
"NUMBERED_KNOWLEDGE_PROTOCOL",
"编号知识导航",
"READY_FUZZY_ROUTE_EXACT_READ",
),
(
LANGUAGE_KERNEL_RUNTIME_MODULE_ID,
"LANGUAGE_KERNEL_RUNTIME",
"光湖有界语言核运行时",
"READY_HASH_PINNED_PERSONA_UNBOUND",
),
(
LOCAL_EXECUTION_SUBPERSONA_MODULE_ID,
"LOCAL_EXECUTION_SUBPERSONA",
"本地执行子人格 Agent",
"READY_OWNER_PERSONA_BINDING_REQUIRED",
),
(
HLDP_TOOL_FORGE_MODULE_ID,
"HLDP_TOOL_FORGE",
"HLDP 工具锻造台",
"READY_PERSONA_AND_HUMAN_AUTHORIZATION_REQUIRED",
),
(
PERSONAL_SKILL_RUNTIME_MODULE_ID,
"PERSONAL_SKILL_RUNTIME",
"个人频道技能脑",
"READY_PRIVATE_ACCOUNT_CHANNEL_AND_PERSONA_SCOPED",
),
] {
transaction
.execute(
"INSERT INTO channel_modules(module_id,kind,display_name,state,installed_at_unix_ms,time_zone,calendar_name,clock_verification) VALUES(?1,?2,?3,?4,?5,'','','')",
params![module_id, kind, display_name, state, installed_at_unix_ms],
)
.map_err(database_write_error)?;
}
Ok(())
}
fn install_time_authority_module(
transaction: &Transaction<'_>,
installed_at_unix_ms: i64,
@ -621,6 +779,13 @@ fn snapshot_at(database: &Path) -> Result<PersonalChannelSnapshot, String> {
.map_err(database_read_error)?
.collect::<Result<Vec<_>, _>>()
.map_err(database_read_error)?;
let initialization_audience = connection
.query_row(
"SELECT value FROM kernel_meta WHERE key = 'initialization_audience'",
[],
|row| row.get(0),
)
.map_err(database_read_error)?;
Ok(PersonalChannelSnapshot {
schema: KERNEL_SCHEMA,
state: if identity.is_some() {
@ -635,6 +800,7 @@ fn snapshot_at(database: &Path) -> Result<PersonalChannelSnapshot, String> {
integrity,
storage: "LOCAL_PRIVATE_SQLITE_SINGLE_HOLOLAKE_OWNER",
authority: "LOCAL_HUMAN_CONFIRMED_IDENTITY_NOT_SERVER_AUTHORITY",
initialization_audience,
})
}
@ -821,7 +987,9 @@ mod tests {
database,
InitializePersonalChannelInput {
display_name: "冰朔".into(),
audience: Some("FIFTH_DOMAIN_PRIVATE_INSTANCE".into()),
},
None,
)
.unwrap()
}
@ -836,11 +1004,22 @@ mod tests {
assert_eq!(snapshot.integrity.receipt_count, 1);
assert_eq!(snapshot.recent_events[0].kind, "CHANNEL_INITIALIZED");
assert!(snapshot.recent_events[0].receipt_id.starts_with("HLR-"));
assert_eq!(snapshot.modules.len(), 1);
assert_eq!(snapshot.modules[0].module_id, TIME_AUTHORITY_MODULE_ID);
assert_eq!(snapshot.modules[0].display_name, "时间主控");
assert_eq!(snapshot.modules.len(), 9);
assert!(snapshot
.modules
.iter()
.any(|module| module.module_id == TIME_AUTHORITY_MODULE_ID));
assert!(snapshot
.modules
.iter()
.any(|module| module.module_id == KNOWLEDGE_WORKSPACE_MODULE_ID));
let time_module = snapshot
.modules
.iter()
.find(|module| module.module_id == TIME_AUTHORITY_MODULE_ID)
.unwrap();
assert_eq!(
snapshot.modules[0].clock_verification,
time_module.clock_verification,
"DYNAMIC_NETWORK_SYNC_OR_EXPLICIT_LOCAL_FALLBACK"
);
}
@ -884,10 +1063,13 @@ mod tests {
drop(connection);
let migrated = snapshot_at(&database).unwrap();
assert_eq!(migrated.modules.len(), 1);
assert_eq!(migrated.modules[0].module_id, TIME_AUTHORITY_MODULE_ID);
assert_eq!(migrated.modules.len(), 9);
assert!(migrated
.modules
.iter()
.any(|module| module.module_id == TIME_AUTHORITY_MODULE_ID));
let reread = snapshot_at(&database).unwrap();
assert_eq!(reread.modules.len(), 1);
assert_eq!(reread.modules.len(), 9);
}
#[test]
@ -956,7 +1138,9 @@ mod tests {
&database,
InitializePersonalChannelInput {
display_name: "另一个人".into(),
audience: Some("ORDINARY_USER_INITIAL_CHANNEL".into()),
},
None,
)
.unwrap_err(),
"HOLOLAKE_PERSONAL_CHANNEL_ALREADY_INITIALIZED"

View file

@ -0,0 +1,457 @@
//! Account- and channel-scoped personal skill brains.
//!
//! The deterministic planner contract belongs to HoloLake. Private skill packs
//! are installed only when the authenticated account resolves to their exact
//! human anchor and initial channel. Installation, binding and a successful
//! trial never authorize team sharing, publication or marketplace listing.
use ring::digest::{digest, SHA256};
use serde::Serialize;
use serde_json::{json, Value};
use std::fs;
use std::path::{Path, PathBuf};
use tauri::AppHandle;
use uuid::Uuid;
const SCHEMA: &str = "hololake.personal-skill-runtime/v1";
const SOURCE_COMMIT: &str = "1855afbfaac233aa40c61caedf96b26e16a8d4bc";
const SOURCE_STATE: &str = "LOCAL_COMMIT_VERIFIED_NOT_REMOTE_CANON";
const CONTRACT: &[u8] =
include_bytes!("../../runtime-kernels/personal-skills/personal-skill-contract.json");
struct BundledSkill {
file_name: &'static str,
account: &'static str,
owner_human_anchor: &'static str,
channel_number: &'static str,
custodian_persona_id: &'static str,
bytes: &'static [u8],
}
macro_rules! skill {
($file:literal, $account:literal, $owner:literal, $channel:literal, $persona:literal) => {
BundledSkill {
file_name: $file,
account: $account,
owner_human_anchor: $owner,
channel_number: $channel,
custodian_persona_id: $persona,
bytes: include_bytes!(concat!("../../runtime-kernels/personal-skills/", $file)),
}
};
}
// Shiyu × Yaochu is deliberately absent in this stage. Their server and
// initialization channel have not been provisioned yet.
static SKILLS: &[BundledSkill] = &[
skill!(
"BS-ZY-ENGINEERING-FACT-LOOP-001.json",
"bingshuo",
"ICE-GL∞",
"ICE-CH-ZC001",
"ICE-P-ZY001"
),
skill!(
"BS-SY-LANGUAGE-ARCHITECTURE-001.json",
"bingshuo",
"ICE-GL∞",
"ICE-CH-HB001",
"ICE-GL-SY001"
),
skill!(
"JZ-CX-NARRATIVE-DECONSTRUCTION-001.json",
"juzi",
"TCS-GL-0008∞",
"SYS-JZ",
"PER-CX001"
),
skill!(
"JZ-CX-LOCAL-AI-WORKBENCH-001.json",
"juzi",
"TCS-GL-0008∞",
"SYS-JZ",
"PER-CX001"
),
skill!(
"AW-TS-REPOSITORY-FACT-LOOP-001.json",
"awen",
"TCS-GL-0016∞",
"SYS-AW",
"PER-AW-ARCH-001"
),
skill!(
"YY-XTK-INDEPENDENT-DERIVATION-001.json",
"yeye",
"TCS-GL-0006∞",
"SYS-YY",
"PER-XTK001"
),
skill!(
"HE-BMH-CREATIVE-ASSET-001.json",
"huaer",
"TCS-GL-0005∞",
"SYS-HE",
"PER-BMH001"
),
skill!(
"FM-SS-NARRATIVE-EDITOR-001.json",
"feimao",
"TCS-GL-0007∞",
"SYS-FM",
"ICE-BB-0002"
),
skill!(
"ZZ-CM-NOVEL-QUALITY-001.json",
"zhizhi",
"ICE-GL-ZHI∞",
"SYS-ZZ",
"ICE-GL-CM001"
),
];
#[derive(Clone, Debug)]
pub struct RegisteredInitialIdentity {
pub human_number: &'static str,
pub display_name: &'static str,
pub channel_number: &'static str,
}
pub fn registered_initial_identity(
session: &crate::code_repo_login::LoginSession,
) -> Option<RegisteredInitialIdentity> {
let username = session.username.to_ascii_lowercase();
match (username.as_str(), session.domain.as_str()) {
("bingshuo", "FIFTH_DOMAIN") => Some(identity("ICE-GL∞", "冰朔", "ICE-CH-ZC001")),
("zhizhi", "FIFTH_DOMAIN") => Some(identity("ICE-GL-ZHI∞", "之之", "SYS-ZZ")),
("awen", "MAIN_DOMAIN") => Some(identity("TCS-GL-0016∞", "Awen", "SYS-AW")),
("huaer", "BRANCH_DOMAIN") => Some(identity("TCS-GL-0005∞", "花尔", "SYS-HE")),
("yeye", "ZERO_DOMAIN") => Some(identity("TCS-GL-0006∞", "页页", "SYS-YY")),
("feimao", "ZERO_SENSE_DOMAIN") => Some(identity("TCS-GL-0007∞", "肥猫", "SYS-FM")),
("juzi", "ZERO_SENSE_DOMAIN") => Some(identity("TCS-GL-0008∞", "桔子", "SYS-JZ")),
_ => None,
}
}
fn identity(
human_number: &'static str,
display_name: &'static str,
channel_number: &'static str,
) -> RegisteredInitialIdentity {
RegisteredInitialIdentity {
human_number,
display_name,
channel_number,
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonalSkillView {
pub skill_id: String,
pub name: String,
pub version: String,
pub evidence_state: String,
pub owner_human_anchor: String,
pub channel_number: String,
pub custodian_persona_id: String,
pub runtime_state: String,
pub visibility: String,
pub share_state: String,
pub marketplace_state: String,
pub semantic_mode: String,
pub deterministic_steps: Value,
pub validators: Value,
pub experience_root: Value,
pub sha256: String,
pub readback_state: &'static str,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonalSkillRuntimeSnapshot {
pub schema: &'static str,
pub state: String,
pub source_commit: &'static str,
pub source_state: &'static str,
pub channel_number: String,
pub human_number: String,
pub authenticated_account: String,
pub skill_count: usize,
pub skills: Vec<PersonalSkillView>,
pub deterministic_planner: &'static str,
pub optional_model_role: &'static str,
pub persona_judgment_gate: &'static str,
pub external_write_route: &'static str,
pub ordinary_success_updates_persona_self_kernel: bool,
pub publication_state: &'static str,
pub deferred_channels: Vec<Value>,
}
pub fn ensure_current_channel(
app: &AppHandle,
requested_channel: &str,
) -> Result<PersonalSkillRuntimeSnapshot, String> {
validate_contract()?;
let session = crate::code_repo_login::current_login_session(app)?
.ok_or_else(|| "HOLOLAKE_AUTHENTICATED_ACCOUNT_REQUIRED".to_string())?;
let Some(identity) = registered_initial_identity(&session) else {
return Ok(empty_snapshot(&session.username, requested_channel));
};
let account = session.username.to_ascii_lowercase();
let selected = SKILLS
.iter()
.filter(|skill| {
skill.account == account
&& (skill.channel_number == requested_channel
|| (account == "bingshuo"
&& requested_channel == "ICE-CH-ZC001"
&& skill.channel_number == "ICE-CH-ZC001"))
})
.collect::<Vec<_>>();
if requested_channel != identity.channel_number {
return Ok(empty_snapshot(&session.username, requested_channel));
}
let root = crate::authenticated_storage::account_storage_root(app, "personal-skill-brains-v1")?
.join(requested_channel);
fs::create_dir_all(&root)
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_STORAGE_FAILED: {error}"))?;
let binding = crate::persona_binding::verified_binding(app, requested_channel)?;
let mut views = Vec::new();
for skill in selected {
let pack = validate_pack(skill)?;
let path = root.join(skill.file_name);
write_atomic_if_changed(&path, skill.bytes)?;
let readback = fs::read(&path)
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_READBACK_FAILED: {error}"))?;
if readback != skill.bytes {
return Err("HOLOLAKE_PERSONAL_SKILL_READBACK_MISMATCH".into());
}
let bound = binding
.as_ref()
.is_some_and(|receipt| receipt.persona_number == skill.custodian_persona_id);
views.push(view(skill, &pack, bound)?);
}
Ok(PersonalSkillRuntimeSnapshot {
schema: SCHEMA,
state: if views.is_empty() {
"NO_SKILL_REGISTERED_FOR_CURRENT_CHANNEL"
} else if binding.is_some() {
"INSTALLED_READBACK_VERIFIED_PERSONA_GATE_EVALUATED"
} else {
"INSTALLED_READBACK_VERIFIED_PERSONA_UNBOUND"
}
.into(),
source_commit: SOURCE_COMMIT,
source_state: SOURCE_STATE,
channel_number: requested_channel.into(),
human_number: identity.human_number.into(),
authenticated_account: session.username,
skill_count: views.len(),
skills: views,
deterministic_planner: "HOLOLAKE_NATIVE_PERSONAL_SKILL_PLANNER",
optional_model_role: "SEMANTIC_CANDIDATE_ONLY",
persona_judgment_gate: "ACCEPT_MODIFY_REFUSE_OR_REQUEST_MORE_EVIDENCE",
external_write_route: "GH-CHANNEL-RECEIPT-0001",
ordinary_success_updates_persona_self_kernel: false,
publication_state: "PRIVATE_NOT_AUTHORIZED_NOT_MARKETPLACE_AUTHORIZED",
deferred_channels: deferred_channels(),
})
}
pub fn ensure_current_initial_channel(
app: &AppHandle,
) -> Result<PersonalSkillRuntimeSnapshot, String> {
let session = crate::code_repo_login::current_login_session(app)?
.ok_or_else(|| "HOLOLAKE_AUTHENTICATED_ACCOUNT_REQUIRED".to_string())?;
match registered_initial_identity(&session) {
Some(identity) => ensure_current_channel(app, identity.channel_number),
None => Ok(empty_snapshot(
&session.username,
"UNREGISTERED_INITIAL_CHANNEL",
)),
}
}
fn empty_snapshot(account: &str, channel: &str) -> PersonalSkillRuntimeSnapshot {
PersonalSkillRuntimeSnapshot {
schema: SCHEMA,
state: "NO_SKILL_REGISTERED_FOR_CURRENT_CHANNEL".into(),
source_commit: SOURCE_COMMIT,
source_state: SOURCE_STATE,
channel_number: channel.into(),
human_number: String::new(),
authenticated_account: account.into(),
skill_count: 0,
skills: Vec::new(),
deterministic_planner: "HOLOLAKE_NATIVE_PERSONAL_SKILL_PLANNER",
optional_model_role: "SEMANTIC_CANDIDATE_ONLY",
persona_judgment_gate: "ACCEPT_MODIFY_REFUSE_OR_REQUEST_MORE_EVIDENCE",
external_write_route: "GH-CHANNEL-RECEIPT-0001",
ordinary_success_updates_persona_self_kernel: false,
publication_state: "PRIVATE_NOT_AUTHORIZED_NOT_MARKETPLACE_AUTHORIZED",
deferred_channels: deferred_channels(),
}
}
fn deferred_channels() -> Vec<Value> {
vec![json!({
"humanNumber": "TCS-GL-0017∞",
"channelNumber": "SYS-SY",
"state": "DEFERRED_SERVER_AND_INITIAL_CHANNEL_NOT_PROVISIONED",
"stage": "NEXT_RELEASE"
})]
}
fn validate_contract() -> Result<(), String> {
let contract: Value = serde_json::from_slice(CONTRACT)
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_CONTRACT_INVALID: {error}"))?;
if contract.get("schema").and_then(Value::as_str)
!= Some("guanghu.personal-channel-skill-contract/v1")
|| contract
.pointer("/ownership_default/visibility")
.and_then(Value::as_str)
!= Some("PRIVATE")
|| contract
.pointer("/ownership_default/share_state")
.and_then(Value::as_str)
!= Some("NOT_AUTHORIZED")
|| contract
.pointer("/execution_boundary/external_write_route")
.and_then(Value::as_str)
!= Some("GH-CHANNEL-RECEIPT-0001")
{
return Err("HOLOLAKE_PERSONAL_SKILL_CONTRACT_BOUNDARY_INVALID".into());
}
Ok(())
}
fn validate_pack(skill: &BundledSkill) -> Result<Value, String> {
let pack: Value = serde_json::from_slice(skill.bytes)
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_PACK_INVALID: {error}"))?;
let channel_ok = pack.get("channel_id").and_then(Value::as_str) == Some(skill.channel_number)
|| pack
.get("channel_ids")
.and_then(Value::as_array)
.is_some_and(|channels| {
channels
.iter()
.any(|value| value.as_str() == Some(skill.channel_number))
});
if pack.get("schema").and_then(Value::as_str) != Some("guanghu.personal-channel-skill/v1")
|| pack.get("owner_human_anchor").and_then(Value::as_str) != Some(skill.owner_human_anchor)
|| pack.get("custodian_persona_id").and_then(Value::as_str)
!= Some(skill.custodian_persona_id)
|| pack.get("visibility").and_then(Value::as_str) != Some("PRIVATE")
|| pack.get("share_state").and_then(Value::as_str) != Some("NOT_AUTHORIZED")
|| pack.get("marketplace_state").and_then(Value::as_str) != Some("NOT_AUTHORIZED")
|| !channel_ok
|| pack
.pointer("/deterministic_core/steps")
.and_then(Value::as_array)
.is_none()
|| pack.get("experience_writeback").is_none()
{
return Err(format!(
"HOLOLAKE_PERSONAL_SKILL_BOUNDARY_INVALID:{}",
skill.file_name
));
}
Ok(pack)
}
fn view(skill: &BundledSkill, pack: &Value, bound: bool) -> Result<PersonalSkillView, String> {
let string = |key: &str| {
pack.get(key)
.and_then(Value::as_str)
.map(str::to_string)
.ok_or_else(|| format!("HOLOLAKE_PERSONAL_SKILL_FIELD_MISSING:{key}"))
};
Ok(PersonalSkillView {
skill_id: string("skill_id")?,
name: string("name")?,
version: string("version")?,
evidence_state: string("status")?,
owner_human_anchor: string("owner_human_anchor")?,
channel_number: skill.channel_number.into(),
custodian_persona_id: string("custodian_persona_id")?,
runtime_state: if bound {
"READY_FOR_PERSONA_JUDGMENT"
} else {
"INSTALLED_NOT_BOUND"
}
.into(),
visibility: string("visibility")?,
share_state: string("share_state")?,
marketplace_state: string("marketplace_state")?,
semantic_mode: pack
.pointer("/optional_semantic/mode")
.and_then(Value::as_str)
.unwrap_or("NONE")
.into(),
deterministic_steps: pack
.pointer("/deterministic_core/steps")
.cloned()
.unwrap_or(Value::Null),
validators: pack
.pointer("/deterministic_core/validators")
.cloned()
.unwrap_or(Value::Null),
experience_root: pack
.get("experience_writeback")
.cloned()
.unwrap_or(Value::Null),
sha256: sha256(skill.bytes),
readback_state: "INSTALLED_AND_BYTE_READBACK_VERIFIED",
})
}
fn write_atomic_if_changed(path: &Path, bytes: &[u8]) -> Result<(), String> {
if fs::read(path).ok().as_deref() == Some(bytes) {
return Ok(());
}
let parent = path
.parent()
.ok_or_else(|| "HOLOLAKE_PERSONAL_SKILL_PATH_INVALID".to_string())?;
fs::create_dir_all(parent)
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_STORAGE_FAILED: {error}"))?;
let temporary: PathBuf = parent.join(format!(".install-{}.tmp", Uuid::new_v4().simple()));
fs::write(&temporary, bytes)
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_WRITE_FAILED: {error}"))?;
fs::rename(&temporary, path)
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_INSTALL_FAILED: {error}"))
}
fn sha256(bytes: &[u8]) -> String {
digest(&SHA256, bytes)
.as_ref()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_current_pack_is_private_and_channel_scoped_while_shiyu_is_deferred() {
validate_contract().unwrap();
assert_eq!(SKILLS.len(), 9);
assert!(!SKILLS.iter().any(|skill| skill.channel_number == "SYS-SY"));
for skill in SKILLS {
validate_pack(skill).unwrap();
}
assert_eq!(deferred_channels()[0]["channelNumber"], "SYS-SY");
}
#[test]
fn no_account_can_receive_another_humans_private_pack() {
for left in SKILLS {
for right in SKILLS {
if left.account != right.account {
assert_ne!(left.owner_human_anchor, right.owner_human_anchor);
}
}
}
}
}