feat: query verified PNCC runtime history

GuangHu-Human-Responsibility: ICE-GL∞ / 冰朔
GuangHu-Persona-Cognitive-Author: ICE-P-ZY001 / 铸渊
GuangHu-Execution-Runtime: Codex thread 019febf6-3902-70f3-9d82-74c9680b0c7e
GuangHu-Development-ID: DEV-20260810-014
GuangHu-Authorization-Scope: LOCAL_PNCC_RUNTIME_DEVELOPMENT_AND_PUBLICATION
This commit is contained in:
铸渊 / ICE-P-ZY001 2026-08-11 01:51:02 +08:00
commit 33b3b67ce7
10 changed files with 289 additions and 3 deletions

View file

@ -32,6 +32,7 @@ Windows / macOS / Linux 构建机与安装包
| 时间 | 版本 | 记录 | 状态 |
| --- | --- | --- | --- |
| 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仓库发布、桌面集成与部署待验收 |
| 2026-08-11 | GH-PNCC 首个运行闭环 | [人格原生代码频道首个只读运行层回执](operations/2026-08-11-hololake-pncc-first-runtime-cycle.md) | 源码与测试闭环已完成;人类投影、桌面制品、发布、部署与在线健康仍未完成 |

View file

@ -0,0 +1,38 @@
# GH-PNCC durable runtime event and receipt query
- Development ID: `DEV-20260810-014`
- Persona cognitive author: `ICE-P-ZY001 / 铸渊`
- Human responsibility subject: `ICE-GL∞ / 冰朔`
- State: `LOCAL_SOURCE_IMPLEMENTED_AND_FULL_RUST_ROUTING_TESTED`
## Implemented facts
`query_persona_code_channel_runtime` provides the runtime-side read model needed by a later human projection,
without building the UI or creating a second truth database. A query must name one exact persona and one
canonical repository. It reads only the existing installation-local session records and event journals,
filters to that identity/repository pair, verifies every returned SHA-256 event chain, sorts by the newest
event, and enforces a caller limit from 1 to 100.
Each summary returns the session state, Git head, node, model instance, actual active organ, event count,
first/last event time, last event kind, event-chain head and structured human/persona attribution. Dormant
sessions return no active organ. The query does not start inference, acquire or release a lease, expose model
thinking, or copy the events into another store. A corrupted matching journal rejects the query.
## Current verification
- PNCC focused Rust tests: `14 passed, 0 failed`.
- Rust full suite: `1154 passed, 0 failed, 2 ignored`; integration test `1 passed`.
- Rust clippy for all targets: `PASS` with `-D warnings`.
- HoloLake architecture routing: `29 passed, 0 failed`.
- Tests cover bounded ordering, identity/repository filtering basis, dormant/active projection semantics,
invalid limits, corrupted-chain refusal, organ contracts, recovery and attribution.
## Remaining acceptance
- GHNQG pre-push quality gate;
- repository commit, publication and fresh-clone readback;
- independent memory-metabolism executor;
- bounded execution-limb executor and reality receipts;
- UI, packaged desktop, installation, deployment and online health.
This receipt proves local source behavior only.

View file

@ -166,6 +166,7 @@ persona_git_identity_commit_implemented: 100
semantic_attribution_first_cycle_implemented: 100
interrupted_session_inspection_and_recovery_source_implemented: 100
typed_organ_contract_and_manifest_inspection_source_implemented: 100
durable_event_and_receipt_query_source_implemented: 100
general_purpose_persona_runtime_implemented: 0
human_live_projection_implemented: 0
hololake_integrated: 0
@ -187,3 +188,7 @@ runtime_health: 0
检查 `FACT_SENSE``MEMORY_METABOLISM``EXECUTION_LIMB` 的固定模式、输入输出 schema、派生权限、
模型推理边界、现实动作边界和真实可激活状态。当前只有只读事实感官可激活;清单里写出记忆器官
或执行手脚不会自动产生执行器,更不会自动获得 shell 或现实动作权限。
运行层现在还提供同源有界查询:调用者必须给出精确人格与精确仓库,最多返回 100 条经过事件
哈希链验证的会话摘要包括生命周期状态、Git 头、节点、模型实例、活跃器官、事件数量、链头和
双层归因。该查询不复制第二套数据库、不启动模型、不取得主锁;匹配会话的事件链损坏时失败关闭。

