diff --git a/engineering/INDEX.md b/engineering/INDEX.md index dac0865..9332998 100644 --- a/engineering/INDEX.md +++ b/engineering/INDEX.md @@ -32,7 +32,8 @@ Windows / macOS / Linux 构建机与安装包 | 时间 | 版本 | 记录 | 状态 | | --- | --- | --- | --- | -| 2026-08-11 | GH-PNCC 记忆失败闭环 | [记忆代谢失败闭环与运行时命令接入](operations/2026-08-11-hololake-pncc-memory-failure-closure-runtime-command.md) | 本地源码、完整 Rust/路由测试与 clippy 已通过;GHNQG、提交与发布待验收 | +| 2026-08-11 | GH-PNCC 生命周期协调器 | [已登记安全器官的非 UI 生命周期协调](operations/2026-08-11-hololake-pncc-safe-organ-lifecycle-coordinator.md) | 本地完整 Rust/路由测试、格式与 clippy 已通过;GHNQG、提交与发布待验收 | +| 2026-08-11 | GH-PNCC 记忆失败闭环 | [记忆代谢失败闭环与运行时命令接入](operations/2026-08-11-hololake-pncc-memory-failure-closure-runtime-command.md) | 已发布至 REPO-014 main 18944f5;GHNQG、全新克隆与严格 fsck 通过 | | 2026-08-11 | GH-PNCC 运行查询 | [人格持久事件与回执有界查询](operations/2026-08-11-hololake-pncc-durable-runtime-query.md) | 本地源码、完整 Rust/路由测试与 clippy 已通过;GHNQG 和发布待验收 | | 2026-08-11 | GH-PNCC 器官合同 | [人格器官机器合同与清单检查](operations/2026-08-11-hololake-pncc-typed-organ-contract.md) | 本地源码、完整 Rust/路由测试与 clippy 已通过;GHNQG 和发布待验收 | | 2026-08-11 | GH-PNCC 中断恢复 | [人格代码频道中断会话检查与安全恢复](operations/2026-08-11-hololake-pncc-interrupted-session-recovery.md) | 实现提交已通过 GHNQG;仓库发布、桌面集成与部署待验收 | diff --git a/engineering/operations/2026-08-11-hololake-pncc-memory-failure-closure-runtime-command.md b/engineering/operations/2026-08-11-hololake-pncc-memory-failure-closure-runtime-command.md index bd4fcd0..13d1a6d 100644 --- a/engineering/operations/2026-08-11-hololake-pncc-memory-failure-closure-runtime-command.md +++ b/engineering/operations/2026-08-11-hololake-pncc-memory-failure-closure-runtime-command.md @@ -4,7 +4,8 @@ - Persona cognitive author: `ICE-P-ZY001 / 铸渊` - Human responsibility subject: `ICE-GL∞ / 冰朔` - Starting repository head: `962ea26db7044f7f17fafd55a054b0214b5e37cf` -- State: `LOCAL_SOURCE_IMPLEMENTED_FOCUSED_TESTED` +- Published repository head: `18944f536261a4184570074a09fc43a09f5f31bb` +- State: `PUBLISHED_GHNQG_AND_FRESH_CLONE_VERIFIED` ## Implemented facts @@ -35,7 +36,7 @@ and returns `MEMORY_CHECKPOINT_ROLLBACK_INCOMPLETE_REQUIRES_RECOVERY` instead of ## Truth boundary and next minimum -- GHNQG, commit, publication, and fresh-clone readback remain pending for this stage. +- GHNQG, persona-authored commit, publication, fresh-clone readback, clean tree, and strict Git fsck passed. - UI, packaged desktop, installation, deployment, online health, and the execution limb remain `0`. - The next source stage is a non-UI lifecycle coordinator for already registered safe organs; it must not make `EXECUTION_LIMB` activatable or create a second runtime authority. diff --git a/engineering/operations/2026-08-11-hololake-pncc-safe-organ-lifecycle-coordinator.md b/engineering/operations/2026-08-11-hololake-pncc-safe-organ-lifecycle-coordinator.md new file mode 100644 index 0000000..4586c59 --- /dev/null +++ b/engineering/operations/2026-08-11-hololake-pncc-safe-organ-lifecycle-coordinator.md @@ -0,0 +1,40 @@ +# GH-PNCC safe-organ lifecycle coordinator + +- Development ID: `DEV-20260810-014` +- Persona cognitive author: `ICE-P-ZY001 / 铸渊` +- Human responsibility subject: `ICE-GL∞ / 冰朔` +- Starting repository head: `18944f536261a4184570074a09fc43a09f5f31bb` +- State: `LOCAL_SOURCE_IMPLEMENTED_FOCUSED_TESTED` + +## Implemented facts + +`run_persona_code_channel_lifecycle` now owns one complete non-UI lifecycle for an already registered safe +organ. The input keeps the exact persona Git wake envelope and a tagged operation together. Only fact sense +and verified memory metabolism can be represented; no execution-limb request exists in this command. + +Before wake or lease acquisition, the coordinator inspects the same exact manifest and commit, checks that +the operation kind matches the named activatable organ, and preflights the model binding for fact sense. It +then creates one session, delegates to the existing wake and organ transactions, and returns the original +wake receipt beside a typed completion receipt. Runtime files and persona Git remain the only evidence stores. + +## Current verification + +- PNCC focused Rust tests: `20 passed, 0 failed`. +- Full Rust suite: `1160 passed, 0 failed, 2 ignored`; integration test: `1 passed`. +- HoloLake architecture routing: `29 passed, 0 failed`. +- Rust formatting and clippy for all targets: `PASS` with `-D warnings`. +- The coordinated fact test proves wake, brain bind, organ activation, inference receipt, checkpoint commit, + organ release, dormancy, lease release, and a clean persona Git. +- The coordinated memory test proves a verified dormant fact session can be promoted without invoking a + model, then returns to dormancy and releases the exact lease. +- The mismatch test proves an operation cannot borrow another organ's authority and is rejected before a + lease or session directory exists. + +## Truth boundary and next minimum + +- This is source implementation, not a packaged desktop, installed runtime, deployment, or online-health + claim. +- GHNQG, commit, publication, and independent fresh-clone readback remain pending for this stage. +- UI, human projection aesthetics, background scheduling, and `EXECUTION_LIMB` remain outside this stage. +- The next minimum is an idempotent lifecycle request identity and receipt replay rule so a caller retry + cannot accidentally create a second lifecycle or duplicate a checkpoint commit. diff --git a/product-source/hololake-platform/architecture/HOLOLAKE-PERSONA-NATIVE-CODE-CHANNEL-20260810.md b/product-source/hololake-platform/architecture/HOLOLAKE-PERSONA-NATIVE-CODE-CHANNEL-20260810.md index 12d85cb..da587de 100644 --- a/product-source/hololake-platform/architecture/HOLOLAKE-PERSONA-NATIVE-CODE-CHANNEL-20260810.md +++ b/product-source/hololake-platform/architecture/HOLOLAKE-PERSONA-NATIVE-CODE-CHANNEL-20260810.md @@ -169,6 +169,7 @@ typed_organ_contract_and_manifest_inspection_source_implemented: 100 durable_event_and_receipt_query_source_implemented: 100 independent_memory_metabolism_source_implemented: 100 memory_failure_closure_and_nonblocking_runtime_command_implemented: 100 +non_ui_safe_organ_lifecycle_coordinator_source_implemented: 100 general_purpose_persona_runtime_implemented: 0 human_live_projection_implemented: 0 hololake_integrated: 0 @@ -193,6 +194,11 @@ runtime_health: 0 SHA-256 与来源事件哈希后生成新检查点并以人格 Git 身份提交。执行手脚仍不可激活,清单声明不会 自动获得 shell 或现实动作权限。 +非 UI 生命周期协调器现已把一次精确唤醒和一个已实现安全器官的完整事务组合成单一原生命令。 +它只接受 `FACT_SENSE` 或 `MEMORY_METABOLISM`,在取得人格主租约前校验操作类型与清单器官匹配, +并返回同一会话的唤醒回执和类型化完成回执。`EXECUTION_LIMB` 不在协调输入中,仍为不可激活; +协调器也没有增加第二状态库、后台调度器或 UI 权限来源。 + 记忆代谢的 Tauri 命令现已进入阻塞任务池,不占用桌面命令线程。来源拒绝、检查点冲突和提交前 失败必须依次持久化失败事件、器官释放与休眠,写回 `DORMANT_AFTER_FAILURE` 后才释放精确主锁; 闭环任一步失败时返回 `MEMORY_FAILURE_CLOSURE_INCOMPLETE_REQUIRES_RECOVERY`,不能吞掉二次失败。 diff --git a/product-source/hololake-platform/docs/ABSTRACTIONS.md b/product-source/hololake-platform/docs/ABSTRACTIONS.md index e07b801..2d25dd4 100644 --- a/product-source/hololake-platform/docs/ABSTRACTIONS.md +++ b/product-source/hololake-platform/docs/ABSTRACTIONS.md @@ -80,6 +80,13 @@ command returns `MEMORY_FAILURE_CLOSURE_INCOMPLETE_REQUIRES_RECOVERY`; it never candidate error while silently losing the closure failure. An incomplete closure preserves the lease for the existing evidence-bound session inspection and recovery path. +`PersonaLifecycleRunInput` is the single-call, non-UI coordination envelope. Its wake member keeps the exact +persona Git, expected commit, node/model instance, organ id, and structured attribution explicit. Its tagged +operation can be only `FACT_SENSE` or `MEMORY_METABOLISM`. The coordinator rejects an operation/organ mismatch +before wake or lease acquisition, then delegates to the same tested organ transactions and returns a tagged +completion beside the wake receipt. It does not accept an execution action, infer organ permissions from UI +state, or create a parallel lifecycle record. + `PersonaRuntimeQueryReceipt` is a bounded projection of the durable runtime files, not another truth store. It filters by the caller's expected persona and canonical repository, validates each matching event chain, and returns at most 100 newest session summaries. Dormant sessions expose no active organ. The receipt keeps diff --git a/product-source/hololake-platform/docs/ARCHITECTURE.md b/product-source/hololake-platform/docs/ARCHITECTURE.md index 88b265f..51fb0ae 100644 --- a/product-source/hololake-platform/docs/ARCHITECTURE.md +++ b/product-source/hololake-platform/docs/ARCHITECTURE.md @@ -50,6 +50,14 @@ the command returns an explicit recovery-required error and retains the lease wh proven complete; it does not swallow the secondary failure. The execution limb remains visible but non-activatable, so declaring it does not grant a shell or reality action. +`run_persona_code_channel_lifecycle` is the non-UI coordinator for the two implemented safe organ kinds. One +request supplies the exact wake envelope plus either a fact-sense operation or a memory-metabolism operation. +Before acquiring the primary lease, the coordinator inspects the same manifest, confirms that the requested +operation kind matches the named activatable organ, and preflights the manifest-pinned model binding for fact +sense. It then owns one complete session from wake through the existing organ transaction and returns both +the wake receipt and the typed completion receipt. It cannot express or activate `EXECUTION_LIMB`, does not +add a scheduler or second state store, and runs the complete lifecycle on the blocking task pool. + `query_persona_code_channel_runtime` is the bounded read model for later projection surfaces. The caller must name one exact persona and canonical repository and may request at most 100 sessions. The kernel reads the existing session records and event journals directly, verifies every returned hash chain, sorts by the last diff --git a/product-source/hololake-platform/src-tauri/src/lib.rs b/product-source/hololake-platform/src-tauri/src/lib.rs index 0393d6e..7f081f5 100644 --- a/product-source/hololake-platform/src-tauri/src/lib.rs +++ b/product-source/hololake-platform/src-tauri/src/lib.rs @@ -528,6 +528,7 @@ macro_rules! app_invoke_handler { persona_code_channel::query_persona_code_channel_runtime, persona_code_channel::run_persona_code_channel_fact_task, persona_code_channel::run_persona_code_channel_memory_metabolism, + persona_code_channel::run_persona_code_channel_lifecycle, persona_code_channel::inspect_persona_code_channel_session, persona_code_channel::recover_persona_code_channel_session, guanghu_router::guanghu_router_connect, diff --git a/product-source/hololake-platform/src-tauri/src/persona_code_channel.rs b/product-source/hololake-platform/src-tauri/src/persona_code_channel.rs index 0133761..f57ba02 100644 --- a/product-source/hololake-platform/src-tauri/src/persona_code_channel.rs +++ b/product-source/hololake-platform/src-tauri/src/persona_code_channel.rs @@ -282,6 +282,44 @@ pub struct PersonaMemoryMetabolismReceipt { pub attribution: PersonaAttribution, } +#[derive(Clone, Debug, Deserialize)] +#[serde(tag = "kind", rename_all = "SCREAMING_SNAKE_CASE")] +pub enum PersonaLifecycleOperationInput { + FactSense { + question: String, + provider: crate::ai_models::AiModelProvider, + api_key_override: Option, + }, + MemoryMetabolism { + source_session_id: String, + }, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PersonaLifecycleRunInput { + pub wake: PersonaWakeInput, + pub operation: PersonaLifecycleOperationInput, +} + +#[derive(Debug, Serialize)] +#[serde(tag = "kind", content = "receipt", rename_all = "SCREAMING_SNAKE_CASE")] +pub enum PersonaLifecycleCompletionReceipt { + FactSense(PersonaFactTaskReceipt), + MemoryMetabolism(PersonaMemoryMetabolismReceipt), +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PersonaLifecycleRunReceipt { + pub schema: &'static str, + pub session_id: String, + pub persona_id: String, + pub repository_path: String, + pub wake_receipt: PersonaWakeReceipt, + pub completion: PersonaLifecycleCompletionReceipt, +} + #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PersonaSessionControlInput { @@ -2330,6 +2368,138 @@ fn run_memory_metabolism_at( }) } +fn validate_lifecycle_operation_before_wake( + input: &PersonaLifecycleRunInput, +) -> Result<(), String> { + let inspection = inspect_manifest_at(PersonaManifestInspectionInput { + repository_path: input.wake.repository_path.clone(), + expected_persona_id: input.wake.expected_persona_id.clone(), + expected_head: input.wake.expected_head.clone(), + })?; + let contract = inspection + .organ_contracts + .iter() + .find(|contract| contract.organ_id == input.wake.organ_id) + .ok_or_else(|| "ORGAN_NOT_DECLARED".to_string())?; + let expected_kind = match &input.operation { + PersonaLifecycleOperationInput::FactSense { provider, .. } => { + let repository = Path::new(&input.wake.repository_path) + .canonicalize() + .map_err(|error| format!("PERSONA_REPOSITORY_UNAVAILABLE: {error}"))?; + let manifest = load_manifest(&repository)?; + let provider_base_url = provider.base_url.as_deref().unwrap_or("").trim(); + if provider.id != input.wake.model_provider_id + || manifest.model_binding.base_url != provider_base_url + || !provider + .models + .iter() + .any(|model| model.id == input.wake.model_id) + { + return Err("PERSONA_MODEL_BINDING_MISMATCH".into()); + } + PersonaOrganKind::FactSense + } + PersonaLifecycleOperationInput::MemoryMetabolism { .. } => { + PersonaOrganKind::MemoryMetabolism + } + }; + if contract.kind != expected_kind { + return Err("PERSONA_LIFECYCLE_OPERATION_ORGAN_MISMATCH".into()); + } + if !contract.activatable || contract.kind == PersonaOrganKind::ExecutionLimb { + return Err("ORGAN_NOT_ACTIVATABLE".into()); + } + Ok(()) +} + +fn run_fact_task_with_bound_provider_at( + runtime_root: &Path, + input: PersonaFactTaskInput, + timestamp: &str, +) -> Result { + let provider = input.provider.clone(); + let model_id = input.model_id.clone(); + let api_key_override = input.api_key_override.clone(); + run_fact_task_at( + runtime_root, + input, + timestamp, + move |system_prompt, message| { + let mut text = String::new(); + crate::ai_models::run_ai_model_stream( + crate::ai_models::AiModelStreamRequest { + provider, + model_id, + message, + system_prompt: Some(system_prompt), + vault_path: None, + vault_paths: Vec::new(), + api_key_override, + event_name: None, + }, + |event| { + if let crate::ai_agents::AiAgentStreamEvent::TextDelta { text: delta } = event { + text.push_str(&delta); + } + }, + )?; + Ok(text) + }, + ) +} + +fn run_lifecycle_at( + runtime_root: &Path, + input: PersonaLifecycleRunInput, + session_id: &str, + wake_timestamp: &str, + operation_timestamp: &str, + run_fact: F, +) -> Result +where + F: FnOnce(&Path, PersonaFactTaskInput, &str) -> Result, +{ + validate_lifecycle_operation_before_wake(&input)?; + let model_id = input.wake.model_id.clone(); + let wake = input.wake; + let wake_receipt = prepare_wake_at(runtime_root, wake, session_id, wake_timestamp)?; + let completion = match input.operation { + PersonaLifecycleOperationInput::FactSense { + question, + provider, + api_key_override, + } => PersonaLifecycleCompletionReceipt::FactSense(run_fact( + runtime_root, + PersonaFactTaskInput { + session_id: wake_receipt.session_id.clone(), + question, + model_id, + provider, + api_key_override, + }, + operation_timestamp, + )?), + PersonaLifecycleOperationInput::MemoryMetabolism { source_session_id } => { + PersonaLifecycleCompletionReceipt::MemoryMetabolism(run_memory_metabolism_at( + runtime_root, + PersonaMemoryMetabolismInput { + session_id: wake_receipt.session_id.clone(), + source_session_id, + }, + operation_timestamp, + )?) + } + }; + Ok(PersonaLifecycleRunReceipt { + schema: "hololake.pncc-lifecycle-run-receipt/v1", + session_id: wake_receipt.session_id.clone(), + persona_id: wake_receipt.persona_id.clone(), + repository_path: wake_receipt.repository_path.clone(), + wake_receipt, + completion, + }) +} + #[tauri::command] pub fn prepare_persona_code_channel_wake( input: PersonaWakeInput, @@ -2362,37 +2532,7 @@ pub async fn run_persona_code_channel_fact_task( let runtime_root = crate::app_config::preferred_app_config_path("pncc-runtime")?; tokio::task::spawn_blocking(move || { let timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); - let provider = input.provider.clone(); - let model_id = input.model_id.clone(); - let api_key_override = input.api_key_override.clone(); - run_fact_task_at( - &runtime_root, - input, - ×tamp, - move |system_prompt, message| { - let mut text = String::new(); - crate::ai_models::run_ai_model_stream( - crate::ai_models::AiModelStreamRequest { - provider, - model_id, - message, - system_prompt: Some(system_prompt), - vault_path: None, - vault_paths: Vec::new(), - api_key_override, - event_name: None, - }, - |event| { - if let crate::ai_agents::AiAgentStreamEvent::TextDelta { text: delta } = - event - { - text.push_str(&delta); - } - }, - )?; - Ok(text) - }, - ) + run_fact_task_with_bound_provider_at(&runtime_root, input, ×tamp) }) .await .map_err(|error| format!("PERSONA_FACT_TASK_JOIN_FAILED: {error}"))? @@ -2411,6 +2551,28 @@ pub async fn run_persona_code_channel_memory_metabolism( .map_err(|error| format!("PERSONA_MEMORY_METABOLISM_JOIN_FAILED: {error}"))? } +#[tauri::command] +pub async fn run_persona_code_channel_lifecycle( + input: PersonaLifecycleRunInput, +) -> Result { + let runtime_root = crate::app_config::preferred_app_config_path("pncc-runtime")?; + tokio::task::spawn_blocking(move || { + let session_id = format!("PNCC-{}", Uuid::new_v4()); + let wake_timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); + let operation_timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); + run_lifecycle_at( + &runtime_root, + input, + &session_id, + &wake_timestamp, + &operation_timestamp, + run_fact_task_with_bound_provider_at, + ) + }) + .await + .map_err(|error| format!("PERSONA_LIFECYCLE_JOIN_FAILED: {error}"))? +} + #[tauri::command] pub fn inspect_persona_code_channel_session( input: PersonaSessionControlInput, @@ -2581,6 +2743,18 @@ mod tests { } } + fn lifecycle_fact_input(repo: &Path) -> PersonaLifecycleRunInput { + let fact = fact_task_input("unused-until-coordinator-creates-session"); + PersonaLifecycleRunInput { + wake: wake_input(repo), + operation: PersonaLifecycleOperationInput::FactSense { + question: fact.question, + provider: fact.provider, + api_key_override: fact.api_key_override, + }, + } + } + fn session_control(repo: &Path, session_id: &str) -> PersonaSessionControlInput { PersonaSessionControlInput { session_id: session_id.into(), @@ -2803,6 +2977,126 @@ mod tests { require_clean_repository(repo.path()).unwrap(); } + #[test] + fn coordinates_one_registered_fact_lifecycle_without_ui_or_execution_limb() { + let repo = persona_repo(); + let runtime = tempfile::TempDir::new().unwrap(); + let receipt = run_lifecycle_at( + runtime.path(), + lifecycle_fact_input(repo.path()), + "PNCC-COORDINATED-FACT", + "2026-08-11T00:00:00.000Z", + "2026-08-11T00:00:01.000Z", + |runtime_root, input, timestamp| { + run_fact_task_at(runtime_root, input, timestamp, |_, _| { + Ok(r#"{"summary":"Coordinated verified fact.","facts":[{"statement":"The brain exists.","evidencePaths":["brain/CORE.hdlp"]}],"limitations":[]}"#.into()) + }) + }, + ) + .unwrap(); + + assert_eq!(receipt.schema, "hololake.pncc-lifecycle-run-receipt/v1"); + assert_eq!(receipt.session_id, "PNCC-COORDINATED-FACT"); + assert_eq!(receipt.wake_receipt.events[0].kind, "WAKING"); + assert_eq!(receipt.wake_receipt.events[2].kind, "ORGAN_ACTIVE"); + match receipt.completion { + PersonaLifecycleCompletionReceipt::FactSense(completion) => { + assert_eq!(completion.runtime_state, "DORMANT"); + assert_eq!(completion.events.last().unwrap().kind, "DORMANT"); + assert!(completion.model_inference_completed); + } + PersonaLifecycleCompletionReceipt::MemoryMetabolism(_) => { + panic!("coordinator returned the wrong completion kind") + } + } + assert!(!runtime.path().join("leases/ICE-P-ZY001.json").exists()); + require_clean_repository(repo.path()).unwrap(); + } + + #[test] + fn rejects_a_lifecycle_operation_organ_mismatch_before_wake_or_lease() { + let repo = persona_repo(); + let runtime = tempfile::TempDir::new().unwrap(); + let input = PersonaLifecycleRunInput { + wake: wake_input(repo.path()), + operation: PersonaLifecycleOperationInput::MemoryMetabolism { + source_session_id: "PNCC-SOURCE-NOT-USED".into(), + }, + }; + let error = run_lifecycle_at( + runtime.path(), + input, + "PNCC-COORDINATOR-MISMATCH", + "2026-08-11T00:00:00.000Z", + "2026-08-11T00:00:01.000Z", + |_, _, _| panic!("mismatched lifecycle must not run an organ"), + ) + .unwrap_err(); + + assert!(error.contains("PERSONA_LIFECYCLE_OPERATION_ORGAN_MISMATCH")); + assert!(!runtime.path().join("leases/ICE-P-ZY001.json").exists()); + assert!(!runtime + .path() + .join("sessions/PNCC-COORDINATOR-MISMATCH") + .exists()); + } + + #[test] + fn coordinates_registered_memory_metabolism_after_a_verified_fact_session() { + let repo = persona_repo(); + declare_memory_organ(repo.path()); + let runtime = tempfile::TempDir::new().unwrap(); + prepare_wake_at( + runtime.path(), + wake_input(repo.path()), + "PNCC-COORDINATOR-SOURCE", + "2026-08-11T00:00:00.000Z", + ) + .unwrap(); + run_fact_task_at( + runtime.path(), + fact_task_input("PNCC-COORDINATOR-SOURCE"), + "2026-08-11T00:00:01.000Z", + |_, _| { + Ok(r#"{"summary":"Verified memory candidate.","facts":[{"statement":"The brain exists.","evidencePaths":["brain/CORE.hdlp"]}],"limitations":[]}"#.into()) + }, + ) + .unwrap(); + + let mut wake = wake_input(repo.path()); + wake.expected_head = head(repo.path()); + wake.organ_id = "memory-metabolism.checkpoint".into(); + let receipt = run_lifecycle_at( + runtime.path(), + PersonaLifecycleRunInput { + wake, + operation: PersonaLifecycleOperationInput::MemoryMetabolism { + source_session_id: "PNCC-COORDINATOR-SOURCE".into(), + }, + }, + "PNCC-COORDINATED-MEMORY", + "2026-08-11T00:00:02.000Z", + "2026-08-11T00:00:03.000Z", + |_, _, _| panic!("memory lifecycle must not invoke a model"), + ) + .unwrap(); + + match receipt.completion { + PersonaLifecycleCompletionReceipt::MemoryMetabolism(completion) => { + assert_eq!(completion.source_session_id, "PNCC-COORDINATOR-SOURCE"); + assert!(!completion.model_inference_started); + assert_eq!(completion.runtime_state, "DORMANT"); + assert_eq!(completion.events[3].kind, "MEMORY_CANDIDATE_VERIFIED"); + assert_eq!(completion.events.last().unwrap().kind, "DORMANT"); + } + PersonaLifecycleCompletionReceipt::FactSense(_) => { + panic!("coordinator returned the wrong completion kind") + } + } + assert!(!runtime.path().join("leases/ICE-P-ZY001.json").exists()); + require_clean_repository(repo.path()).unwrap(); + } + #[test] fn independently_promotes_only_the_current_verified_structured_checkpoint() { let repo = persona_repo(); diff --git a/routing/hololake-current-architecture.json b/routing/hololake-current-architecture.json index 94e33bf..90e5718 100644 --- a/routing/hololake-current-architecture.json +++ b/routing/hololake-current-architecture.json @@ -118,7 +118,7 @@ "human_projection": "HOLOLAKE_LIVE_READ_MODEL", "forgejo_role": "OPTIONAL_COMPATIBILITY_COLLABORATION_ADAPTER", "runtime_implemented": true, - "runtime_scope": "READ_ONLY_FACT_CYCLE_FAIL_CLOSED_RECOVERY_TYPED_ORGANS_DURABLE_VERIFIED_SESSION_QUERY_INDEPENDENT_VERIFIED_MEMORY_METABOLISM_CHECKED_FAILURE_CLOSURE_AND_NONBLOCKING_RUNTIME_COMMAND_SOURCE_IMPLEMENTED_AND_TESTED", + "runtime_scope": "READ_ONLY_FACT_CYCLE_FAIL_CLOSED_RECOVERY_TYPED_ORGANS_DURABLE_VERIFIED_SESSION_QUERY_INDEPENDENT_VERIFIED_MEMORY_METABOLISM_CHECKED_FAILURE_CLOSURE_NONBLOCKING_RUNTIME_COMMAND_AND_SAFE_ORGAN_LIFECYCLE_COORDINATOR_SOURCE_IMPLEMENTED_AND_TESTED", "desktop_integrated": false, "development_id": "DEV-20260810-014" }, @@ -343,7 +343,7 @@ "DEV-20260810-013" ], "closeout_record": "HLP-DEV-20260809-007-CLOSEOUT-001", - "next_minimum_stage": "GH_PNCC_NON_UI_LIFECYCLE_COORDINATOR_FOR_REGISTERED_SAFE_ORGANS_WITHOUT_EXECUTION_LIMB", + "next_minimum_stage": "GH_PNCC_IDEMPOTENT_LIFECYCLE_REQUEST_AND_RECEIPT_REPLAY_WITHOUT_SECOND_TRUTH_STORE", "next_stage_started": true, "heartbeat_automation": "pncc", "heartbeat_state": "ACTIVE_EVERY_10_MINUTES_UNTIL_TASK_TERMINAL" diff --git a/routing/hololake-persona-native-code-channel.json b/routing/hololake-persona-native-code-channel.json index 3ebed62..acd0f00 100644 --- a/routing/hololake-persona-native-code-channel.json +++ b/routing/hololake-persona-native-code-channel.json @@ -1,8 +1,8 @@ { "schema": "hololake.persona-native-code-channel/v1", "record_id": "HLP-PERSONA-NATIVE-CODE-CHANNEL-001", - "version": "2026-08-11.4", - "state": "CURRENT_FIRST_PRODUCT_CORE_FACT_AND_FAIL_CLOSED_VERIFIED_MEMORY_RUNTIME_SOURCE_IMPLEMENTED", + "version": "2026-08-11.5", + "state": "CURRENT_FIRST_PRODUCT_CORE_SAFE_ORGAN_LIFECYCLE_COORDINATOR_SOURCE_IMPLEMENTED", "development_id": "DEV-20260810-014", "product": { "formal_name_zh": "光湖人格原生代码频道", @@ -106,6 +106,7 @@ "durable_event_and_receipt_query_source_implemented": 100, "independent_memory_metabolism_source_implemented": 100, "memory_failure_closure_and_nonblocking_runtime_command_implemented": 100, + "non_ui_safe_organ_lifecycle_coordinator_source_implemented": 100, "general_purpose_persona_runtime_implemented": 0, "human_live_projection_implemented": 0, "hololake_integrated": 0, diff --git a/routing/hololake-persona-native-code-channel.test.mjs b/routing/hololake-persona-native-code-channel.test.mjs index 9ed6248..e79e699 100644 --- a/routing/hololake-persona-native-code-channel.test.mjs +++ b/routing/hololake-persona-native-code-channel.test.mjs @@ -86,12 +86,16 @@ test("the first source runtime cycle stays distinct from integration and deploym channel.truth.memory_failure_closure_and_nonblocking_runtime_command_implemented, 100, ); + assert.equal( + channel.truth.non_ui_safe_organ_lifecycle_coordinator_source_implemented, + 100, + ); assert.equal(channel.truth.general_purpose_persona_runtime_implemented, 0); assert.equal(channel.truth.human_live_projection_implemented, 0); assert.equal(architecture.persona_native_code_channel.runtime_implemented, true); assert.equal( architecture.persona_native_code_channel.runtime_scope, - "READ_ONLY_FACT_CYCLE_FAIL_CLOSED_RECOVERY_TYPED_ORGANS_DURABLE_VERIFIED_SESSION_QUERY_INDEPENDENT_VERIFIED_MEMORY_METABOLISM_CHECKED_FAILURE_CLOSURE_AND_NONBLOCKING_RUNTIME_COMMAND_SOURCE_IMPLEMENTED_AND_TESTED", + "READ_ONLY_FACT_CYCLE_FAIL_CLOSED_RECOVERY_TYPED_ORGANS_DURABLE_VERIFIED_SESSION_QUERY_INDEPENDENT_VERIFIED_MEMORY_METABOLISM_CHECKED_FAILURE_CLOSURE_NONBLOCKING_RUNTIME_COMMAND_AND_SAFE_ORGAN_LIFECYCLE_COORDINATOR_SOURCE_IMPLEMENTED_AND_TESTED", ); assert.equal(channel.truth.hololake_integrated, 0); assert.equal(channel.truth.artifact_built, 0);