From 1cd8a1b48951775530143c61a3af2d11215d4921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20/=20ICE-P-ZY001?= Date: Tue, 11 Aug 2026 09:20:55 +0800 Subject: [PATCH] fix: bind wake receipt to event journal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- engineering/INDEX.md | 3 +- ...c-success-receipt-event-journal-binding.md | 33 +++++++++++ ...KE-PERSONA-NATIVE-CODE-CHANNEL-20260810.md | 5 ++ .../src-tauri/src/persona_code_channel.rs | 58 +++++++++++++++++-- routing/hololake-current-architecture.json | 2 +- .../hololake-persona-native-code-channel.json | 5 +- ...olake-persona-native-code-channel.test.mjs | 6 +- 7 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 engineering/operations/2026-08-11-hololake-pncc-success-receipt-event-journal-binding.md diff --git a/engineering/INDEX.md b/engineering/INDEX.md index a3711a6..ce18c07 100644 --- a/engineering/INDEX.md +++ b/engineering/INDEX.md @@ -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 06a7782;GHNQG、全新克隆与严格读回通过 | | 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 和发布待验收 | diff --git a/engineering/operations/2026-08-11-hololake-pncc-success-receipt-event-journal-binding.md b/engineering/operations/2026-08-11-hololake-pncc-success-receipt-event-journal-binding.md new file mode 100644 index 0000000..75bd37b --- /dev/null +++ b/engineering/operations/2026-08-11-hololake-pncc-success-receipt-event-journal-binding.md @@ -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//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. 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 70c2659..4866823 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 @@ -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//events.jsonl`,再与 `eventJournal` 精确比对。同步改写 +回执和外层哈希不能把人格运行轨迹指向另一份日志或另一会话。 + 成功回执里的大脑入口也不能只是载荷内的自述。检查、恢复绑定和重放会从已验证会话记录中的 人格仓库与相对大脑入口重新解析规范文件路径,再与唤醒回执的 `brainEntry` 比对。即使攻击者 同步改写成功回执并重算载荷哈希,也不能把一次真实唤醒伪装成启动了另一个大脑文件。 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 62ac514..eda0d29 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 @@ -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(); diff --git a/routing/hololake-current-architecture.json b/routing/hololake-current-architecture.json index 1951cb9..95d14ed 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_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" }, diff --git a/routing/hololake-persona-native-code-channel.json b/routing/hololake-persona-native-code-channel.json index 42f430d..63b16e4 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.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, diff --git a/routing/hololake-persona-native-code-channel.test.mjs b/routing/hololake-persona-native-code-channel.test.mjs index 57909f7..993175a 100644 --- a/routing/hololake-persona-native-code-channel.test.mjs +++ b/routing/hololake-persona-native-code-channel.test.mjs @@ -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);