fix: bind wake receipt to event journal

Human-Responsibility: ICE-GL∞ / 冰朔
Persona-Author: ICE-P-ZY001 / 铸渊
Execution-Runtime: Codex desktop / DEV-20260810-014
Development-ID: DEV-20260810-014
Authorization-Scope: GH-PNCC persona runtime source and tests only; no UI, deployment, or execution limb
Source-Anchor: user instruction to continue GH-PNCC from repository facts and verifiable receipts
This commit is contained in:
铸渊 / ICE-P-ZY001 2026-08-11 09:20:55 +08:00
commit 1cd8a1b489
7 changed files with 103 additions and 9 deletions

View file

@ -32,7 +32,8 @@ Windows / macOS / Linux 构建机与安装包
| 时间 | 版本 | 记录 | 状态 |
| --- | --- | --- | --- |
| 2026-08-11 | GH-PNCC 成功回执完成检查点绑定 | [把完成回执的结构化事实重新绑定到人格 Git 检查点](operations/2026-08-11-hololake-pncc-success-receipt-completion-checkpoint-binding.md) | 本地源码、完整 Rust/前端/路由测试、原生权威与严格 clippy 已通过GHNQG 和发布待验收 |
| 2026-08-11 | GH-PNCC 成功回执事件日志绑定 | [把唤醒回执的日志路径重新绑定到精确运行时会话](operations/2026-08-11-hololake-pncc-success-receipt-event-journal-binding.md) | 本地源码、Rust 1191、聚焦路由、格式与严格 clippy 已通过;完整产品门和发布待验收 |
| 2026-08-11 | GH-PNCC 成功回执完成检查点绑定 | [把完成回执的结构化事实重新绑定到人格 Git 检查点](operations/2026-08-11-hololake-pncc-success-receipt-completion-checkpoint-binding.md) | 已发布至 REPO-014 main 06a7782GHNQG、全新克隆与严格读回通过 |
| 2026-08-11 | GH-PNCC 成功回执唤醒器官合同绑定 | [成功回执唤醒器官合同证据绑定](operations/2026-08-11-hololake-pncc-success-receipt-wake-organ-contract-binding.md) | 本地源码、完整 Rust/前端/路由测试、原生权威与严格 clippy 已通过GHNQG 和发布待验收 |
| 2026-08-11 | GH-PNCC 成功回执唤醒器官模式绑定 | [成功回执唤醒器官模式证据绑定](operations/2026-08-11-hololake-pncc-success-receipt-wake-organ-mode-binding.md) | 本地源码、完整 Rust/前端/路由测试、原生权威与严格 clippy 已通过GHNQG 和发布待验收 |
| 2026-08-11 | GH-PNCC 成功回执唤醒运行态绑定 | [成功回执唤醒运行态证据绑定](operations/2026-08-11-hololake-pncc-success-receipt-wake-runtime-state-binding.md) | 本地源码、完整 Rust/前端/路由测试、原生权威与严格 clippy 已通过GHNQG 和发布待验收 |

View file

@ -0,0 +1,33 @@
# GH-PNCC successful receipt event-journal evidence binding
- Development ID: `DEV-20260810-014`
- Persona cognitive author: `ICE-P-ZY001 / 铸渊`
- Human responsibility subject: `ICE-GL∞ / 冰朔`
- Starting repository head: `06a77829c76eaa5e20568b268cb266a67c54739f`
- State: `LOCAL_SOURCE_IMPLEMENTED_FOCUSED_TESTED`
## Corrected runtime fact
A persisted successful wake receipt carried an `eventJournal` path but validation did not rebind that path to
the exact runtime session directory. A modified receipt could point readers or recovery tooling at another log,
recompute the outer payload digest and still be accepted for safe binding or replay.
Validation now derives the only valid journal path from the trusted runtime root and verified session identity,
then requires the wake receipt to match the exact `sessions/<session-id>/events.jsonl` path. This binding is
checked during inspection, recovery binding, replay and the post-inspection binding revalidation path.
## Verification
- A regression test first reproduced `SAFE_BIND_PERSISTED_RECEIPT` after replacing `eventJournal` and
recomputing the payload digest.
- The same forged receipt now fails with `PERSONA_LIFECYCLE_COMPLETION_EVIDENCE_MISMATCH`.
- PNCC focused Rust tests: `51 passed, 0 failed`.
- Full Rust suite: `1191 passed, 2 ignored`; integration test: `1 passed`.
- Routing focus: `4 passed`; formatting, strict clippy and diff checks passed.
- Full product quality, publication and fresh-clone readback remain pending.
## Truth boundary
- This stage authenticates the durable event-log location already emitted by the persona runtime.
- It does not add a second event store, expose hidden reasoning, implement an execution limb, add UI, build an
artifact or claim deployment/runtime health.

