{"record":{"id":"059b3a23350fbdf6","repo":"astrid-runtime/astrid","slug":"principal-migration-component-has-no-ordinary-home","errorCode":null,"errorMessage":"principal migration component has no ordinary-home receipt: {}","messagePattern":"principal migration component has no ordinary-home receipt: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/ledger.rs","lineNumber":405,"sourceCode":") -> io::Result<()> {\n    // The ledger is historical: mutable profile/package summaries and deleted\n    // principal UIDs are not required to be present on a later boot.\n    let mut principal_homes = std::collections::BTreeSet::new();\n    for component in &existing.components {\n        if let Some(uid) = principal_component_uid(&component.name)\n            && component.name.ends_with(\":home\")\n        {\n            principal_homes.insert(uid);\n        }\n    }\n    for component in &existing.components {\n        if mutable_component(&component.name) {\n            continue;\n        }\n        if let Some(uid) = principal_component_uid(&component.name)\n            && !principal_homes.contains(&uid)\n        {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"principal migration component has no ordinary-home receipt: {}\",\n                    component.name\n                ),\n            ));\n        }\n        if let Some(current) = proofs.get(&component.name) {\n            if current != &component.destination_proof {\n                return Err(io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    format!(\n                        \"destination receipt changed for migration component {}\",\n                        component.name\n                    ),\n                ));\n            }\n            continue;","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/ledger.rs#L387-L423","documentation":"`validate_existing_proofs` skips mutable components, then requires that any immutable component whose name encodes a principal UID has a corresponding ordinary-home receipt (i.e. its UID is present in principal_homes). If a principal component exists in the ledger but its UID has no ordinary-home receipt, validation fails. This ensures principals recorded in the migration ledger were also proven at the ordinary-home level.","triggerScenarios":"validate_existing_proofs (via resume_existing_layout or existing_layout_requires_receipts_for_live_immutable_components) encounters an immutable principal component whose parsed UID is absent from the set of validated principal_homes receipts.","commonSituations":"The ordinary-home receipt was deleted or never written while the principal component entry survived in the ledger; a partial restore restored the ledger but not the receipts; UID changed/removed (userdel) between migrations.","solutions":["Regenerate or restore the missing ordinary-home receipt for that UID (re-run migration so collect_destination_proofs recreates it).","If the UID is legitimately gone (deleted historical user), re-run resume_existing_layout so the ledger is revalidated under the current rules — deleted historical UIDs are handled by the live-projection check, not this one.","Do not hand-edit the ledger; bring ledger and receipts back into consistency by re-migrating."],"exampleFix":"// before: ledger has system:principal-1000 but no principal-home-1000.json\n$ rm ledger && astrid migrate  # regenerate receipts + ledger together","handlingStrategy":"validation","validationCode":"let uid = principal_component_uid(&component.name);\nlet ok = uid.map(|u| principal_homes.contains(&u)).unwrap_or(true);\nif !ok { eprintln!(\"{} has no ordinary-home receipt\", component.name); }","typeGuard":null,"tryCatchPattern":"match resume_existing_layout(...) {\n    Err(e) if e.to_string().contains(\"no ordinary-home receipt\") => {\n        eprintln!(\"regenerate receipts via a fresh migration run\");\n    }\n    r => r?,\n}","preventionTips":["Keep ordinary-home receipts alongside the ledger; back up both together.","Verify receipts exist for every principal UID in the ledger before resuming.","Avoid userdel/rename of UIDs between migration runs."],"tags":["security","ledger","validation","migration"],"backgroundTag":"missing-required-config-field","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}