feat: discover verified persona repository bindings

This commit is contained in:
冰朔 2026-08-12 01:31:55 +08:00
commit b0970ed0d2
18 changed files with 417 additions and 15 deletions

View file

@ -526,6 +526,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::discover_persona_code_channel_repositories,
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,

View file

@ -187,11 +187,40 @@ pub struct PersonaManifestInspectionReceipt {
pub brain_entry: String,
pub current_checkpoint: String,
pub human_responsibility_subject: String,
pub cognitive_gravity: PersonaCognitiveGravityEvidence,
pub model_provider_id: String,
pub model_id: String,
pub model_base_url: String,
pub git_author_name: String,
pub git_author_email: String,
pub organ_contracts: Vec<PersonaOrganContract>,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaRepositoryDiscoveryInput {
pub expected_persona_id: String,
pub repository_paths: Vec<String>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaRepositoryDiscoveryFailure {
pub repository_path: String,
pub code: String,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaRepositoryDiscoveryReceipt {
pub schema: &'static str,
pub expected_persona_id: String,
pub inspected_repository_count: usize,
pub binding_count: usize,
pub bindings: Vec<PersonaManifestInspectionReceipt>,
pub failures: Vec<PersonaRepositoryDiscoveryFailure>,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaRuntimeQueryInput {
@ -906,7 +935,7 @@ fn inspect_manifest_at(
validate_git_identity(&manifest.git_identity)?;
validate_model_binding(&manifest.model_binding)?;
repository_file(&repository, &manifest.brain_entry)?;
cognitive_gravity_evidence(&repository, &manifest)?;
let cognitive_gravity = cognitive_gravity_evidence(&repository, &manifest)?;
repository_file(&repository, &manifest.current_checkpoint)?;
let mut contracts = Vec::with_capacity(manifest.organs.len());
for organ in &manifest.organs {
@ -927,12 +956,68 @@ fn inspect_manifest_at(
brain_entry: manifest.brain_entry,
current_checkpoint: manifest.current_checkpoint,
human_responsibility_subject: manifest.human_responsibility_subject,
cognitive_gravity,
model_provider_id: manifest.model_binding.provider_id,
model_id: manifest.model_binding.model_id,
model_base_url: manifest.model_binding.base_url,
git_author_name: manifest.git_identity.author_name,
git_author_email: manifest.git_identity.author_email,
organ_contracts: contracts,
})
}
fn discover_persona_repositories_at(
input: PersonaRepositoryDiscoveryInput,
) -> Result<PersonaRepositoryDiscoveryReceipt, String> {
let expected_persona_id = validated_id("EXPECTED_PERSONA_ID", &input.expected_persona_id)?;
if input.repository_paths.len() > 64 {
return Err("PERSONA_REPOSITORY_DISCOVERY_LIMIT_EXCEEDED".into());
}
let mut seen = Vec::<PathBuf>::new();
let mut bindings = Vec::new();
let mut failures = Vec::new();
for raw_path in input.repository_paths {
let trimmed = raw_path.trim();
if trimmed.is_empty() {
continue;
}
let display_path = trimmed.to_string();
let (repository, git_head) = match exact_repository(Path::new(trimmed)) {
Ok(value) => value,
Err(code) => {
failures.push(PersonaRepositoryDiscoveryFailure {
repository_path: display_path,
code,
});
continue;
}
};
if seen.iter().any(|candidate| candidate == &repository) {
continue;
}
seen.push(repository.clone());
match inspect_manifest_at(PersonaManifestInspectionInput {
repository_path: repository.to_string_lossy().into_owned(),
expected_persona_id: expected_persona_id.clone(),
expected_head: git_head,
}) {
Ok(receipt) => bindings.push(receipt),
Err(code) => failures.push(PersonaRepositoryDiscoveryFailure {
repository_path: repository.to_string_lossy().into_owned(),
code,
}),
}
}
Ok(PersonaRepositoryDiscoveryReceipt {
schema: "hololake.pncc-repository-discovery/v1",
expected_persona_id,
inspected_repository_count: seen.len(),
binding_count: bindings.len(),
bindings,
failures,
})
}
fn hex_digest(bytes: &[u8]) -> String {
digest(&SHA256, bytes)
.as_ref()
@ -3759,6 +3844,13 @@ pub fn inspect_persona_code_channel_manifest(
inspect_manifest_at(input)
}
#[tauri::command]
pub fn discover_persona_code_channel_repositories(
input: PersonaRepositoryDiscoveryInput,
) -> Result<PersonaRepositoryDiscoveryReceipt, String> {
discover_persona_repositories_at(input)
}
#[tauri::command]
pub fn query_persona_code_channel_runtime(
input: PersonaRuntimeQueryInput,
@ -6266,6 +6358,9 @@ mod tests {
let receipt = inspect_manifest_at(manifest_inspection(repo.path())).unwrap();
assert_eq!(receipt.persona_id, "ICE-P-ZY001");
assert!(receipt.repository_clean);
assert_eq!(receipt.model_provider_id, "fixture-provider");
assert_eq!(receipt.model_id, "fixture-model");
assert_eq!(receipt.cognitive_gravity.subject_persona_id, "ICE-P-ZY001");
assert_eq!(receipt.organ_contracts.len(), 1);
let contract = &receipt.organ_contracts[0];
assert_eq!(contract.kind, PersonaOrganKind::FactSense);
@ -6276,6 +6371,60 @@ mod tests {
assert_eq!(contract.implementation_state, "IMPLEMENTED");
}
#[test]
fn discovers_only_verified_persona_repository_bindings() {
let persona = persona_repo();
let ordinary = tempfile::TempDir::new().unwrap();
run_git(ordinary.path(), &["init", "-b", "main"]);
run_git(
ordinary.path(),
&["config", "user.name", "Ordinary Repository"],
);
run_git(
ordinary.path(),
&["config", "user.email", "ordinary@example.invalid"],
);
fs::write(ordinary.path().join("README.md"), "ordinary repository\n").unwrap();
run_git(ordinary.path(), &["add", "."]);
run_git(ordinary.path(), &["commit", "-m", "ordinary fixture"]);
let receipt = discover_persona_repositories_at(PersonaRepositoryDiscoveryInput {
expected_persona_id: "ICE-P-ZY001".into(),
repository_paths: vec![
ordinary.path().to_string_lossy().into_owned(),
persona.path().to_string_lossy().into_owned(),
persona.path().to_string_lossy().into_owned(),
],
})
.unwrap();
assert_eq!(receipt.schema, "hololake.pncc-repository-discovery/v1");
assert_eq!(receipt.inspected_repository_count, 2);
assert_eq!(receipt.binding_count, 1);
assert_eq!(receipt.bindings[0].persona_id, "ICE-P-ZY001");
assert_eq!(receipt.failures.len(), 1);
assert!(
receipt.failures[0]
.code
.starts_with("PERSONA_FILE_UNAVAILABLE: .hololake/persona/manifest.json:"),
"unexpected discovery failure: {}",
receipt.failures[0].code,
);
}
#[test]
fn empty_persona_repository_discovery_is_a_truthful_non_binding_receipt() {
let receipt = discover_persona_repositories_at(PersonaRepositoryDiscoveryInput {
expected_persona_id: "ICE-P-ZY001".into(),
repository_paths: Vec::new(),
})
.unwrap();
assert_eq!(receipt.inspected_repository_count, 0);
assert_eq!(receipt.binding_count, 0);
assert!(receipt.bindings.is_empty());
assert!(receipt.failures.is_empty());
}
#[test]
fn declares_but_refuses_an_execution_limb_without_an_executor() {
let repo = persona_repo();