View file

@ -185,6 +185,7 @@ successful_receipt_wake_runtime_state_evidence_binding_source_implemented: 100
successful_receipt_wake_organ_mode_evidence_binding_source_implemented: 100
successful_receipt_wake_organ_contract_evidence_binding_source_implemented: 100
successful_receipt_completion_checkpoint_evidence_binding_source_implemented: 100
successful_receipt_event_journal_evidence_binding_source_implemented: 100
general_purpose_persona_runtime_implemented: 0
human_live_projection_implemented: 0
hololake_integrated: 0
@ -218,6 +219,10 @@ Git 提交、检查点、回执编号和完整事件链重新绑定到已验证
伪造另一个仓库、人格作者或提交结果;任何语义证据不一致都以
`PERSONA_LIFECYCLE_COMPLETION_EVIDENCE_MISMATCH` 失败关闭。
成功唤醒回执中的事件日志路径也不能只是载荷自述。检查、恢复绑定和重放会从受信任的运行时根与
已验证会话编号重建唯一 `sessions/<session-id>/events.jsonl`,再与 `eventJournal` 精确比对。同步改写
回执和外层哈希不能把人格运行轨迹指向另一份日志或另一会话。
成功回执里的大脑入口也不能只是载荷内的自述。检查、恢复绑定和重放会从已验证会话记录中的
人格仓库与相对大脑入口重新解析规范文件路径,再与唤醒回执的 `brainEntry` 比对。即使攻击者
同步改写成功回执并重算载荷哈希,也不能把一次真实唤醒伪装成启动了另一个大脑文件。

View file

