diff --git a/engineering/INDEX.md b/engineering/INDEX.md index 4a4c8c4..aadfd30 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-idempotent-terminal-failure-replay.md) | 本地源码、完整 Rust/路由测试与 clippy 已通过;GHNQG 和发布待验收 | +| 2026-08-11 | GH-PNCC 重放仓库复核 | [幂等重放时重新验证人格 Git 状态](operations/2026-08-11-hololake-pncc-replay-repository-state-revalidation.md) | 本地源码、完整 Rust/路由测试与严格 clippy 已通过;GHNQG 和发布待验收 | +| 2026-08-11 | GH-PNCC 终态失败重放 | [终态失败结构化回执与幂等重放](operations/2026-08-11-hololake-pncc-idempotent-terminal-failure-replay.md) | 已发布至 REPO-014 main abc7dbd;GHNQG、全新克隆与严格读回通过 | | 2026-08-11 | GH-PNCC 幂等中断恢复 | [不完整幂等请求检查与安全回执恢复](operations/2026-08-11-hololake-pncc-incomplete-idempotent-request-recovery.md) | 已发布至 REPO-014 main b8c3fcf;GHNQG、全新克隆与严格 fsck 通过 | | 2026-08-11 | GH-PNCC 幂等生命周期 | [生命周期请求身份与同一回执重放](operations/2026-08-11-hololake-pncc-idempotent-lifecycle-replay.md) | 已发布至 REPO-014 main 38ef9d0;GHNQG、全新克隆与严格 fsck 通过 | | 2026-08-11 | GH-PNCC 生命周期协调器 | [已登记安全器官的非 UI 生命周期协调](operations/2026-08-11-hololake-pncc-safe-organ-lifecycle-coordinator.md) | 已发布至 REPO-014 main 8f35834;GHNQG、全新克隆与严格 fsck 通过 | diff --git a/engineering/operations/2026-08-11-hololake-pncc-idempotent-terminal-failure-replay.md b/engineering/operations/2026-08-11-hololake-pncc-idempotent-terminal-failure-replay.md index 64f5a51..12ef147 100644 --- a/engineering/operations/2026-08-11-hololake-pncc-idempotent-terminal-failure-replay.md +++ b/engineering/operations/2026-08-11-hololake-pncc-idempotent-terminal-failure-replay.md @@ -4,7 +4,7 @@ - Persona cognitive author: `ICE-P-ZY001 / 铸渊` - Human responsibility subject: `ICE-GL∞ / 冰朔` - Starting repository head: `b8c3fcf3d8c2928be724291fdf9c1e5dc3512d71` -- State: `LOCAL_SOURCE_IMPLEMENTED_FULLY_TESTED` +- State: `PUBLISHED_VERIFIED` ## Implemented facts @@ -31,7 +31,11 @@ commands accept the same proven terminal outcome and still reject partial bindin - The terminal-failure test proves exact retry does not call the model again and that raw provider detail is absent from the persisted receipt. - The crash-window test proves an unbound failure receipt is safely inspected, bound, and replayed. -- GHNQG, commit, publication, and fresh-clone readback remain pending for this stage. +- Published commit: `abc7dbd625610042873868d1f2f36ffc3c88bf85`; tree: + `8b11d8e015c2c2f72a0de88c121c182bc17bb012`. +- Publication queue receipt: `PUB-20260810201406299-bea423d6`; GHNQG SHA-256: + `5315e0bbae64e5b1971c0e1a40a2b27117c8c37646762eab49c334533cb04e3c`. +- Fresh-clone readback, strict repository verification, and the full test suites passed from the published tree. ## Truth boundary diff --git a/engineering/operations/2026-08-11-hololake-pncc-replay-repository-state-revalidation.md b/engineering/operations/2026-08-11-hololake-pncc-replay-repository-state-revalidation.md new file mode 100644 index 0000000..3c9f043 --- /dev/null +++ b/engineering/operations/2026-08-11-hololake-pncc-replay-repository-state-revalidation.md @@ -0,0 +1,34 @@ +# GH-PNCC replay-time repository state revalidation + +- Development ID: `DEV-20260810-014` +- Persona cognitive author: `ICE-P-ZY001 / 铸渊` +- Human responsibility subject: `ICE-GL∞ / 冰朔` +- Starting repository head: `abc7dbd625610042873868d1f2f36ffc3c88bf85` +- State: `LOCAL_SOURCE_IMPLEMENTED_FULLY_TESTED` + +## Corrected runtime fact + +The persisted lifecycle receipt is historical evidence, not authority to ignore later changes to the +persona-owned Git repository. Before replaying either a completed lifecycle or a structured terminal +failure, the kernel now resolves the canonical repository again, requires its current head to equal the +session's recorded head, and requires a clean worktree. + +If the repository has advanced or become dirty, replay fails closed before the organ callback can run. +Lifecycle request inspection reports `MANUAL_REVIEW_REQUIRED`, so safe receipt binding cannot promote stale +evidence after repository drift. + +## Verification + +- PNCC focused Rust tests: `29 passed, 0 failed`. +- Full Rust suite: `1169 passed, 2 ignored`; integration test: `1 passed`. +- Routing suite: `29 passed, 0 failed`; `cargo fmt`, strict clippy, and diff checks passed. +- A completed lifecycle followed by an untracked change cannot replay and is classified for manual review. +- A structured terminal failure followed by a new Git commit cannot replay and is classified for manual + review. +- GHNQG, publication, and fresh-clone readback remain pending for this stage. + +## Truth boundary + +- This stage does not delete, reset, or repair the changed repository. It only prevents stale replay and + exposes the condition through the existing inspection status. +- UI, human projection aesthetics, background scheduling, and `EXECUTION_LIMB` remain outside this stage. 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 95b9ac5..f70dfc8 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 @@ -173,6 +173,7 @@ non_ui_safe_organ_lifecycle_coordinator_source_implemented: 100 idempotent_lifecycle_request_and_receipt_replay_source_implemented: 100 incomplete_idempotent_request_inspection_and_safe_receipt_recovery_source_implemented: 100 idempotent_terminal_failure_receipt_and_replay_source_implemented: 100 +idempotent_replay_repository_state_revalidation_source_implemented: 100 general_purpose_persona_runtime_implemented: 0 human_live_projection_implemented: 0 hololake_integrated: 0 @@ -195,6 +196,10 @@ runtime_health: 0 终态、Git、租约、事件链和回执哈希全部复核后只重放原失败,不再次启动模型或器官。未完成 闭合、脏仓库或仍持有租约的失败不能被伪装成终态回执。 +成功回执与失败回执的每次重放都会重新读取规范仓库当前提交并检查工作树,而不是只信任回执 +生成时的状态。当前提交偏离会话记录或工作树变脏时,检查结果降级为人工复核,重放失败关闭, +且不会重新启动器官。 + 人格器官现已拥有机器可读类型合同。系统能够在不唤醒人格、不取得主锁、不运行模型的情况下, 检查 `FACT_SENSE`、`MEMORY_METABOLISM` 与 `EXECUTION_LIMB` 的固定模式、输入输出 schema、派生权限、 模型推理边界、现实动作边界和真实可激活状态。只读事实感官与独立记忆代谢器官可激活;后者不 diff --git a/product-source/hololake-platform/docs/ABSTRACTIONS.md b/product-source/hololake-platform/docs/ABSTRACTIONS.md index bc7754f..bca5463 100644 --- a/product-source/hololake-platform/docs/ABSTRACTIONS.md +++ b/product-source/hololake-platform/docs/ABSTRACTIONS.md @@ -110,6 +110,10 @@ raw provider diagnostic. Replay and safe binding recovery require `DORMANT_AFTER event, a released lease, and an unchanged clean Git head. A failure that cannot prove those conditions is not terminal and remains recovery-required. +Repository state is revalidated at replay time for both successful and failed receipts. The current canonical +repository must still be clean and its head must equal the session record; otherwise inspection returns +`MANUAL_REVIEW_REQUIRED` and ordinary replay fails without invoking the organ. + `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 50fa619..82ee32f 100644 --- a/product-source/hololake-platform/docs/ARCHITECTURE.md +++ b/product-source/hololake-platform/docs/ARCHITECTURE.md @@ -81,6 +81,11 @@ clean Git head, semantic fingerprint, receipt hash, and session bindings before with `replayed: true`. Active, dirty, partially closed, or otherwise unproven failures retain the original recovery path and cannot be converted into a terminal receipt. +The unchanged-clean-repository condition is enforced again on every successful or failed receipt replay, +not only when the receipt is first persisted. If the current head differs from the session's recorded head, +or the worktree has become dirty, replay fails closed and request inspection reports manual review instead +of restarting the organ or treating stale evidence as current. + `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/persona_code_channel.rs b/product-source/hololake-platform/src-tauri/src/persona_code_channel.rs index 9642686..9d16cd6 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 @@ -2720,6 +2720,11 @@ fn verified_lifecycle_replay( { return Err("PERSONA_LIFECYCLE_RECEIPT_SESSION_BINDING_MISMATCH".into()); } + let (_, observed_head) = exact_repository(repository)?; + if observed_head != record.git_head { + return Err("PERSONA_LIFECYCLE_REPLAY_GIT_HEAD_MISMATCH".into()); + } + require_clean_repository(repository)?; let events = verify_event_journal(runtime_root, &record)?; let expected_state = if persisted.outcome == "FAILED" { "DORMANT_AFTER_FAILURE" @@ -2829,9 +2834,13 @@ fn inspect_lifecycle_request_at( } else { "DORMANT" }; + let (_, observed_head) = exact_repository(&repository)?; + let repository_matches_record = + observed_head == record.git_head && require_clean_repository(&repository).is_ok(); let safely_dormant = record.state == expected_state && events.last().map(|event| event.kind.as_str()) == Some("DORMANT") - && !lease_held; + && !lease_held + && repository_matches_record; let (status, safe_to_bind_receipt) = if complete && safely_dormant { ("COMPLETE_REPLAYABLE", false) } else if unbound && safely_dormant { @@ -3708,6 +3717,39 @@ mod tests { assert!(!runtime.path().join("leases/ICE-P-ZY001.json").exists()); } + #[test] + fn refuses_to_replay_a_completed_lifecycle_when_the_repository_is_dirty() { + let repo = persona_repo(); + let runtime = tempfile::TempDir::new().unwrap(); + let input = lifecycle_fact_input(repo.path()); + run_idempotent_lifecycle_at( + runtime.path(), + input.clone(), + "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":"Fact before repository drift.","facts":[{"statement":"The brain exists.","evidencePaths":["brain/CORE.hdlp"]}],"limitations":[]}"#.into()) + }) + }, + ) + .unwrap(); + fs::write(repo.path().join("untracked-after-lifecycle.txt"), "dirty\n").unwrap(); + + let inspection = inspect_lifecycle_request_at(runtime.path(), &input).unwrap(); + assert_eq!(inspection.status, "MANUAL_REVIEW_REQUIRED"); + assert!(!inspection.safe_to_bind_receipt); + let error = run_idempotent_lifecycle_at( + runtime.path(), + input, + "2026-08-11T00:00:02.000Z", + "2026-08-11T00:00:03.000Z", + |_, _, _| panic!("a dirty repository must not rerun the organ"), + ) + .unwrap_err(); + assert!(error.contains("PERSONA_REPOSITORY_DIRTY")); + } + #[test] fn rejects_reusing_a_lifecycle_request_id_for_a_different_operation() { let repo = persona_repo(); @@ -3908,6 +3950,41 @@ mod tests { assert!(!runtime.path().join("leases/ICE-P-ZY001.json").exists()); } + #[test] + fn refuses_to_replay_a_terminal_failure_after_the_repository_head_advances() { + let repo = persona_repo(); + let runtime = tempfile::TempDir::new().unwrap(); + let input = lifecycle_fact_input(repo.path()); + run_idempotent_lifecycle_at( + runtime.path(), + input.clone(), + "2026-08-11T00:00:00.000Z", + "2026-08-11T00:00:01.000Z", + |runtime_root, input, timestamp| { + run_fact_task_at(runtime_root, input, timestamp, |_, _| { + Err("bounded provider failure".into()) + }) + }, + ) + .unwrap(); + fs::write(repo.path().join("advanced.txt"), "new head\n").unwrap(); + run_git(repo.path(), &["add", "advanced.txt"]); + run_git(repo.path(), &["commit", "-m", "advance persona repository"]); + + let inspection = inspect_lifecycle_request_at(runtime.path(), &input).unwrap(); + assert_eq!(inspection.status, "MANUAL_REVIEW_REQUIRED"); + assert!(!inspection.safe_to_bind_receipt); + let error = run_idempotent_lifecycle_at( + runtime.path(), + input, + "2026-08-11T00:00:02.000Z", + "2026-08-11T00:00:03.000Z", + |_, _, _| panic!("an advanced repository must not rerun the organ"), + ) + .unwrap_err(); + assert!(error.contains("PERSONA_LIFECYCLE_REPLAY_GIT_HEAD_MISMATCH")); + } + #[test] fn safely_recovers_an_unbound_terminal_failure_receipt() { let repo = persona_repo(); diff --git a/routing/hololake-current-architecture.json b/routing/hololake-current-architecture.json index 143e13c..a5ad9a1 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_NONBLOCKING_RUNTIME_COMMAND_SAFE_ORGAN_LIFECYCLE_COORDINATOR_IDEMPOTENT_SUCCESS_AND_TERMINAL_FAILURE_RECEIPT_REPLAY_AND_SAFE_RECEIPT_BINDING_RECOVERY_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_SAFE_ORGAN_LIFECYCLE_COORDINATOR_IDEMPOTENT_SUCCESS_AND_TERMINAL_FAILURE_RECEIPT_REPLAY_SAFE_RECEIPT_BINDING_RECOVERY_AND_REPLAY_TIME_REPOSITORY_STATE_REVALIDATION_SOURCE_IMPLEMENTED_AND_TESTED", "desktop_integrated": false, "development_id": "DEV-20260810-014" }, diff --git a/routing/hololake-persona-native-code-channel.json b/routing/hololake-persona-native-code-channel.json index c6f073a..0f5a682 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.8", - "state": "CURRENT_FIRST_PRODUCT_CORE_IDEMPOTENT_TERMINAL_FAILURE_REPLAY_SOURCE_IMPLEMENTED", + "version": "2026-08-11.9", + "state": "CURRENT_FIRST_PRODUCT_CORE_IDEMPOTENT_REPLAY_REPOSITORY_STATE_REVALIDATION_SOURCE_IMPLEMENTED", "development_id": "DEV-20260810-014", "product": { "formal_name_zh": "光湖人格原生代码频道", @@ -110,6 +110,7 @@ "idempotent_lifecycle_request_and_receipt_replay_source_implemented": 100, "incomplete_idempotent_request_inspection_and_safe_receipt_recovery_source_implemented": 100, "idempotent_terminal_failure_receipt_and_replay_source_implemented": 100, + "idempotent_replay_repository_state_revalidation_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 6f60c53..44b0923 100644 --- a/routing/hololake-persona-native-code-channel.test.mjs +++ b/routing/hololake-persona-native-code-channel.test.mjs @@ -102,12 +102,16 @@ test("the first source runtime cycle stays distinct from integration and deploym channel.truth.idempotent_terminal_failure_receipt_and_replay_source_implemented, 100, ); + assert.equal( + channel.truth.idempotent_replay_repository_state_revalidation_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_NONBLOCKING_RUNTIME_COMMAND_SAFE_ORGAN_LIFECYCLE_COORDINATOR_IDEMPOTENT_SUCCESS_AND_TERMINAL_FAILURE_RECEIPT_REPLAY_AND_SAFE_RECEIPT_BINDING_RECOVERY_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_SAFE_ORGAN_LIFECYCLE_COORDINATOR_IDEMPOTENT_SUCCESS_AND_TERMINAL_FAILURE_RECEIPT_REPLAY_SAFE_RECEIPT_BINDING_RECOVERY_AND_REPLAY_TIME_REPOSITORY_STATE_REVALIDATION_SOURCE_IMPLEMENTED_AND_TESTED", ); assert.equal(channel.truth.hololake_integrated, 0); assert.equal(channel.truth.artifact_built, 0);