View file

@ -64,6 +64,12 @@ inspection receipt reports them as not independently activatable until their exe
an execution-limb declaration never grants a shell or reality action by itself. The inspection command reads
and validates all contracts without acquiring a runtime lease or starting model inference.
`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
the event-chain head and human/persona attribution so a future renderer can link a summary back to the same
machine evidence rather than trusting display state.
## `HoloLakeUiPlugin`
A versioned, declarative presentation package for one host-owned semantic surface. It contains a manifest,

View file

@ -43,6 +43,13 @@ schemas, derived permissions, inference/reality-action boundaries, and the actua
implemented read-only fact sense can wake. Merely declaring a memory organ or execution limb does not create
an executor or grant a shell; those contracts remain visible but fail closed as not activatable.
`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
event, and returns lifecycle state, Git head, node/model instance, active organ, event count, chain head and
structured attribution. It does not copy facts into a second database, expose hidden reasoning, acquire a
lease, or start inference. A corrupted matching journal fails the query closed.
## User-node sovereignty
HoloLake has no platform-hosted user runtime. Each human has one canonical, independently operated node:

View file

@ -525,6 +525,7 @@ macro_rules! app_invoke_handler {
guanghu_living_system::guanghu_living_system_plan,
persona_code_channel::prepare_persona_code_channel_wake,
persona_code_channel::inspect_persona_code_channel_manifest,
persona_code_channel::query_persona_code_channel_runtime,
persona_code_channel::run_persona_code_channel_fact_task,
persona_code_channel::inspect_persona_code_channel_session,
persona_code_channel::recover_persona_code_channel_session,

View file

@ -13,6 +13,7 @@ const MAX_FACT_QUESTION_BYTES: usize = 8_000;
const MAX_FACT_SOURCE_BYTES: usize = 128_000;
const MAX_FACT_CONTEXT_BYTES: usize = 512_000;
const MAX_FACT_RESPONSE_BYTES: usize = 128_000;
const MAX_SESSION_QUERY_LIMIT: usize = 100;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
@ -169,6 +170,44 @@ pub struct PersonaManifestInspectionReceipt {
pub organ_contracts: Vec<PersonaOrganContract>,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaRuntimeQueryInput {
pub expected_persona_id: String,
pub expected_repository_path: String,
pub limit: Option<usize>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaRuntimeSessionProjection {
pub session_id: String,
pub state: String,
pub git_head: String,
pub node_id: String,
pub model_instance_id: String,
pub active_organ: Option<String>,
pub event_count: usize,
pub first_event_at: String,
pub last_event_at: String,
pub last_event: String,
pub event_chain_head: String,
pub attribution: PersonaAttribution,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaRuntimeQueryReceipt {
pub schema: &'static str,
pub persona_id: String,
pub repository_path: String,
pub observed_git_head: String,
pub repository_clean: bool,
pub matching_session_count: usize,
pub returned_session_count: usize,
pub sessions: Vec<PersonaRuntimeSessionProjection>,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaFactTaskInput {
@ -1439,6 +1478,99 @@ fn inspect_session_at(
})
}
fn query_runtime_sessions_at(
runtime_root: &Path,
input: PersonaRuntimeQueryInput,
) -> Result<PersonaRuntimeQueryReceipt, String> {
let expected_persona_id = validated_id("EXPECTED_PERSONA_ID", &input.expected_persona_id)?;
let limit = input.limit.unwrap_or(25);
if limit == 0 || limit > MAX_SESSION_QUERY_LIMIT {
return Err("PERSONA_SESSION_QUERY_LIMIT_INVALID".into());
}
let expected_repository = Path::new(&input.expected_repository_path)
.canonicalize()
.map_err(|error| format!("PERSONA_REPOSITORY_UNAVAILABLE: {error}"))?;
let (repository, observed_head) = exact_repository(&expected_repository)?;
let repository_clean = repository_is_clean(&repository)?;
let sessions_root = runtime_root.join("sessions");
let entries = match fs::read_dir(&sessions_root) {
Ok(entries) => entries,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
return Ok(PersonaRuntimeQueryReceipt {
schema: "hololake.pncc-runtime-query/v1",
persona_id: expected_persona_id,
repository_path: repository.to_string_lossy().into_owned(),
observed_git_head: observed_head,
repository_clean,
matching_session_count: 0,
returned_session_count: 0,
sessions: Vec::new(),
});
}
Err(error) => return Err(format!("PERSONA_SESSIONS_DIRECTORY_READ_FAILED: {error}")),
};
let mut projections = Vec::new();
for entry in entries {
let entry = entry.map_err(|error| format!("PERSONA_SESSION_ENTRY_FAILED: {error}"))?;
if !entry
.file_type()
.map_err(|error| format!("PERSONA_SESSION_ENTRY_TYPE_FAILED: {error}"))?
.is_dir()
{
continue;
}
let session_id = match entry.file_name().to_str() {
Some(value) => validated_id("SESSION_ID", value)?,
None => return Err("PERSONA_SESSION_ID_NOT_UTF8".into()),
};
let record = load_session_record(runtime_root, &session_id)?;
if record.persona_id != expected_persona_id
|| Path::new(&record.repository_path) != repository
{
continue;
}
let events = verify_event_journal(runtime_root, &record)?;
let first = events.first().expect("verified non-empty event chain");
let last = events.last().expect("verified non-empty event chain");
projections.push(PersonaRuntimeSessionProjection {
session_id: record.session_id,
state: record.state.clone(),
git_head: record.git_head,
node_id: record.node_id,
model_instance_id: record.model_instance_id,
active_organ: if record.state.starts_with("DORMANT") {
None
} else {
Some(record.active_organ)
},
event_count: events.len(),
first_event_at: first.timestamp.clone(),
last_event_at: last.timestamp.clone(),
last_event: last.kind.clone(),
event_chain_head: last.event_hash.clone(),
attribution: record.attribution,
});
}
projections.sort_by(|left, right| {
right
.last_event_at
.cmp(&left.last_event_at)
.then_with(|| right.session_id.cmp(&left.session_id))
});
let matching_session_count = projections.len();
projections.truncate(limit);
Ok(PersonaRuntimeQueryReceipt {
schema: "hololake.pncc-runtime-query/v1",
persona_id: expected_persona_id,
repository_path: repository.to_string_lossy().into_owned(),
observed_git_head: observed_head,
repository_clean,
matching_session_count,
returned_session_count: projections.len(),
sessions: projections,
})
}
fn recover_session_at(
runtime_root: &Path,
input: PersonaSessionControlInput,
@ -1802,6 +1934,14 @@ pub fn inspect_persona_code_channel_manifest(
inspect_manifest_at(input)
}
#[tauri::command]
pub fn query_persona_code_channel_runtime(
input: PersonaRuntimeQueryInput,
) -> Result<PersonaRuntimeQueryReceipt, String> {
let runtime_root = crate::app_config::preferred_app_config_path("pncc-runtime")?;
query_runtime_sessions_at(&runtime_root, input)
}
#[tauri::command]
pub async fn run_persona_code_channel_fact_task(
input: PersonaFactTaskInput,
@ -2007,6 +2147,14 @@ mod tests {
}
}
fn runtime_query(repo: &Path, limit: Option<usize>) -> PersonaRuntimeQueryInput {
PersonaRuntimeQueryInput {
expected_persona_id: "ICE-P-ZY001".into(),
expected_repository_path: repo.to_string_lossy().into_owned(),
limit,
}
}
#[test]
fn prepares_exact_persona_git_wake_with_hash_chained_events() {
let repo = persona_repo();
@ -2471,4 +2619,79 @@ mod tests {
.unwrap_err()
.contains("ORGAN_NOT_ACTIVATABLE"));
}
#[test]
fn queries_bounded_verified_runtime_projections_without_a_second_store() {
let repo = persona_repo();
let runtime = tempfile::TempDir::new().unwrap();
prepare_wake_at(
runtime.path(),
wake_input(repo.path()),
"PNCC-SESSION-HISTORY-001",
"2026-08-11T00:00:00.000Z",
)
.unwrap();
recover_session_at(
runtime.path(),
session_control(repo.path(), "PNCC-SESSION-HISTORY-001"),
"2026-08-11T00:01:00.000Z",
)
.unwrap();
prepare_wake_at(
runtime.path(),
wake_input(repo.path()),
"PNCC-SESSION-HISTORY-002",
"2026-08-11T00:02:00.000Z",
)
.unwrap();
let receipt =
query_runtime_sessions_at(runtime.path(), runtime_query(repo.path(), Some(1))).unwrap();
assert_eq!(receipt.matching_session_count, 2);
assert_eq!(receipt.returned_session_count, 1);
assert_eq!(receipt.sessions[0].session_id, "PNCC-SESSION-HISTORY-002");
assert_eq!(receipt.sessions[0].last_event, "ORGAN_ACTIVE");
assert_eq!(
receipt.sessions[0].active_organ.as_deref(),
Some("fact-sense.repository")
);
assert_eq!(receipt.sessions[0].event_count, 3);
assert!(!receipt.sessions[0].event_chain_head.is_empty());
assert_eq!(
receipt.sessions[0].attribution.persona_cognitive_author,
"ICE-P-ZY001"
);
}
#[test]
fn runtime_query_rejects_invalid_limits_and_corrupted_event_chains() {
let repo = persona_repo();
let runtime = tempfile::TempDir::new().unwrap();
assert!(
query_runtime_sessions_at(runtime.path(), runtime_query(repo.path(), Some(0)))
.unwrap_err()
.contains("LIMIT_INVALID")
);
prepare_wake_at(
runtime.path(),
wake_input(repo.path()),
"PNCC-SESSION-CORRUPTED",
"2026-08-11T00:00:00.000Z",
)
.unwrap();
let journal = runtime
.path()
.join("sessions/PNCC-SESSION-CORRUPTED/events.jsonl");
let content = fs::read_to_string(&journal).unwrap();
fs::write(
&journal,
content.replacen("\"eventHash\":\"", "\"eventHash\":\"00", 1),
)
.unwrap();
assert!(
query_runtime_sessions_at(runtime.path(), runtime_query(repo.path(), Some(10)))
.unwrap_err()
.contains("EVENT_HASH_INVALID")
);
}
}

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_AND_TYPED_ORGAN_MANIFEST_INSPECTION_SOURCE_IMPLEMENTED_AND_TESTED",
"runtime_scope": "READ_ONLY_FACT_CYCLE_FAIL_CLOSED_RECOVERY_TYPED_ORGANS_AND_DURABLE_VERIFIED_SESSION_QUERY_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_DURABLE_EVENT_AND_RECEIPT_QUERY_API_WITHOUT_UI",
"next_minimum_stage": "GH_PNCC_INDEPENDENT_MEMORY_METABOLISM_EXECUTOR_WITHOUT_UI",
"next_stage_started": true,
"heartbeat_automation": "pncc",
"heartbeat_state": "ACTIVE_EVERY_10_MINUTES_UNTIL_TASK_TERMINAL"

View file

@ -103,6 +103,7 @@
"persona_git_identity_commit_implemented": 100,
"interrupted_session_inspection_and_recovery_source_implemented": 100,
"typed_organ_contract_and_manifest_inspection_source_implemented": 100,
"durable_event_and_receipt_query_source_implemented": 100,
"general_purpose_persona_runtime_implemented": 0,
"human_live_projection_implemented": 0,
"hololake_integrated": 0,

View file

@ -77,12 +77,16 @@ test("the first source runtime cycle stays distinct from integration and deploym
channel.truth.typed_organ_contract_and_manifest_inspection_source_implemented,
100,
);
assert.equal(
channel.truth.durable_event_and_receipt_query_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_AND_TYPED_ORGAN_MANIFEST_INSPECTION_SOURCE_IMPLEMENTED_AND_TESTED",
"READ_ONLY_FACT_CYCLE_FAIL_CLOSED_RECOVERY_TYPED_ORGANS_AND_DURABLE_VERIFIED_SESSION_QUERY_SOURCE_IMPLEMENTED_AND_TESTED",
);
assert.equal(channel.truth.hololake_integrated, 0);
assert.equal(channel.truth.artifact_built, 0);