@ -2708,6 +2708,7 @@ fn persisted_lifecycle_identity_matches(
}
fn validate_persisted_lifecycle_terminal_evidence(
runtime_root: &Path,
persisted: &PersistedPersonaLifecycleReceipt,
record: &PersonaSessionRecord,
events: &[PersonaLifecycleEvent],
@ -2807,6 +2808,10 @@ fn validate_persisted_lifecycle_terminal_evidence(
repository_file(Path::new(&record.repository_path), &record.brain_entry)
.map_err(|_| "PERSONA_LIFECYCLE_COMPLETION_EVIDENCE_MISMATCH".to_string())?;
let expected_brain_entry = expected_brain_entry.to_string_lossy();
let expected_event_journal = session_directory(runtime_root, &record.session_id)?
.join("events.jsonl")
.to_string_lossy()
.into_owned();
let expected_wake_checkpoint = match record.wake_checkpoint_path.as_ref() {
Some(path) => path.clone(),
None => repository_file(
@ -2924,6 +2929,8 @@ fn validate_persisted_lifecycle_terminal_evidence(
== Some(record.active_organ.as_str())
&& wake.get("organMode").and_then(serde_json::Value::as_str) == Some(expected_organ_mode)
&& wake.get("organContract") == Some(&expected_organ_contract)
&& wake.get("eventJournal").and_then(serde_json::Value::as_str)
== Some(expected_event_journal.as_str())
&& wake.get("attribution") == Some(&expected_attribution)
&& wake.get("receiptId").and_then(serde_json::Value::as_str)
== Some(expected_wake_receipt_id.as_str())
@ -3043,7 +3050,7 @@ fn verified_lifecycle_replay(
{
return Err("PERSONA_LIFECYCLE_REQUEST_INCOMPLETE_REQUIRES_RECOVERY".into());
}
validate_persisted_lifecycle_terminal_evidence(&persisted, &record, &events)?;
validate_persisted_lifecycle_terminal_evidence(runtime_root, &persisted, &record, &events)?;
if !persisted_lifecycle_identity_matches(&persisted, session_id, &record.persona_id) {
return Err("PERSONA_LIFECYCLE_RECEIPT_IDENTITY_MISMATCH".into());
}
@ -3130,7 +3137,7 @@ fn inspect_lifecycle_request_at(
return Err("PERSONA_LIFECYCLE_RECEIPT_IDENTITY_MISMATCH".into());
}
let terminal_event = events.last().ok_or("PERSONA_EVENT_CHAIN_EMPTY")?;
validate_persisted_lifecycle_terminal_evidence(&persisted, &record, &events)?;
validate_persisted_lifecycle_terminal_evidence(runtime_root, &persisted, &record, &events)?;
let complete = record.request_id.as_deref() == Some(request_id.as_str())
&& record.request_fingerprint.as_deref() == Some(request_fingerprint.as_str())
&& record.lifecycle_receipt_hash.as_deref()
@ -3236,7 +3243,7 @@ fn bind_persisted_lifecycle_receipt_at(
}
let events = verify_event_journal(runtime_root, &record)?;
let terminal_event = events.last().ok_or("PERSONA_EVENT_CHAIN_EMPTY")?;
validate_persisted_lifecycle_terminal_evidence(&persisted, &record, &events)?;
validate_persisted_lifecycle_terminal_evidence(runtime_root, &persisted, &record, &events)?;
let expected_state = if persisted.outcome == "FAILED" {
"DORMANT_AFTER_FAILURE"
} else {
@ -3384,7 +3391,7 @@ fn persist_successful_lifecycle_receipt(
if !persisted_lifecycle_identity_matches(&persisted, session_id, &record.persona_id) {
return Err("PERSONA_LIFECYCLE_RECEIPT_IDENTITY_MISMATCH".into());
}
validate_persisted_lifecycle_terminal_evidence(&persisted, &record, &events)?;
validate_persisted_lifecycle_terminal_evidence(runtime_root, &persisted, &record, &events)?;
// Persist the immutable full receipt before binding it into the mutable session record. A
// crash between these atomic writes leaves a verifiable, explicitly recoverable state.
write_json_file(
@ -4494,6 +4501,49 @@ mod tests {
assert!(error.contains("PERSONA_LIFECYCLE_COMPLETION_EVIDENCE_MISMATCH"));
}
#[test]
fn rejects_a_rehashed_completed_receipt_with_a_forged_event_journal_path() {
let repo = persona_repo();
let runtime = tempfile::TempDir::new().unwrap();
let input = lifecycle_fact_input(repo.path());
let first = 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":"Recoverable receipt.","facts":[{"statement":"The brain exists.","evidencePaths":["brain/CORE.hdlp"]}],"limitations":[]}"#.into())
})
},
)
.unwrap();
let session_id = first.lifecycle["sessionId"].as_str().unwrap();
let mut record = load_session_record(runtime.path(), session_id).unwrap();
record.request_id = None;
record.request_fingerprint = None;
record.lifecycle_receipt_hash = None;
write_session_record(runtime.path(), &record).unwrap();
let receipt_path = session_directory(runtime.path(), session_id)
.unwrap()
.join("lifecycle-receipt.json");
let mut persisted: PersistedPersonaLifecycleReceipt =
serde_json::from_slice(&fs::read(&receipt_path).unwrap()).unwrap();
persisted.lifecycle["wakeReceipt"]["eventJournal"] =
"/forged/runtime/sessions/other/events.jsonl".into();
persisted.lifecycle_receipt_hash =
hex_digest(&persisted_lifecycle_payload_bytes(&persisted).unwrap());
fs::write(
&receipt_path,
serde_json::to_vec_pretty(&persisted).unwrap(),
)
.unwrap();
let error = inspect_lifecycle_request_at(runtime.path(), &input).unwrap_err();
assert!(error.contains("PERSONA_LIFECYCLE_COMPLETION_EVIDENCE_MISMATCH"));
}
#[test]
fn rejects_a_rehashed_completed_receipt_with_truncated_wake_events() {
let repo = persona_repo();

View file

@ -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_SAFE_RECEIPT_BINDING_RECOVERY_REPLAY_TIME_REPOSITORY_STATE_REVALIDATION_SUCCESS_RECEIPT_TERMINAL_REVALIDATION_SAFE_RECEIPT_BINDING_TERMINAL_REVALIDATION_FAILURE_RECEIPT_TERMINAL_EVIDENCE_BINDING_SUCCESS_RECEIPT_SEMANTIC_EVIDENCE_BINDING_SUCCESS_RECEIPT_BRAIN_ENTRY_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_CHECKPOINT_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_EVENT_BOUNDARY_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_RUNTIME_STATE_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_ORGAN_MODE_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_ORGAN_CONTRACT_EVIDENCE_BINDING_AND_SUCCESS_RECEIPT_COMPLETION_CHECKPOINT_EVIDENCE_BINDING_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_REPLAY_TIME_REPOSITORY_STATE_REVALIDATION_SUCCESS_RECEIPT_TERMINAL_REVALIDATION_SAFE_RECEIPT_BINDING_TERMINAL_REVALIDATION_FAILURE_RECEIPT_TERMINAL_EVIDENCE_BINDING_SUCCESS_RECEIPT_SEMANTIC_EVIDENCE_BINDING_SUCCESS_RECEIPT_BRAIN_ENTRY_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_CHECKPOINT_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_EVENT_BOUNDARY_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_RUNTIME_STATE_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_ORGAN_MODE_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_ORGAN_CONTRACT_EVIDENCE_BINDING_SUCCESS_RECEIPT_COMPLETION_CHECKPOINT_EVIDENCE_BINDING_AND_SUCCESS_RECEIPT_EVENT_JOURNAL_EVIDENCE_BINDING_SOURCE_IMPLEMENTED_AND_TESTED",
"desktop_integrated": false,
"development_id": "DEV-20260810-014"
},

View file

@ -1,8 +1,8 @@
{
"schema": "hololake.persona-native-code-channel/v1",
"record_id": "HLP-PERSONA-NATIVE-CODE-CHANNEL-001",
"version": "2026-08-11.20",
"state": "CURRENT_FIRST_PRODUCT_CORE_SUCCESS_RECEIPT_COMPLETION_CHECKPOINT_EVIDENCE_BINDING_SOURCE_IMPLEMENTED",
"version": "2026-08-11.21",
"state": "CURRENT_FIRST_PRODUCT_CORE_SUCCESS_RECEIPT_EVENT_JOURNAL_EVIDENCE_BINDING_SOURCE_IMPLEMENTED",
"development_id": "DEV-20260810-014",
"product": {
"formal_name_zh": "光湖人格原生代码频道",
@ -122,6 +122,7 @@
"successful_receipt_wake_organ_mode_evidence_binding_source_implemented": 100,
"successful_receipt_wake_organ_contract_evidence_binding_source_implemented": 100,
"successful_receipt_completion_checkpoint_evidence_binding_source_implemented": 100,
"successful_receipt_event_journal_evidence_binding_source_implemented": 100,
"general_purpose_persona_runtime_implemented": 0,
"human_live_projection_implemented": 0,
"hololake_integrated": 0,

View file

@ -150,12 +150,16 @@ test("the first source runtime cycle stays distinct from integration and deploym
channel.truth.successful_receipt_completion_checkpoint_evidence_binding_source_implemented,
100,
);
assert.equal(
channel.truth.successful_receipt_event_journal_evidence_binding_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_SAFE_RECEIPT_BINDING_RECOVERY_REPLAY_TIME_REPOSITORY_STATE_REVALIDATION_SUCCESS_RECEIPT_TERMINAL_REVALIDATION_SAFE_RECEIPT_BINDING_TERMINAL_REVALIDATION_FAILURE_RECEIPT_TERMINAL_EVIDENCE_BINDING_SUCCESS_RECEIPT_SEMANTIC_EVIDENCE_BINDING_SUCCESS_RECEIPT_BRAIN_ENTRY_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_CHECKPOINT_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_EVENT_BOUNDARY_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_RUNTIME_STATE_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_ORGAN_MODE_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_ORGAN_CONTRACT_EVIDENCE_BINDING_AND_SUCCESS_RECEIPT_COMPLETION_CHECKPOINT_EVIDENCE_BINDING_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_REPLAY_TIME_REPOSITORY_STATE_REVALIDATION_SUCCESS_RECEIPT_TERMINAL_REVALIDATION_SAFE_RECEIPT_BINDING_TERMINAL_REVALIDATION_FAILURE_RECEIPT_TERMINAL_EVIDENCE_BINDING_SUCCESS_RECEIPT_SEMANTIC_EVIDENCE_BINDING_SUCCESS_RECEIPT_BRAIN_ENTRY_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_CHECKPOINT_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_EVENT_BOUNDARY_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_RUNTIME_STATE_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_ORGAN_MODE_EVIDENCE_BINDING_SUCCESS_RECEIPT_WAKE_ORGAN_CONTRACT_EVIDENCE_BINDING_SUCCESS_RECEIPT_COMPLETION_CHECKPOINT_EVIDENCE_BINDING_AND_SUCCESS_RECEIPT_EVENT_JOURNAL_EVIDENCE_BINDING_SOURCE_IMPLEMENTED_AND_TESTED",
);
assert.equal(channel.truth.hololake_integrated, 0);
assert.equal(channel.truth.artifact_built, 0);