ASELSANMicrokernel
S546 · SOURCE-BOUND GATE EVIDENCE

S546 · R1 üçüncü fiziksel boot/UART koşusu — RED

tam S546 implementation modülü → Operations --test hedefi ile bağlı tam focused test → ayrı Operations kaydı Bu sayfa yalnız S546 kapısına aittir; komşu kapıların kaynakları bu kabulün içine katılmaz.

S546 · FAIL nedeni

S546 immutable fiziksel RED'dir; koşu tekrarlanamaz ve geriye dönük yükseltilemez — hiçbir sınıflandırıcı sonucu veya state geçişi RED'i PASS yapamaz.

Kaynak ve focused test kanıtının PASS olması bu fiziksel FAIL sonucunu değiştirmez.

S546Focused kod testiOperations id exactsource SHA exacttest target exact

operation: g8l-s546-r1-reachable-producer-physical-boot-uart-run

uygulama/model · focused test · Operations · 3 exact excerpt

sequence-bound=true · implementation-bound=true
01 · Yürütme / doğrulama kodu

Kapının gerçek repository sözleşmesi

tam dosyaL1–L737
kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s546_r1_reachable_producer_physical_boot_uart_run.rs::S546 r1 reachable producer physical boot uart run implementation
//! S546 records the third physical RPi5 boot/UART run of the reachable-producer
//! candidate as an immutable physical **RED** with a new failure class: a
//! silent pre-BOOT8H hang (`Boot8hAbsentPrimaryFailSilent`).
//!
//! The exact S545 candidate booted the board through `ASELSAN/BOOT8G` and then
//! produced no further UART output: no `ASELSAN/BOOT8H`, no required
//! `[R1:S536] BOOT_TO_UI_READY`, no `S538ERR`/`S541ERR` line, no panic line and
//! no unknown-IRQ line.  The host closed the capture after sustained
//! quiescence (`capture_closed=true terminal_seen=false grace_complete=false
//! success=false`, host SIGTERM after more than 60 seconds without new
//! bytes).  The immutable raw is 16990 bytes, SHA-256
//! `a71a9107b4b6ea351eb65720a6b82486105fffdb931563d1c39e8a381c3e485d`,
//! mode 0444, link count 1, leading NUL 7, CR/LF 206/206.
//!
//! Narrowed deterministic source cause: the S544 boot hook requires the
//! S431-S535 acceptance ledger, whose S430 anchor is produced only inside the
//! CPU1 generic-timer PPI27 path (exceptions.rs:3173) below the G8h
//! early-return interceptor (exceptions.rs:1326) - a path that never runs
//! before G8h and is disabled after it.  The hook therefore fails with
//! `AcceptanceLedgerNotReady` (diagnostic 7), CPU1 publishes
//! `secondary_fail(ERR_PRIMARY_VALIDATION=43, 544, 7)`, CPU0's
//! `wait_for_cpu1_epoch` observes the published error and `primary_fail`
//! parks silently: no UART line is emitted on that path, which is why the raw
//! ends after `BOOT8G`.
//!
//! The module itself performs no SD write, no UART open, no power transition
//! and no device operation; the single authorized S546 physical transaction
//! was executed by the operator and the host tooling, and this module records
//! it as constants plus a pure classifier over the immutable raw bytes.  It
//! is not wired into any boot, IRQ, scheduler or driver path.  It does not
//! rerun S540 or S543 and cannot promote any RED observation; there is no
//! automatic S547 promotion.  Physical observations = 1,
//! `RUNBOOK_EXECUTED_IN_S546=YES` (the ten-step runbook was fully executed),
//! Boot-to-UI physically observed = false and R1 acceptance complete = false.
//!
//! Predecessor: S545 (host-only candidate freeze + pre-arm contract).
//! Remediation chain (a plan, not a commitment): S569 (source: decouple the
//! R1 marker chain from the unreachable ledger + add a bounded UART error
//! line to the G8h primary failure path), S570 (candidate freeze), S571
//! (separately authorized physical run).

pub const S546_SEQUENCE: usize = 546;
pub const S546_EXPECTED_PREDECESSOR: usize = 545;
pub const S546_R1_STAGE: u8 = 1;
pub const S546_R1_RANGE_FIRST: usize = 536;
pub const S546_R1_RANGE_LAST: usize = 568;
pub const S546_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS: usize = 1;
pub const S546_PHYSICAL_OBSERVATIONS: usize = 1;
pub const S546_PHYSICAL_OR_DEVICE_OPERATIONS: usize = 1;
pub const S546_SD_WRITE_TRANSACTIONS: usize = 1;
pub const S546_SD_WRITES: usize = 4;
pub const S546_UART_OPENS: usize = 1;
pub const S546_POWER_TRANSITIONS: usize = 2;
pub const S546_POWER_TRANSITIONS_OPERATOR_REPORTED: usize = 2;
pub const S546_POWER_TRANSITIONS_INDEPENDENTLY_OBSERVED: usize = 0;
pub const S546_NEW_IMMUTABLE_RAW_CAPTURES: usize = 1;
pub const S546_S540_PHYSICAL_VERDICT_RETAINED_RED: bool = true;
pub const S546_S543_PHYSICAL_VERDICT_RETAINED_RED: bool = true;
pub const S546_AUTOMATIC_PROMOTION: bool = false;
pub const S546_BOOT_TO_UI_PHYSICALLY_OBSERVED: bool = false;
pub const S546_HARDWARE_PRESENT: bool = true;
pub const S546_R1_ACCEPTANCE_COMPLETE: bool = false;
pub const RUNBOOK_EXECUTED_IN_S546: bool = true;

pub const S546_PHYSICAL_RUN_RECORDED: bool = true;
pub const S546_PHYSICAL_VERDICT_PENDING: bool = false;
pub const S546_PHYSICAL_GATE_RED: bool = true;
pub const S546_RED_CLASS: &str = "Boot8hAbsentPrimaryFailSilent";
pub const S546_RAW_BYTES: usize = 16990;
pub const S546_RAW_SHA256: &str =
    "a71a9107b4b6ea351eb65720a6b82486105fffdb931563d1c39e8a381c3e485d";
pub const S546_RAW_MODE_OCTAL: &str = "0444";
pub const S546_RAW_LINK_COUNT: usize = 1;
pub const S546_RAW_LEADING_NUL_BYTES: usize = 7;
pub const S546_RAW_TOTAL_NUL_BYTES: usize = 22;
pub const S546_RAW_CR_BYTES: usize = 206;
pub const S546_RAW_LF_BYTES: usize = 206;
pub const S546_CANDIDATE_IMAGE_BYTES: usize = 945760;
pub const S546_CANDIDATE_IMAGE_SHA256: &str =
    "ed1901a991e2f9e9ae3c16f254147a2b0180686a8d70ca5d7353374fee08d467";
pub const S546_REQUIRED_MARKER: &str = "[R1:S536] BOOT_TO_UI_READY";
pub const S546_ROUTE_MARKER: &str = "ASELSAN/S538 ROUTE=PRIOR_BOOT_TO_UI";
pub const S546_HANDOFF_MARKER: &str = "ASELSAN/S541 HANDOFF=CPU1_PREFLIGHT_ARMED";
pub const S546_BOOT_MARKER: &str = "ASELSAN/BOOT8H";
pub const S546_BOOT8G_MARKER: &str = "ASELSAN/BOOT8G";
pub const S546_S541_ERROR_MARKER: &str = "ASELSAN/S541ERR";
pub const S546_S538_ERROR_MARKER: &str = "ASELSAN/S538ERR";
pub const S546_AWAITING_PREFLIGHT_TOKEN: &str = "AwaitingPreflight";
pub const S546_CPU0_READINESS_TIMEOUT_TOKEN: &str = "Cpu0ReadinessTimeout";
pub const S546_PANIC_TOKENS: [&str; 2] = ["panic", "PANIC"];
pub const S546_UNKNOWN_IRQ_TOKENS: [&str; 2] = ["Bilinmeyen IRQ", "unknown IRQ"];
pub const S546_CANONICAL_CONTRACT_ANCHOR_ID: u64 = 0x5460_0000_0000_0001;
pub const S546_RUNBOOK_STEP_COUNT: usize = 10;
pub const S546_RUNBOOK_HOST_OBSERVED_STEPS: usize = 5;
pub const S546_RUNBOOK_OPERATOR_REPORTED_STEPS: usize = 5;
pub const S546_S540_RAW_BYTES: usize = 20525;
pub const S546_S543_RAW_BYTES: usize = 20509;

/// Who can attest a runbook step.  Operator-reported steps have no host
/// witness (power, card seating); host-observed steps leave a host-side log.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS546StepReporter {
    OperatorReported,
    HostObserved,
}

/// The ten ordered steps of the S546 physical runbook.  In the recorded S546
/// run every step was executed exactly once in this order.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum G8lS546RunbookStep {
    PowerOff,
    CardOutOfPi,
    CardIntoMac,
    AuthorizedWriteVerifyReadBack,
    SafeEject,
    CardIntoUnpoweredPi,
    UartPreArmExactIdentity,
    PowerOn,
    PowerOffAfterCapture,
    CardBackToMacReauth,
}

impl G8lS546RunbookStep {
    pub const ORDER: [G8lS546RunbookStep; S546_RUNBOOK_STEP_COUNT] = [
        Self::PowerOff,
        Self::CardOutOfPi,
        Self::CardIntoMac,
        Self::AuthorizedWriteVerifyReadBack,
        Self::SafeEject,
        Self::CardIntoUnpoweredPi,
        Self::UartPreArmExactIdentity,
        Self::PowerOn,
        Self::PowerOffAfterCapture,
        Self::CardBackToMacReauth,
    ];

    pub const fn index(self) -> usize {
        match self {
            Self::PowerOff => 0,
            Self::CardOutOfPi => 1,
            Self::CardIntoMac => 2,
            Self::AuthorizedWriteVerifyReadBack => 3,
            Self::SafeEject => 4,
            Self::CardIntoUnpoweredPi => 5,
            Self::UartPreArmExactIdentity => 6,
            Self::PowerOn => 7,
            Self::PowerOffAfterCapture => 8,
            Self::CardBackToMacReauth => 9,
        }
    }

    pub const fn from_index(index: usize) -> Option<Self> {
        if index < S546_RUNBOOK_STEP_COUNT {
            Some(Self::ORDER[index])
        } else {
            None
        }
    }

    pub const fn reporter(self) -> G8lS546StepReporter {
        match self {
            Self::PowerOff
            | Self::CardOutOfPi
            | Self::CardIntoUnpoweredPi
            | Self::PowerOn
            | Self::PowerOffAfterCapture => G8lS546StepReporter::OperatorReported,
            Self::CardIntoMac
            | Self::AuthorizedWriteVerifyReadBack
            | Self::SafeEject
            | Self::UartPreArmExactIdentity
            | Self::CardBackToMacReauth => G8lS546StepReporter::HostObserved,
        }
    }

    /// Attestations that must be present before the step may be accepted.
    pub const fn required_attestation(self) -> G8lS546StepAttestation {
        match self {
            Self::AuthorizedWriteVerifyReadBack => G8lS546StepAttestation {
                authority_token_exact: true,
                read_back_byte_exact: true,
                target_identity_exact: true,
            },
            Self::UartPreArmExactIdentity | Self::CardBackToMacReauth => G8lS546StepAttestation {
                authority_token_exact: false,
                read_back_byte_exact: false,
                target_identity_exact: true,
            },
            _ => G8lS546StepAttestation::NONE,
        }
    }

    pub const fn is_power_transition(self) -> bool {
        matches!(
            self,
            Self::PowerOff | Self::PowerOn | Self::PowerOffAfterCapture
        )
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct G8lS546StepAttestation {
    pub authority_token_exact: bool,
    pub read_back_byte_exact: bool,
    pub target_identity_exact: bool,
}

impl G8lS546StepAttestation {
    pub const NONE: Self = Self {
        authority_token_exact: false,
        read_back_byte_exact: false,
        target_identity_exact: false,
    };

    pub const fn satisfies(self, required: Self) -> bool {
        (!required.authority_token_exact || self.authority_token_exact)
            && (!required.read_back_byte_exact || self.read_back_byte_exact)
            && (!required.target_identity_exact || self.target_identity_exact)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS546RunbookStepReceipt {
    pub step: G8lS546RunbookStep,
    pub index: usize,
    pub reporter: G8lS546StepReporter,
    pub attestation: G8lS546StepAttestation,
}

/// Ordered, fail-closed runbook ledger.  Steps are accepted only in
/// `G8lS546RunbookStep::ORDER`; skipping, replaying, reporting with the wrong
/// witness class or omitting a required attestation is an error and leaves
/// the ledger unchanged.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct G8lS546RunbookLedger {
    accepted: [Option<G8lS546RunbookStepReceipt>; S546_RUNBOOK_STEP_COUNT],
    next_index: usize,
}

impl G8lS546RunbookLedger {
    pub const fn new() -> Self {
        Self {
            accepted: [None; S546_RUNBOOK_STEP_COUNT],
            next_index: 0,
        }
    }

    pub const fn next_step(&self) -> Option<G8lS546RunbookStep> {
        G8lS546RunbookStep::from_index(self.next_index)
    }

    pub const fn accepted_steps(&self) -> usize {
        self.next_index
    }

    pub const fn is_complete(&self) -> bool {
        self.next_index == S546_RUNBOOK_STEP_COUNT
    }

    pub fn receipt(&self, step: G8lS546RunbookStep) -> Option<G8lS546RunbookStepReceipt> {
        self.accepted[step.index()]
    }

    pub fn advance(
        &mut self,
        step: G8lS546RunbookStep,
        reporter: G8lS546StepReporter,
        attestation: G8lS546StepAttestation,
    ) -> Result<G8lS546RunbookStepReceipt, G8lS546Error> {
        let Some(expected) = self.next_step() else {
            return Err(G8lS546Error::RunbookAlreadyComplete);
        };
        if step.index() < self.next_index {
            return Err(G8lS546Error::RunbookStepReplay);
        }
        if step != expected {
            return Err(G8lS546Error::RunbookOutOfOrder);
        }
        if reporter != step.reporter() {
            return Err(G8lS546Error::RunbookReporterMismatch);
        }
        if !attestation.satisfies(step.required_attestation()) {
            return Err(G8lS546Error::RunbookAttestationMissing);
        }
        let receipt = G8lS546RunbookStepReceipt {
            step,
            index: step.index(),
            reporter,
            attestation,
        };
        self.accepted[step.index()] = Some(receipt);
        self.next_index = self
            .next_index
            .checked_add(1)
            .ok_or(G8lS546Error::RunbookOverflow)?;
        Ok(receipt)
    }
}

impl Default for G8lS546RunbookLedger {
    fn default() -> Self {
        Self::new()
    }
}

/// Exact non-overlapping substring counts over a raw capture.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct G8lS546MarkerCounts {
    pub boot8g: usize,
    pub boot8h: usize,
    pub required_marker: usize,
    pub route_marker: usize,
    pub handoff_marker: usize,
    pub s541_error: usize,
    pub s538_error: usize,
    pub awaiting_preflight_token: usize,
    pub cpu0_readiness_timeout_token: usize,
    pub panic: usize,
    pub unknown_irq: usize,
}

impl G8lS546MarkerCounts {
    pub const fn error_total(self) -> usize {
        self.s541_error + self.s538_error + self.panic + self.unknown_irq
    }

    pub const fn is_pass_matrix(self) -> bool {
        self.boot8h >= 1
            && self.required_marker == 1
            && self.route_marker == 1
            && self.handoff_marker == 1
            && self.error_total() == 0
    }
}

/// Physical verdict of one immutable raw.  There is deliberately no
/// constructor, conversion, `Default`, or method that yields `Pass` from
/// anything but `classify` over raw bytes.  The recorded S546 raw classifies
/// to `RedBoot8hAbsentPrimaryFailSilent`: BOOT8G reached, BOOT8H absent and
/// zero error/panic/unknown-IRQ markers (the silent `primary_fail` hang).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS546Verdict {
    Pass,
    RedAwaitingPreflight,
    RedCpu0ReadinessTimeout,
    RedBoot8hAbsentPrimaryFailSilent,
    RedMarkerAbsent,
    RedPanic,
    RedUnknownIrq,
    Inconclusive,
}

impl G8lS546Verdict {
    pub const fn is_pass(self) -> bool {
        matches!(self, Self::Pass)
    }

    pub const fn is_red(self) -> bool {
        matches!(
            self,
            Self::RedAwaitingPreflight
                | Self::RedCpu0ReadinessTimeout
                | Self::RedBoot8hAbsentPrimaryFailSilent
                | Self::RedMarkerAbsent
                | Self::RedPanic
                | Self::RedUnknownIrq
        )
    }

    pub const fn label(self) -> &'static str {
        match self {
            Self::Pass => "PASS",
            Self::RedAwaitingPreflight => "RED_AWAITING_PREFLIGHT",
            Self::RedCpu0ReadinessTimeout => "RED_CPU0_READINESS_TIMEOUT",
            Self::RedBoot8hAbsentPrimaryFailSilent => "RED_BOOT8H_ABSENT_PRIMARY_FAIL_SILENT",
            Self::RedMarkerAbsent => "RED_MARKER_ABSENT",
            Self::RedPanic => "RED_PANIC",
            Self::RedUnknownIrq => "RED_UNKNOWN_IRQ",
            Self::Inconclusive => "INCONCLUSIVE",
        }
    }
}

pub fn count_substring(haystack: &[u8], needle: &[u8]) -> usize {
    if needle.is_empty() || haystack.len() < needle.len() {
        return 0;
    }
    let mut count = 0usize;
    let mut index = 0usize;
    while index + needle.len() <= haystack.len() {
        if &haystack[index..index + needle.len()] == needle {
            count += 1;
            index += needle.len();
        } else {
            index += 1;
        }
    }
    count
}

pub fn count_markers(raw: &[u8]) -> G8lS546MarkerCounts {
    G8lS546MarkerCounts {
        boot8g: count_substring(raw, S546_BOOT8G_MARKER.as_bytes()),
        boot8h: count_substring(raw, S546_BOOT_MARKER.as_bytes()),
        required_marker: count_substring(raw, S546_REQUIRED_MARKER.as_bytes()),
        route_marker: count_substring(raw, S546_ROUTE_MARKER.as_bytes()),
        handoff_marker: count_substring(raw, S546_HANDOFF_MARKER.as_bytes()),
        s541_error: count_substring(raw, S546_S541_ERROR_MARKER.as_bytes()),
        s538_error: count_substring(raw, S546_S538_ERROR_MARKER.as_bytes()),
        awaiting_preflight_token: count_substring(raw, S546_AWAITING_PREFLIGHT_TOKEN.as_bytes()),
        cpu0_readiness_timeout_token: count_substring(
            raw,
            S546_CPU0_READINESS_TIMEOUT_TOKEN.as_bytes(),
        ),
        panic: count_substring(raw, S546_PANIC_TOKENS[0].as_bytes())
            + count_substring(raw, S546_PANIC_TOKENS[1].as_bytes()),
        unknown_irq: count_substring(raw, S546_UNKNOWN_IRQ_TOKENS[0].as_bytes())
            + count_substring(raw, S546_UNKNOWN_IRQ_TOKENS[1].as_bytes()),
    }
}

pub const fn classify_counts(counts: G8lS546MarkerCounts) -> G8lS546Verdict {
    if counts.boot8h == 0 {
        // The recorded S546 failure class: boot reached BOOT8G, then hung
        // silently before BOOT8H with zero error/panic/unknown-IRQ markers
        // (the UART-invisible `primary_fail` path).  A BOOT8H-less raw with
        // any error token or without BOOT8G stays `Inconclusive`.
        if counts.boot8g >= 1 && counts.error_total() == 0 {
            return G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent;
        }
        return G8lS546Verdict::Inconclusive;
    }
    if counts.panic > 0 {
        return G8lS546Verdict::RedPanic;
    }
    if counts.unknown_irq > 0 {
        return G8lS546Verdict::RedUnknownIrq;
    }
    if counts.s538_error > 0 && counts.awaiting_preflight_token > 0 {
        return G8lS546Verdict::RedAwaitingPreflight;
    }
    if counts.s541_error > 0 && counts.cpu0_readiness_timeout_token > 0 {
        return G8lS546Verdict::RedCpu0ReadinessTimeout;
    }
    if counts.is_pass_matrix() {
        return G8lS546Verdict::Pass;
    }
    G8lS546Verdict::RedMarkerAbsent
}

/// The only path to a verdict: exact substring counting over raw bytes.
pub fn classify(raw: &[u8]) -> G8lS546Verdict {
    classify_counts(count_markers(raw))
}

const fn hex_nibble(byte: u8) -> Option<u8> {
    match byte {
        b'0'..=b'9' => Some(byte - b'0'),
        b'a'..=b'f' => Some(byte - b'a' + 10),
        _ => None,
    }
}

/// Decodes a lowercase 64-character SHA-256 hex digest; anything else fails.
pub fn decode_sha256_hex(text: &str) -> Option<[u8; 32]> {
    let bytes = text.as_bytes();
    if bytes.len() != 64 {
        return None;
    }
    let mut digest = [0u8; 32];
    let mut index = 0usize;
    while index < 32 {
        let high = hex_nibble(bytes[index * 2])?;
        let low = hex_nibble(bytes[index * 2 + 1])?;
        digest[index] = (high << 4) | low;
        index += 1;
    }
    Some(digest)
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS546EvidenceContractRequest<'a> {
    pub contract_anchor_id: u64,
    pub predecessor_sequence: usize,
    pub candidate_image_bytes: usize,
    pub candidate_image_sha256: &'a str,
    pub runbook_step_count: usize,
    pub physical_run_recorded: bool,
    pub recorded_raw_bytes: usize,
    pub recorded_raw_sha256: &'a str,
    pub claimed_verdict: Option<G8lS546Verdict>,
}

impl G8lS546EvidenceContractRequest<'static> {
    pub const CANONICAL: Self = Self {
        contract_anchor_id: S546_CANONICAL_CONTRACT_ANCHOR_ID,
        predecessor_sequence: S546_EXPECTED_PREDECESSOR,
        candidate_image_bytes: S546_CANDIDATE_IMAGE_BYTES,
        candidate_image_sha256: S546_CANDIDATE_IMAGE_SHA256,
        runbook_step_count: S546_RUNBOOK_STEP_COUNT,
        physical_run_recorded: S546_PHYSICAL_RUN_RECORDED,
        recorded_raw_bytes: S546_RAW_BYTES,
        recorded_raw_sha256: S546_RAW_SHA256,
        claimed_verdict: Some(G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent),
    };
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS546EvidenceContractReceipt {
    pub contract_anchor_id: u64,
    pub sequence: usize,
    pub predecessor_sequence: usize,
    pub r1_stage: u8,
    pub candidate_image_bytes: usize,
    pub candidate_image_sha256: [u8; 32],
    pub boot_marker_minimum: usize,
    pub required_marker_exact: usize,
    pub route_marker_exact: usize,
    pub handoff_marker_exact: usize,
    pub error_marker_maximum: usize,
    pub runbook_step_count: usize,
    pub runbook_host_observed_steps: usize,
    pub runbook_operator_reported_steps: usize,
    pub runbook_power_transition_steps: usize,
    pub physical_run_recorded: bool,
    pub physical_verdict_pending: bool,
    pub physical_verdict: Option<G8lS546Verdict>,
    pub physical_gate_red: bool,
    pub physical_red_class: &'static str,
    pub recorded_raw_bytes: usize,
    pub recorded_raw_sha256: [u8; 32],
    pub sd_write_transactions: usize,
    pub uart_opens: usize,
    pub power_transitions_reported: usize,
    pub power_transitions_independently_observed: usize,
    pub new_immutable_raw_captures: usize,
    pub s540_physical_verdict_retained_red: bool,
    pub s543_physical_verdict_retained_red: bool,
    pub automatic_promotion: bool,
    pub supported_profile_runtime_observations: usize,
    pub physical_observations: usize,
    pub boot_to_ui_physically_observed: bool,
    pub r1_acceptance_complete: bool,
    pub runbook_executed: bool,
}

#[derive(Debug, Default)]
pub struct G8lS546EvidenceContractState {
    receipt: Option<G8lS546EvidenceContractReceipt>,
}

impl G8lS546EvidenceContractState {
    pub const fn new() -> Self {
        Self { receipt: None }
    }

    pub const fn receipt(&self) -> Option<G8lS546EvidenceContractReceipt> {
        self.receipt
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS546Outcome {
    ContractPublished(G8lS546EvidenceContractReceipt),
    ContractRetained(G8lS546EvidenceContractReceipt),
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS546Error {
    ContractAnchorZero,
    WrongPredecessor,
    CandidateImageBytesMismatch,
    CandidateImageSha256Malformed,
    CandidateImageSha256Mismatch,
    RunbookStepCountMismatch,
    PhysicalRunRecordMismatch,
    RecordedVerdictMismatch,
    RecordedRawBytesMismatch,
    RecordedRawSha256Malformed,
    RecordedRawSha256Mismatch,
    RunbookOutOfOrder,
    RunbookStepReplay,
    RunbookReporterMismatch,
    RunbookAttestationMissing,
    RunbookAlreadyComplete,
    RunbookOverflow,
    PublishedStateDrift,
}

impl G8lS546Error {
    pub const fn diagnostic_code(self) -> u64 {
        match self {
            Self::ContractAnchorZero => 0x5460,
            Self::WrongPredecessor => 0x5461,
            Self::CandidateImageBytesMismatch => 0x5462,
            Self::CandidateImageSha256Malformed => 0x5463,
            Self::CandidateImageSha256Mismatch => 0x5464,
            Self::RunbookStepCountMismatch => 0x5465,
            Self::PhysicalRunRecordMismatch => 0x5466,
            Self::RecordedVerdictMismatch => 0x5467,
            Self::RecordedRawBytesMismatch => 0x546f,
            Self::RecordedRawSha256Malformed => 0x5470,
            Self::RecordedRawSha256Mismatch => 0x5471,
            Self::RunbookOutOfOrder => 0x5468,
            Self::RunbookStepReplay => 0x5469,
            Self::RunbookReporterMismatch => 0x546a,
            Self::RunbookAttestationMissing => 0x546b,
            Self::RunbookAlreadyComplete => 0x546c,
            Self::RunbookOverflow => 0x546d,
            Self::PublishedStateDrift => 0x546e,
        }
    }
}

const fn count_reporter(reporter: G8lS546StepReporter) -> usize {
    let mut count = 0usize;
    let mut index = 0usize;
    while index < S546_RUNBOOK_STEP_COUNT {
        if matches!(
            (G8lS546RunbookStep::ORDER[index].reporter(), reporter),
            (
                G8lS546StepReporter::HostObserved,
                G8lS546StepReporter::HostObserved
            ) | (
                G8lS546StepReporter::OperatorReported,
                G8lS546StepReporter::OperatorReported
            )
        ) {
            count += 1;
        }
        index += 1;
    }
    count
}

const fn count_power_transition_steps() -> usize {
    let mut count = 0usize;
    let mut index = 0usize;
    while index < S546_RUNBOOK_STEP_COUNT {
        if G8lS546RunbookStep::ORDER[index].is_power_transition() {
            count += 1;
        }
        index += 1;
    }
    count
}

/// Publishes the recorded S546 evidence receipt.  Every field is bound to the
/// exact S545 candidate identity, to the marker matrix and to the immutable
/// S546 raw identity; any drift from the recorded raw bytes, digest or RED
/// verdict is rejected fail-closed.  A `Pass` claim can never be accepted:
/// the only recorded verdict is `RedBoot8hAbsentPrimaryFailSilent`.
pub fn service_s546_model_evidence_contract(
    state: &mut G8lS546EvidenceContractState,
    request: G8lS546EvidenceContractRequest<'_>,
) -> Result<G8lS546Outcome, G8lS546Error> {
    if request.contract_anchor_id == 0 {
        return Err(G8lS546Error::ContractAnchorZero);
    }
    if request.predecessor_sequence != S546_EXPECTED_PREDECESSOR {
        return Err(G8lS546Error::WrongPredecessor);
    }
    if request.candidate_image_bytes != S546_CANDIDATE_IMAGE_BYTES {
        return Err(G8lS546Error::CandidateImageBytesMismatch);
    }
    let digest = decode_sha256_hex(request.candidate_image_sha256)
        .ok_or(G8lS546Error::CandidateImageSha256Malformed)?;
    let expected = decode_sha256_hex(S546_CANDIDATE_IMAGE_SHA256)
        .ok_or(G8lS546Error::CandidateImageSha256Malformed)?;
    if digest != expected {
        return Err(G8lS546Error::CandidateImageSha256Mismatch);
    }
    if request.runbook_step_count != S546_RUNBOOK_STEP_COUNT {
        return Err(G8lS546Error::RunbookStepCountMismatch);
    }
    if request.physical_run_recorded != S546_PHYSICAL_RUN_RECORDED {
        return Err(G8lS546Error::PhysicalRunRecordMismatch);
    }
    if request.recorded_raw_bytes != S546_RAW_BYTES {
        return Err(G8lS546Error::RecordedRawBytesMismatch);
    }
    let raw_digest = decode_sha256_hex(request.recorded_raw_sha256)
        .ok_or(G8lS546Error::RecordedRawSha256Malformed)?;
    let expected_raw_digest =
        decode_sha256_hex(S546_RAW_SHA256).ok_or(G8lS546Error::RecordedRawSha256Malformed)?;
    if raw_digest != expected_raw_digest {
        return Err(G8lS546Error::RecordedRawSha256Mismatch);
    }
    if request.claimed_verdict != Some(G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent) {
        return Err(G8lS546Error::RecordedVerdictMismatch);
    }
    let receipt = G8lS546EvidenceContractReceipt {
        contract_anchor_id: request.contract_anchor_id,
        sequence: S546_SEQUENCE,
        predecessor_sequence: S546_EXPECTED_PREDECESSOR,
        r1_stage: S546_R1_STAGE,
        candidate_image_bytes: S546_CANDIDATE_IMAGE_BYTES,
        candidate_image_sha256: digest,
        boot_marker_minimum: 1,
        required_marker_exact: 1,
        route_marker_exact: 1,
        handoff_marker_exact: 1,
        error_marker_maximum: 0,
        runbook_step_count: S546_RUNBOOK_STEP_COUNT,
        runbook_host_observed_steps: count_reporter(G8lS546StepReporter::HostObserved),
        runbook_operator_reported_steps: count_reporter(G8lS546StepReporter::OperatorReported),
        runbook_power_transition_steps: count_power_transition_steps(),
        physical_run_recorded: S546_PHYSICAL_RUN_RECORDED,
        physical_verdict_pending: S546_PHYSICAL_VERDICT_PENDING,
        physical_verdict: Some(G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent),
        physical_gate_red: S546_PHYSICAL_GATE_RED,
        physical_red_class: S546_RED_CLASS,
        recorded_raw_bytes: S546_RAW_BYTES,
        recorded_raw_sha256: raw_digest,
        sd_write_transactions: S546_SD_WRITE_TRANSACTIONS,
        uart_opens: S546_UART_OPENS,
        power_transitions_reported: S546_POWER_TRANSITIONS_OPERATOR_REPORTED,
        power_transitions_independently_observed: S546_POWER_TRANSITIONS_INDEPENDENTLY_OBSERVED,
        new_immutable_raw_captures: S546_NEW_IMMUTABLE_RAW_CAPTURES,
        s540_physical_verdict_retained_red: S546_S540_PHYSICAL_VERDICT_RETAINED_RED,
        s543_physical_verdict_retained_red: S546_S543_PHYSICAL_VERDICT_RETAINED_RED,
        automatic_promotion: S546_AUTOMATIC_PROMOTION,
        supported_profile_runtime_observations: S546_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS,
        physical_observations: S546_PHYSICAL_OBSERVATIONS,
        boot_to_ui_physically_observed: S546_BOOT_TO_UI_PHYSICALLY_OBSERVED,
        r1_acceptance_complete: S546_R1_ACCEPTANCE_COMPLETE,
        runbook_executed: RUNBOOK_EXECUTED_IN_S546,
    };
    if let Some(published) = state.receipt {
        if published != receipt {
            return Err(G8lS546Error::PublishedStateDrift);
        }
        return Ok(G8lS546Outcome::ContractRetained(published));
    }
    state.receipt = Some(receipt);
    Ok(G8lS546Outcome::ContractPublished(receipt))
}
snippet sha256: 4e45fbd2d02afile sha256: 4e45fbd2d02a
02 · Doğrulayan test kodu

Operations komutuna bağlı focused test

tam dosyaL1–L892
simulation/tests/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s546_r1_reachable_producer_physical_boot_uart_run.rs::S546 r1 reachable producer physical boot uart run focused tests
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s546_r1_reachable_producer_physical_boot_uart_run::*;
use sha2::{Digest, Sha256};
use std::collections::BTreeSet;

const SOURCE: &str = include_str!(
    "../../kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s546_r1_reachable_producer_physical_boot_uart_run.rs"
);
const MAIN: &str = include_str!("../../kernel/src/main.rs");
const SIMULATION_LIB: &str = include_str!("../src/lib.rs");
const S540_RAW: &[u8] =
    include_bytes!("../../evidence/rpi5/r1/sequence-540-physical-boot-uart/s540-uart.raw");
const S543_RAW: &[u8] =
    include_bytes!("../../evidence/rpi5/r1/sequence-543-remediated-physical-retry/s543-uart.raw");
const S546_RAW: &[u8] =
    include_bytes!("../../evidence/rpi5/r1/sequence-546-physical-boot-uart/s546-uart.raw");
const S546_FLASH_LOG: &[u8] =
    include_bytes!("../../evidence/rpi5/r1/sequence-546-physical-boot-uart/s546-flash.log");
const S546_CAPTURE_LOG: &[u8] =
    include_bytes!("../../evidence/rpi5/r1/sequence-546-physical-boot-uart/s546-capture.log");
const S546_EVIDENCE_SHA256SUMS: &str =
    include_str!("../../evidence/rpi5/r1/sequence-546-physical-boot-uart/EVIDENCE_SHA256SUMS");

const MODULE: &str = "g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s546_r1_reachable_producer_physical_boot_uart_run";

fn synthetic_pass_raw() -> Vec<u8> {
    let mut raw = Vec::new();
    raw.extend_from_slice(b"\0\0\0RPi: BCM2712 bootloader\r\n");
    raw.extend_from_slice(b"ASELSAN/BOOT0 BCM2712\r\n");
    raw.extend_from_slice(b"ASELSAN/BOOT8H REPORTER=CPU0 PREEMPT=OK TARGET=CPU1\r\n");
    raw.extend_from_slice(S546_HANDOFF_MARKER.as_bytes());
    raw.extend_from_slice(b" PRODUCER=CPU1 CONSUMER=CPU0 REQUEST_ID=1\r\n");
    raw.extend_from_slice(S546_ROUTE_MARKER.as_bytes());
    raw.extend_from_slice(b" CPU=0 BOARD=BCM2712 UART=UART10\r\n");
    raw.extend_from_slice(S546_REQUIRED_MARKER.as_bytes());
    raw.extend_from_slice(b"\r\n");
    raw
}

fn full_attestation() -> G8lS546StepAttestation {
    G8lS546StepAttestation {
        authority_token_exact: true,
        read_back_byte_exact: true,
        target_identity_exact: true,
    }
}

fn request(anchor: u64) -> G8lS546EvidenceContractRequest<'static> {
    G8lS546EvidenceContractRequest {
        contract_anchor_id: anchor,
        ..G8lS546EvidenceContractRequest::CANONICAL
    }
}

#[test]
fn sequence_scope_and_nonpromotion_are_exact() {
    assert_eq!(S546_SEQUENCE, 546);
    assert_eq!(S546_EXPECTED_PREDECESSOR, 545);
    assert_eq!(S546_R1_STAGE, 1);
    assert_eq!(S546_R1_RANGE_FIRST, 536);
    assert_eq!(S546_R1_RANGE_LAST, 568);
    assert_eq!(S546_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS, 1);
    assert_eq!(S546_PHYSICAL_OBSERVATIONS, 1);
    assert_eq!(S546_PHYSICAL_OR_DEVICE_OPERATIONS, 1);
    assert_eq!(S546_SD_WRITE_TRANSACTIONS, 1);
    assert_eq!(S546_SD_WRITES, 4);
    assert_eq!(S546_UART_OPENS, 1);
    assert_eq!(S546_POWER_TRANSITIONS, 2);
    assert_eq!(S546_POWER_TRANSITIONS_OPERATOR_REPORTED, 2);
    assert_eq!(S546_POWER_TRANSITIONS_INDEPENDENTLY_OBSERVED, 0);
    assert_eq!(S546_NEW_IMMUTABLE_RAW_CAPTURES, 1);
    assert!(S546_S540_PHYSICAL_VERDICT_RETAINED_RED);
    assert!(S546_S543_PHYSICAL_VERDICT_RETAINED_RED);
    assert!(!S546_AUTOMATIC_PROMOTION);
    assert!(!S546_BOOT_TO_UI_PHYSICALLY_OBSERVED);
    assert!(S546_HARDWARE_PRESENT);
    assert!(!S546_R1_ACCEPTANCE_COMPLETE);
    assert!(RUNBOOK_EXECUTED_IN_S546);
    assert!(S546_PHYSICAL_RUN_RECORDED);
    assert!(!S546_PHYSICAL_VERDICT_PENDING);
    assert!(S546_PHYSICAL_GATE_RED);
    assert_eq!(S546_RED_CLASS, "Boot8hAbsentPrimaryFailSilent");
    assert_eq!(S546_RAW_BYTES, 16990);
    assert_eq!(
        S546_RAW_SHA256,
        "a71a9107b4b6ea351eb65720a6b82486105fffdb931563d1c39e8a381c3e485d"
    );
    assert_eq!(S546_RAW_MODE_OCTAL, "0444");
    assert_eq!(S546_RAW_LINK_COUNT, 1);
    assert_eq!(S546_RAW_LEADING_NUL_BYTES, 7);
    assert_eq!(S546_RAW_TOTAL_NUL_BYTES, 22);
    assert_eq!(S546_RAW_CR_BYTES, 206);
    assert_eq!(S546_RAW_LF_BYTES, 206);
    assert_eq!(S546_CANDIDATE_IMAGE_BYTES, 945760);
    assert_eq!(
        S546_CANDIDATE_IMAGE_SHA256,
        "ed1901a991e2f9e9ae3c16f254147a2b0180686a8d70ca5d7353374fee08d467"
    );
    assert_eq!(S546_REQUIRED_MARKER, "[R1:S536] BOOT_TO_UI_READY");
    assert_eq!(S546_ROUTE_MARKER, "ASELSAN/S538 ROUTE=PRIOR_BOOT_TO_UI");
    assert_eq!(
        S546_HANDOFF_MARKER,
        "ASELSAN/S541 HANDOFF=CPU1_PREFLIGHT_ARMED"
    );
    assert_eq!(S546_BOOT_MARKER, "ASELSAN/BOOT8H");
    assert_eq!(S546_BOOT8G_MARKER, "ASELSAN/BOOT8G");
    assert_eq!(S546_S541_ERROR_MARKER, "ASELSAN/S541ERR");
    assert_eq!(S546_S538_ERROR_MARKER, "ASELSAN/S538ERR");
    assert_eq!(S546_RUNBOOK_STEP_COUNT, 10);
    assert_eq!(S546_RUNBOOK_HOST_OBSERVED_STEPS, 5);
    assert_eq!(S546_RUNBOOK_OPERATOR_REPORTED_STEPS, 5);
}

#[test]
fn module_is_registered_in_kernel_and_simulation() {
    assert!(MAIN.contains(&format!("mod {MODULE};")));
    assert!(SIMULATION_LIB.contains(&format!("pub mod {MODULE};")));
}

#[test]
fn source_has_no_device_execution_or_uart_emission_surface() {
    for forbidden in [
        "unsafe",
        "asm!",
        "write_volatile",
        "crate::uart",
        "crate::arch",
        "#[no_mangle]",
        "spin::",
        "std::",
        "/dev/disk",
        "/dev/cu.",
        "diskutil",
        "dd if=",
        "TIOCEXCL",
        "kprintln!",
    ] {
        assert!(!SOURCE.contains(forbidden), "forbidden token: {forbidden}");
    }
    assert!(SOURCE.contains("performs no SD write, no UART open, no power transition"));
    assert!(SOURCE.contains("rerun S540 or S543"));
}

#[test]
fn diagnostic_codes_are_nonzero_and_unique() {
    let errors = [
        G8lS546Error::ContractAnchorZero,
        G8lS546Error::WrongPredecessor,
        G8lS546Error::CandidateImageBytesMismatch,
        G8lS546Error::CandidateImageSha256Malformed,
        G8lS546Error::CandidateImageSha256Mismatch,
        G8lS546Error::RunbookStepCountMismatch,
        G8lS546Error::PhysicalRunRecordMismatch,
        G8lS546Error::RecordedVerdictMismatch,
        G8lS546Error::RecordedRawBytesMismatch,
        G8lS546Error::RecordedRawSha256Malformed,
        G8lS546Error::RecordedRawSha256Mismatch,
        G8lS546Error::RunbookOutOfOrder,
        G8lS546Error::RunbookStepReplay,
        G8lS546Error::RunbookReporterMismatch,
        G8lS546Error::RunbookAttestationMissing,
        G8lS546Error::RunbookAlreadyComplete,
        G8lS546Error::RunbookOverflow,
        G8lS546Error::PublishedStateDrift,
    ];
    let codes: BTreeSet<_> = errors
        .into_iter()
        .map(G8lS546Error::diagnostic_code)
        .collect();
    assert_eq!(codes.len(), errors.len());
    assert!(!codes.contains(&0));
}

#[test]
fn canonical_request_publishes_recorded_red_contract_receipt() {
    let mut state = G8lS546EvidenceContractState::new();
    let G8lS546Outcome::ContractPublished(receipt) =
        service_s546_model_evidence_contract(&mut state, request(0x5461)).unwrap()
    else {
        panic!("first S546 publication missing")
    };
    assert_eq!(state.receipt(), Some(receipt));
    assert_eq!(receipt.contract_anchor_id, 0x5461);
    assert_eq!(receipt.sequence, 546);
    assert_eq!(receipt.predecessor_sequence, 545);
    assert_eq!(receipt.r1_stage, 1);
    assert_eq!(receipt.candidate_image_bytes, 945760);
    assert_eq!(
        receipt.candidate_image_sha256,
        decode_sha256_hex(S546_CANDIDATE_IMAGE_SHA256).unwrap()
    );
    assert_eq!(receipt.candidate_image_sha256[0], 0xed);
    assert_eq!(receipt.candidate_image_sha256[31], 0x67);
    assert_eq!(receipt.boot_marker_minimum, 1);
    assert_eq!(receipt.required_marker_exact, 1);
    assert_eq!(receipt.route_marker_exact, 1);
    assert_eq!(receipt.handoff_marker_exact, 1);
    assert_eq!(receipt.error_marker_maximum, 0);
    assert_eq!(receipt.runbook_step_count, 10);
    assert_eq!(receipt.runbook_host_observed_steps, 5);
    assert_eq!(receipt.runbook_operator_reported_steps, 5);
    assert_eq!(receipt.runbook_power_transition_steps, 3);
    assert!(receipt.physical_run_recorded);
    assert!(!receipt.physical_verdict_pending);
    assert_eq!(
        receipt.physical_verdict,
        Some(G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent)
    );
    assert!(receipt.physical_gate_red);
    assert_eq!(receipt.physical_red_class, "Boot8hAbsentPrimaryFailSilent");
    assert_eq!(receipt.recorded_raw_bytes, 16990);
    assert_eq!(
        receipt.recorded_raw_sha256,
        decode_sha256_hex(S546_RAW_SHA256).unwrap()
    );
    assert_eq!(receipt.recorded_raw_sha256[0], 0xa7);
    assert_eq!(receipt.recorded_raw_sha256[31], 0x5d);
    assert_eq!(receipt.sd_write_transactions, 1);
    assert_eq!(receipt.uart_opens, 1);
    assert_eq!(receipt.power_transitions_reported, 2);
    assert_eq!(receipt.power_transitions_independently_observed, 0);
    assert_eq!(receipt.new_immutable_raw_captures, 1);
    assert!(receipt.s540_physical_verdict_retained_red);
    assert!(receipt.s543_physical_verdict_retained_red);
    assert!(!receipt.automatic_promotion);
    assert_eq!(receipt.supported_profile_runtime_observations, 1);
    assert_eq!(receipt.physical_observations, 1);
    assert!(!receipt.boot_to_ui_physically_observed);
    assert!(!receipt.r1_acceptance_complete);
    assert!(receipt.runbook_executed);
}

#[test]
fn exact_replay_retains_the_same_receipt() {
    let mut state = G8lS546EvidenceContractState::new();
    let G8lS546Outcome::ContractPublished(receipt) =
        service_s546_model_evidence_contract(&mut state, request(0x5462)).unwrap()
    else {
        panic!("first publication missing")
    };
    assert_eq!(
        service_s546_model_evidence_contract(&mut state, request(0x5462)),
        Ok(G8lS546Outcome::ContractRetained(receipt))
    );
    assert_eq!(state.receipt(), Some(receipt));
}

#[test]
fn divergent_input_after_publication_fails_closed() {
    let mut state = G8lS546EvidenceContractState::new();
    let published = service_s546_model_evidence_contract(&mut state, request(0x5463)).unwrap();
    assert_eq!(
        service_s546_model_evidence_contract(&mut state, request(0x5464)),
        Err(G8lS546Error::PublishedStateDrift)
    );
    let G8lS546Outcome::ContractPublished(receipt) = published else {
        panic!("publication missing")
    };
    assert_eq!(state.receipt(), Some(receipt));
}

#[test]
fn contract_request_rejects_every_identity_or_claim_drift() {
    let cases: [(G8lS546EvidenceContractRequest<'static>, G8lS546Error); 12] = [
        (
            G8lS546EvidenceContractRequest {
                contract_anchor_id: 0,
                ..request(1)
            },
            G8lS546Error::ContractAnchorZero,
        ),
        (
            G8lS546EvidenceContractRequest {
                predecessor_sequence: 544,
                ..request(1)
            },
            G8lS546Error::WrongPredecessor,
        ),
        (
            G8lS546EvidenceContractRequest {
                candidate_image_bytes: 941392,
                ..request(1)
            },
            G8lS546Error::CandidateImageBytesMismatch,
        ),
        (
            G8lS546EvidenceContractRequest {
                candidate_image_sha256:
                    "ED1901A991E2F9E9AE3C16F254147A2B0180686A8D70CA5D7353374FEE08D467",
                ..request(1)
            },
            G8lS546Error::CandidateImageSha256Malformed,
        ),
        (
            G8lS546EvidenceContractRequest {
                candidate_image_sha256:
                    "aa0c459b987c3f4c143b4eb14ce0ed655c2812e2a36516793e7bd8b27b60d87c",
                ..request(1)
            },
            G8lS546Error::CandidateImageSha256Mismatch,
        ),
        (
            G8lS546EvidenceContractRequest {
                runbook_step_count: 9,
                ..request(1)
            },
            G8lS546Error::RunbookStepCountMismatch,
        ),
        (
            G8lS546EvidenceContractRequest {
                physical_run_recorded: false,
                ..request(1)
            },
            G8lS546Error::PhysicalRunRecordMismatch,
        ),
        (
            G8lS546EvidenceContractRequest {
                recorded_raw_bytes: 20509,
                ..request(1)
            },
            G8lS546Error::RecordedRawBytesMismatch,
        ),
        (
            G8lS546EvidenceContractRequest {
                recorded_raw_sha256:
                    "A71A9107B4B6EA351EB65720A6B82486105FFFDB931563D1C39E8A381C3E485D",
                ..request(1)
            },
            G8lS546Error::RecordedRawSha256Malformed,
        ),
        (
            G8lS546EvidenceContractRequest {
                recorded_raw_sha256:
                    "1f1111a1a39ab6263b505b0889d025df19d5c48bb2f84e30708412b0da47dc11",
                ..request(1)
            },
            G8lS546Error::RecordedRawSha256Mismatch,
        ),
        (
            G8lS546EvidenceContractRequest {
                claimed_verdict: None,
                ..request(1)
            },
            G8lS546Error::RecordedVerdictMismatch,
        ),
        (
            G8lS546EvidenceContractRequest {
                claimed_verdict: Some(G8lS546Verdict::Pass),
                ..request(1)
            },
            G8lS546Error::RecordedVerdictMismatch,
        ),
    ];
    for (bad, expected) in cases {
        let mut state = G8lS546EvidenceContractState::new();
        assert_eq!(
            service_s546_model_evidence_contract(&mut state, bad),
            Err(expected)
        );
        assert_eq!(state.receipt(), None);
    }
}

#[test]
fn sha256_hex_decoder_is_exact_and_fail_closed() {
    let digest = decode_sha256_hex(S546_CANDIDATE_IMAGE_SHA256).unwrap();
    assert_eq!(digest[0], 0xed);
    assert_eq!(digest[1], 0x19);
    assert_eq!(digest[31], 0x67);
    let raw_digest = decode_sha256_hex(S546_RAW_SHA256).unwrap();
    assert_eq!(raw_digest[0], 0xa7);
    assert_eq!(raw_digest[1], 0x1a);
    assert_eq!(raw_digest[31], 0x5d);
    assert_eq!(decode_sha256_hex(""), None);
    assert_eq!(decode_sha256_hex(&S546_CANDIDATE_IMAGE_SHA256[..63]), None);
    let mut longer = String::from(S546_CANDIDATE_IMAGE_SHA256);
    longer.push('0');
    assert_eq!(decode_sha256_hex(&longer), None);
    let mut invalid = String::from(S546_CANDIDATE_IMAGE_SHA256);
    invalid.replace_range(10..11, "g");
    assert_eq!(decode_sha256_hex(&invalid), None);
    let mut uppercase = String::from(S546_CANDIDATE_IMAGE_SHA256);
    uppercase.replace_range(0..1, "E");
    assert_eq!(decode_sha256_hex(&uppercase), None);
}

#[test]
fn immutable_s540_raw_classifies_red_awaiting_preflight() {
    assert_eq!(S540_RAW.len(), S546_S540_RAW_BYTES);
    assert_eq!(S540_RAW.len(), 20_525);
    let counts = count_markers(S540_RAW);
    assert_eq!(counts.boot8g, 1);
    assert_eq!(counts.boot8h, 1);
    assert_eq!(counts.required_marker, 0);
    assert_eq!(counts.route_marker, 0);
    assert_eq!(counts.handoff_marker, 0);
    assert_eq!(counts.s541_error, 0);
    assert_eq!(counts.s538_error, 1);
    assert_eq!(counts.awaiting_preflight_token, 1);
    assert_eq!(counts.cpu0_readiness_timeout_token, 0);
    assert_eq!(counts.panic, 0);
    assert_eq!(counts.unknown_irq, 0);
    let verdict = classify(S540_RAW);
    assert_eq!(verdict, G8lS546Verdict::RedAwaitingPreflight);
    assert!(verdict.is_red());
    assert!(!verdict.is_pass());
    assert_eq!(verdict.label(), "RED_AWAITING_PREFLIGHT");
    assert!(S546_S540_PHYSICAL_VERDICT_RETAINED_RED);
}

#[test]
fn immutable_s543_raw_classifies_red_cpu0_readiness_timeout() {
    assert_eq!(S543_RAW.len(), S546_S543_RAW_BYTES);
    assert_eq!(S543_RAW.len(), 20_509);
    let counts = count_markers(S543_RAW);
    assert_eq!(counts.boot8g, 1);
    assert_eq!(counts.boot8h, 1);
    assert_eq!(counts.required_marker, 0);
    assert_eq!(counts.route_marker, 0);
    assert_eq!(counts.handoff_marker, 0);
    assert_eq!(counts.s541_error, 1);
    assert_eq!(counts.s538_error, 0);
    assert_eq!(counts.awaiting_preflight_token, 0);
    assert_eq!(counts.cpu0_readiness_timeout_token, 1);
    assert_eq!(counts.panic, 0);
    assert_eq!(counts.unknown_irq, 0);
    let verdict = classify(S543_RAW);
    assert_eq!(verdict, G8lS546Verdict::RedCpu0ReadinessTimeout);
    assert!(verdict.is_red());
    assert!(!verdict.is_pass());
    assert_eq!(verdict.label(), "RED_CPU0_READINESS_TIMEOUT");
    assert!(S546_S543_PHYSICAL_VERDICT_RETAINED_RED);
}

#[test]
fn immutable_s546_raw_classifies_red_boot8h_absent_primary_fail_silent() {
    assert_eq!(S546_RAW.len(), S546_RAW_BYTES);
    assert_eq!(S546_RAW.len(), 16_990);
    let counts = count_markers(S546_RAW);
    assert_eq!(counts.boot8g, 1);
    assert_eq!(counts.boot8h, 0);
    assert_eq!(counts.required_marker, 0);
    assert_eq!(counts.route_marker, 0);
    assert_eq!(counts.handoff_marker, 0);
    assert_eq!(counts.s541_error, 0);
    assert_eq!(counts.s538_error, 0);
    assert_eq!(counts.awaiting_preflight_token, 0);
    assert_eq!(counts.cpu0_readiness_timeout_token, 0);
    assert_eq!(counts.panic, 0);
    assert_eq!(counts.unknown_irq, 0);
    assert_eq!(counts.error_total(), 0);
    assert!(!counts.is_pass_matrix());
    let verdict = classify(S546_RAW);
    assert_eq!(verdict, G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent);
    assert!(verdict.is_red());
    assert!(!verdict.is_pass());
    assert_eq!(verdict.label(), "RED_BOOT8H_ABSENT_PRIMARY_FAIL_SILENT");
    assert!(S546_PHYSICAL_GATE_RED);
    assert!(!S546_PHYSICAL_VERDICT_PENDING);
}

#[test]
fn immutable_s546_raw_wire_shape_is_exact() {
    assert!(S546_RAW[..S546_RAW_LEADING_NUL_BYTES]
        .iter()
        .all(|byte| *byte == 0));
    assert_ne!(S546_RAW[S546_RAW_LEADING_NUL_BYTES], 0);
    assert_eq!(
        S546_RAW.iter().filter(|byte| **byte == 0).count(),
        S546_RAW_TOTAL_NUL_BYTES
    );
    assert_eq!(
        S546_RAW.iter().filter(|byte| **byte == b'\r').count(),
        S546_RAW_CR_BYTES
    );
    assert_eq!(
        S546_RAW.iter().filter(|byte| **byte == b'\n').count(),
        S546_RAW_LF_BYTES
    );
    let payloads = [
        ("s546-capture.log", S546_CAPTURE_LOG),
        ("s546-flash.log", S546_FLASH_LOG),
        ("s546-uart.raw", S546_RAW),
    ];
    let manifest_lines = S546_EVIDENCE_SHA256SUMS.lines().collect::<Vec<_>>();
    assert_eq!(manifest_lines.len(), payloads.len());
    assert_eq!(S546_EVIDENCE_SHA256SUMS.len(), 244);
    for (line, (name, payload)) in manifest_lines.into_iter().zip(payloads) {
        let (digest, listed_name) = line.split_once("  ").unwrap();
        assert_eq!(listed_name, name);
        assert_eq!(digest.len(), 64);
        assert!(digest
            .bytes()
            .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)));
        assert_eq!(format!("{:x}", Sha256::digest(payload)), digest);
    }
    // The raw ends quiescent after BOOT8G: the last line completes and no
    // BOOT8H, marker or error byte follows anywhere after it.
    assert!(S546_RAW.ends_with(b"BASE_TICKS=1005 TICKS=1005\r\n"));
    let boot8g_at = S546_RAW
        .windows(S546_BOOT8G_MARKER.len())
        .position(|window| window == S546_BOOT8G_MARKER.as_bytes())
        .unwrap();
    assert_eq!(
        count_substring(&S546_RAW[boot8g_at..], S546_BOOT_MARKER.as_bytes()),
        0
    );
    assert_eq!(
        classify(&S546_RAW[..boot8g_at]),
        G8lS546Verdict::Inconclusive
    );
}

#[test]
fn synthetic_exact_marker_matrix_classifies_pass() {
    let raw = synthetic_pass_raw();
    let counts = count_markers(&raw);
    assert_eq!(counts.boot8h, 1);
    assert_eq!(counts.required_marker, 1);
    assert_eq!(counts.route_marker, 1);
    assert_eq!(counts.handoff_marker, 1);
    assert_eq!(counts.error_total(), 0);
    assert!(counts.is_pass_matrix());
    let verdict = classify(&raw);
    assert_eq!(verdict, G8lS546Verdict::Pass);
    assert!(verdict.is_pass());
    assert!(!verdict.is_red());
    assert_eq!(verdict.label(), "PASS");
}

#[test]
fn duplicate_required_marker_is_not_pass() {
    let mut raw = synthetic_pass_raw();
    raw.extend_from_slice(S546_REQUIRED_MARKER.as_bytes());
    raw.extend_from_slice(b"\r\n");
    let counts = count_markers(&raw);
    assert_eq!(counts.required_marker, 2);
    assert!(!counts.is_pass_matrix());
    assert_eq!(classify(&raw), G8lS546Verdict::RedMarkerAbsent);
}

#[test]
fn missing_route_or_handoff_marker_is_red_marker_absent() {
    let pass = synthetic_pass_raw();
    let pass_text = String::from_utf8_lossy(&pass).into_owned();
    let without_route = pass_text.replacen(S546_ROUTE_MARKER, "ASELSAN/S538 ROUTE=NONE", 1);
    assert_eq!(
        classify(without_route.as_bytes()),
        G8lS546Verdict::RedMarkerAbsent
    );
    let without_handoff = pass_text.replacen(S546_HANDOFF_MARKER, "ASELSAN/S541 HANDOFF=NONE", 1);
    assert_eq!(
        classify(without_handoff.as_bytes()),
        G8lS546Verdict::RedMarkerAbsent
    );
    let without_required = pass_text.replacen(S546_REQUIRED_MARKER, "[R1:S536] PENDING", 1);
    assert_eq!(
        classify(without_required.as_bytes()),
        G8lS546Verdict::RedMarkerAbsent
    );
}

#[test]
fn panic_and_unknown_irq_override_marker_matrix() {
    let mut with_panic = synthetic_pass_raw();
    with_panic.extend_from_slice(b"kernel panic: unreachable\r\n");
    assert_eq!(count_markers(&with_panic).panic, 1);
    assert_eq!(classify(&with_panic), G8lS546Verdict::RedPanic);
    let mut with_upper_panic = synthetic_pass_raw();
    with_upper_panic.extend_from_slice(b"PANIC\r\n");
    assert_eq!(classify(&with_upper_panic), G8lS546Verdict::RedPanic);
    let mut with_unknown_irq = synthetic_pass_raw();
    with_unknown_irq.extend_from_slice(b"Bilinmeyen IRQ 1023\r\n");
    assert_eq!(count_markers(&with_unknown_irq).unknown_irq, 1);
    assert_eq!(classify(&with_unknown_irq), G8lS546Verdict::RedUnknownIrq);
    let mut with_english_irq = synthetic_pass_raw();
    with_english_irq.extend_from_slice(b"unknown IRQ 1023\r\n");
    assert_eq!(classify(&with_english_irq), G8lS546Verdict::RedUnknownIrq);
    let mut panic_before_irq = synthetic_pass_raw();
    panic_before_irq.extend_from_slice(b"unknown IRQ then panic\r\n");
    assert_eq!(classify(&panic_before_irq), G8lS546Verdict::RedPanic);
}

#[test]
fn error_markers_override_pass_matrix_and_boot8h_absence_partitions_exactly() {
    let mut s538 = synthetic_pass_raw();
    s538.extend_from_slice(b"ASELSAN/S538ERR AwaitingPreflight\r\n");
    assert_eq!(classify(&s538), G8lS546Verdict::RedAwaitingPreflight);
    let mut s541 = synthetic_pass_raw();
    s541.extend_from_slice(b"ASELSAN/S541ERR Cpu0ReadinessTimeout\r\n");
    assert_eq!(classify(&s541), G8lS546Verdict::RedCpu0ReadinessTimeout);
    let mut s541_other = synthetic_pass_raw();
    s541_other.extend_from_slice(b"ASELSAN/S541ERR Other\r\n");
    assert_eq!(classify(&s541_other), G8lS546Verdict::RedMarkerAbsent);
    assert_eq!(classify(b""), G8lS546Verdict::Inconclusive);
    assert_eq!(classify(b"\0\0\0"), G8lS546Verdict::Inconclusive);
    // BOOT8G alone with zero error tokens is the S546 silent-hang class;
    // BOOT8G with an error token stays Inconclusive (mixed, indeterminate).
    assert_eq!(
        classify(b"ASELSAN/BOOT8G TIMER=PER_CPU\r\n"),
        G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent
    );
    assert_eq!(
        classify(b"ASELSAN/BOOT8G then panic\r\n"),
        G8lS546Verdict::Inconclusive
    );
    let text = String::from_utf8_lossy(&synthetic_pass_raw()).into_owned();
    let no_boot8h = text.replacen("ASELSAN/BOOT8H", "ASELSAN/BOOT8G", 1);
    assert_eq!(
        classify(no_boot8h.as_bytes()),
        G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent
    );
    let boot8h_at = S540_RAW
        .windows(S546_BOOT_MARKER.len())
        .position(|window| window == S546_BOOT_MARKER.as_bytes())
        .unwrap();
    // The S540 prefix before BOOT8H already contains BOOT8G and no error
    // token, so under the recorded S546 class it is exactly the silent hang.
    assert_eq!(
        classify(&S540_RAW[..boot8h_at]),
        G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent
    );
    assert_eq!(
        classify(&S540_RAW[..boot8h_at + S546_BOOT_MARKER.len()]),
        G8lS546Verdict::RedMarkerAbsent
    );
    assert_eq!(classify(&S543_RAW[..40]), G8lS546Verdict::Inconclusive);
}

#[test]
fn substring_counter_is_exact_and_non_overlapping() {
    assert_eq!(count_substring(b"", b"a"), 0);
    assert_eq!(count_substring(b"abc", b""), 0);
    assert_eq!(count_substring(b"ab", b"abc"), 0);
    assert_eq!(count_substring(b"aaaa", b"aa"), 2);
    assert_eq!(
        count_substring(b"ASELSAN/BOOT8H ASELSAN/BOOT8H", b"ASELSAN/BOOT8H"),
        2
    );
    assert_eq!(count_substring(b"ASELSAN/BOOT8", b"ASELSAN/BOOT8H"), 0);
    assert_eq!(count_substring(S540_RAW, b"ASELSANBOOT"), 2);
}

#[test]
fn runbook_completes_only_in_canonical_order_with_exact_reporters() {
    let mut ledger = G8lS546RunbookLedger::new();
    assert_eq!(ledger.next_step(), Some(G8lS546RunbookStep::PowerOff));
    for (index, step) in G8lS546RunbookStep::ORDER.into_iter().enumerate() {
        assert_eq!(step.index(), index);
        assert_eq!(G8lS546RunbookStep::from_index(index), Some(step));
        let receipt = ledger
            .advance(step, step.reporter(), full_attestation())
            .unwrap();
        assert_eq!(receipt.step, step);
        assert_eq!(receipt.index, index);
        assert_eq!(receipt.reporter, step.reporter());
        assert_eq!(ledger.accepted_steps(), index + 1);
        assert_eq!(ledger.receipt(step), Some(receipt));
    }
    assert!(ledger.is_complete());
    assert_eq!(ledger.next_step(), None);
    assert_eq!(G8lS546RunbookStep::from_index(10), None);
    let host = G8lS546RunbookStep::ORDER
        .iter()
        .filter(|step| step.reporter() == G8lS546StepReporter::HostObserved)
        .count();
    assert_eq!(host, S546_RUNBOOK_HOST_OBSERVED_STEPS);
    assert_eq!(10 - host, S546_RUNBOOK_OPERATOR_REPORTED_STEPS);
    assert_eq!(
        G8lS546RunbookStep::AuthorizedWriteVerifyReadBack.reporter(),
        G8lS546StepReporter::HostObserved
    );
    assert_eq!(
        G8lS546RunbookStep::PowerOn.reporter(),
        G8lS546StepReporter::OperatorReported
    );
    assert_eq!(
        ledger.advance(
            G8lS546RunbookStep::CardBackToMacReauth,
            G8lS546StepReporter::HostObserved,
            full_attestation()
        ),
        Err(G8lS546Error::RunbookAlreadyComplete)
    );
}

#[test]
fn runbook_order_violations_fail_closed_without_mutation() {
    let mut ledger = G8lS546RunbookLedger::new();
    assert_eq!(
        ledger.advance(
            G8lS546RunbookStep::PowerOn,
            G8lS546StepReporter::OperatorReported,
            full_attestation()
        ),
        Err(G8lS546Error::RunbookOutOfOrder)
    );
    assert_eq!(ledger.accepted_steps(), 0);
    ledger
        .advance(
            G8lS546RunbookStep::PowerOff,
            G8lS546StepReporter::OperatorReported,
            G8lS546StepAttestation::NONE,
        )
        .unwrap();
    ledger
        .advance(
            G8lS546RunbookStep::CardOutOfPi,
            G8lS546StepReporter::OperatorReported,
            G8lS546StepAttestation::NONE,
        )
        .unwrap();
    let snapshot = ledger.clone();
    assert_eq!(
        ledger.advance(
            G8lS546RunbookStep::AuthorizedWriteVerifyReadBack,
            G8lS546StepReporter::HostObserved,
            full_attestation()
        ),
        Err(G8lS546Error::RunbookOutOfOrder)
    );
    assert_eq!(
        ledger.advance(
            G8lS546RunbookStep::PowerOff,
            G8lS546StepReporter::OperatorReported,
            G8lS546StepAttestation::NONE
        ),
        Err(G8lS546Error::RunbookStepReplay)
    );
    assert_eq!(
        ledger.advance(
            G8lS546RunbookStep::CardIntoMac,
            G8lS546StepReporter::OperatorReported,
            G8lS546StepAttestation::NONE
        ),
        Err(G8lS546Error::RunbookReporterMismatch)
    );
    assert_eq!(ledger, snapshot);
    assert_eq!(ledger.next_step(), Some(G8lS546RunbookStep::CardIntoMac));
}

#[test]
fn runbook_write_and_identity_steps_require_attestations() {
    let mut ledger = G8lS546RunbookLedger::new();
    for step in &G8lS546RunbookStep::ORDER[..3] {
        ledger
            .advance(*step, step.reporter(), G8lS546StepAttestation::NONE)
            .unwrap();
    }
    let write = G8lS546RunbookStep::AuthorizedWriteVerifyReadBack;
    for partial in [
        G8lS546StepAttestation::NONE,
        G8lS546StepAttestation {
            authority_token_exact: true,
            read_back_byte_exact: false,
            target_identity_exact: true,
        },
        G8lS546StepAttestation {
            authority_token_exact: false,
            read_back_byte_exact: true,
            target_identity_exact: true,
        },
        G8lS546StepAttestation {
            authority_token_exact: true,
            read_back_byte_exact: true,
            target_identity_exact: false,
        },
    ] {
        assert_eq!(
            ledger.advance(write, G8lS546StepReporter::HostObserved, partial),
            Err(G8lS546Error::RunbookAttestationMissing)
        );
        assert_eq!(ledger.accepted_steps(), 3);
    }
    ledger
        .advance(write, G8lS546StepReporter::HostObserved, full_attestation())
        .unwrap();
    ledger
        .advance(
            G8lS546RunbookStep::SafeEject,
            G8lS546StepReporter::HostObserved,
            G8lS546StepAttestation::NONE,
        )
        .unwrap();
    ledger
        .advance(
            G8lS546RunbookStep::CardIntoUnpoweredPi,
            G8lS546StepReporter::OperatorReported,
            G8lS546StepAttestation::NONE,
        )
        .unwrap();
    assert_eq!(
        ledger.advance(
            G8lS546RunbookStep::UartPreArmExactIdentity,
            G8lS546StepReporter::HostObserved,
            G8lS546StepAttestation::NONE
        ),
        Err(G8lS546Error::RunbookAttestationMissing)
    );
    assert_eq!(
        ledger.next_step(),
        Some(G8lS546RunbookStep::UartPreArmExactIdentity)
    );
    assert!(G8lS546StepAttestation::default().satisfies(G8lS546StepAttestation::NONE));
    assert!(!G8lS546StepAttestation::default().satisfies(write.required_attestation()));
    assert_eq!(
        G8lS546RunbookStep::ORDER
            .iter()
            .filter(|step| step.is_power_transition())
            .count(),
        3
    );
}

#[test]
fn verdict_has_no_promotion_path_and_pass_comes_only_from_raw_bytes() {
    for verdict in [
        G8lS546Verdict::RedAwaitingPreflight,
        G8lS546Verdict::RedCpu0ReadinessTimeout,
        G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent,
        G8lS546Verdict::RedMarkerAbsent,
        G8lS546Verdict::RedPanic,
        G8lS546Verdict::RedUnknownIrq,
    ] {
        assert!(verdict.is_red());
        assert!(!verdict.is_pass());
    }
    assert!(!G8lS546Verdict::Inconclusive.is_red());
    assert!(!G8lS546Verdict::Inconclusive.is_pass());
    let verdict_block = SOURCE
        .split("pub enum G8lS546Verdict")
        .nth(1)
        .unwrap()
        .split("pub fn count_substring")
        .next()
        .unwrap();
    for forbidden in [
        "fn promote",
        "fn upgrade",
        "impl From",
        "impl Default",
        "fn pass(",
    ] {
        assert!(!verdict_block.contains(forbidden), "forbidden: {forbidden}");
    }
    assert_eq!(SOURCE.matches("G8lS546Verdict::Pass").count(), 1);
    assert!(SOURCE.contains("if counts.is_pass_matrix() {\n        return G8lS546Verdict::Pass;"));
    assert!(SOURCE.contains("Self::Pass => \"PASS\""));
    assert!(SOURCE.contains("matches!(self, Self::Pass)"));
    assert!(
        SOURCE.contains("physical_verdict: Some(G8lS546Verdict::RedBoot8hAbsentPrimaryFailSilent)")
    );
    assert!(!SOURCE.contains("Some(G8lS546Verdict::Pass)"));
}

#[test]
fn recorded_physical_red_keeps_r1_claims_and_promotion_closed() {
    for contract in [
        "S546_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS: usize = 1",
        "S546_PHYSICAL_OBSERVATIONS: usize = 1",
        "S546_PHYSICAL_OR_DEVICE_OPERATIONS: usize = 1",
        "S546_SD_WRITE_TRANSACTIONS: usize = 1",
        "S546_SD_WRITES: usize = 4",
        "S546_UART_OPENS: usize = 1",
        "S546_POWER_TRANSITIONS: usize = 2",
        "S546_POWER_TRANSITIONS_OPERATOR_REPORTED: usize = 2",
        "S546_POWER_TRANSITIONS_INDEPENDENTLY_OBSERVED: usize = 0",
        "S546_NEW_IMMUTABLE_RAW_CAPTURES: usize = 1",
        "S546_HARDWARE_PRESENT: bool = true",
        "S546_R1_ACCEPTANCE_COMPLETE: bool = false",
        "S546_BOOT_TO_UI_PHYSICALLY_OBSERVED: bool = false",
        "S546_AUTOMATIC_PROMOTION: bool = false",
        "S546_PHYSICAL_RUN_RECORDED: bool = true",
        "S546_PHYSICAL_VERDICT_PENDING: bool = false",
        "S546_PHYSICAL_GATE_RED: bool = true",
        "S546_RED_CLASS: &str = \"Boot8hAbsentPrimaryFailSilent\"",
        "S546_RAW_BYTES: usize = 16990",
        "\"a71a9107b4b6ea351eb65720a6b82486105fffdb931563d1c39e8a381c3e485d\"",
        "RUNBOOK_EXECUTED_IN_S546: bool = true",
    ] {
        assert!(SOURCE.contains(contract), "{contract}");
    }
    assert!(SOURCE.contains("RUNBOOK_EXECUTED_IN_S546=YES"));
    assert!(SOURCE.contains("automatic S547 promotion"));
    assert!(SOURCE.contains("exceptions.rs:3173"));
    assert!(SOURCE.contains("exceptions.rs:1326"));
    assert!(SOURCE.contains("AcceptanceLedgerNotReady"));
    assert!(SOURCE.contains("secondary_fail(ERR_PRIMARY_VALIDATION=43, 544, 7)"));
    assert!(SOURCE.contains("S569"));
    assert!(SOURCE.contains("S570 (candidate freeze), S571"));
    assert!(SOURCE.contains("a plan, not a commitment"));
}
snippet sha256: 4d9b7da4d243file sha256: 4d9b7da4d243
03 · Kapı kimlik kaydı

Operations sıra, kimlik ve başlık bağı

tam Operations kaydıL3146–L3231
website/src/lib/operations.ts::g8l-s546-r1-reachable-producer-physical-boot-uart-run
  {
    id: "g8l-s546-r1-reachable-producer-physical-boot-uart-run",
    date: "2026-08-30",
    sequence: 546,
    status: "failed",
    umbrella_status: "partial",
    title: "S546 · R1 üçüncü fiziksel boot/UART koşusu — RED",
    summary:
      "S546 üçüncü gerçek RPi5 boot/UART fiziksel koşusudur ve yeni bir hata sınıfıyla immutable RED'dir: sessiz pre-BOOT8H takılması (Boot8hAbsentPrimaryFailSilent). Exact S545 candidate (945760 B / ed1901a9…08d467) tek yetkili transaction ile karta yazıldı, UART güçten önce exclusive pre-arm edildi ve tek power-on tüketildi; kart ASELSAN/BOOT8G'ye kadar boot etti, sonra hiçbir UART çıktısı gelmedi ve host >60 s sessizlik sonrası capture'ı kapattı (capture_closed=true terminal_seen=false grace_complete=false success=false). Yeni immutable raw 16990 B / a71a9107…3e485d / 0444 / nlink=1'dir: BOOT8G=1, BOOT8H=0, BOOT_TO_UI_READY=0, S538 route=0, S541 handoff=0 ve S541ERR/S538ERR/panic/unknown IRQ=0/0/0/0 — S540 ve S543'ün aksine hiçbir hata marker'ı yoktur. Kaynak nedeni deterministiktir: S544 boot hook'u S431–S535 ledger'ını ister, ledger'ın S430 çapası yalnız G8h erken dönüşünün (exceptions.rs:1326) altındaki CPU1 generic-timer PPI27 yolunda (exceptions.rs:3173) üretilir, hook AcceptanceLedgerNotReady (7) ile düşer, CPU1 secondary_fail(43, 544, 7) yayımlar ve CPU0 primary_fail sessiz park eder — UART satırı yoktur. Focused 24/24 PASS yalnız RED kaydının bütünlüğünü doğrular; fiziksel PASS değildir ve S540 ve S543 fiziksel RED değişmez. RUNBOOK_EXECUTED_IN_S546=YES, physical observations=1, operatör-bildirimli güç geçişi=2 (bağımsız gözlem=0), Boot-to-UI=false, R1 acceptance=false'dur. Remediation zinciri plan olarak S569 (kaynak) → S570 (freeze) → S571 (fiziksel koşu) şeklindedir.",
    evidence: [
      "S546 dar fiziksel kapısı immutable RED'dir ve yeni hata sınıfı Boot8hAbsentPrimaryFailSilent olarak adlandırılır: BOOT8G görüldü, BOOT8H ve tüm R1 marker'ları yok, hiçbir hata/panic/unknown-IRQ satırı yok.",
      "Operatör tek S546 transaction'ını yetkilendirdi: kart (serial 0x425001fa) fresh doğrulandı, exact S545 dört-dosya paketi staged write/byte-exact read-back/sync/eject ile yazıldı; flash preflight ve exact4 sonucu PASS'tir.",
      "Flash log 246 B / 4d64a7bfa152e8e1b69925cd35bef9c4a735b4e32de49b8dc9069186917f5ccf; flash script 23845 B / cccc58885051484ca92846040457453a931aedbd7cdd0910ab5d1233c1fc11ef SHA-256'dır.",
      "Exact Debug Probe UART'ı güçten önce exclusive 115200/8N1 + TCIFLUSH + fresh O_EXCL raw inode ile pre-arm edildi; capture wrapper 351 B / f3f6e84f1af7335a39d241c7968235bad5cb20e27c64da92930a8f6f99b40420, audited S540 engine 20572 B / 9f001c4cec407bbb4310ca0f89d9cc7e8a1be32307ba8d7ea0541e315ff1efec SHA-256'dır.",
      "Immutable raw 16990 B / a71a9107b4b6ea351eb65720a6b82486105fffdb931563d1c39e8a381c3e485d SHA-256 / mode 0444 / nlink 1'dir; wire şekli leading NUL=7, toplam NUL=22 ve CR/LF=206/206 değerlerini korur.",
      "Capture kapanışı host tarafındadır: capture_closed=true terminal_seen=false grace_complete=false success=false (>60 s sessizlik sonrası host SIGTERM); success marker'ı hiç gelmedi.",
      "Marker matrisi BOOT8G=1, BOOT8H=0, BOOT_TO_UI_READY=0, S538 route=0, S541 handoff=0, S541ERR=0, S538ERR=0, panic/PANIC=0/0 ve unknown/Bilinmeyen IRQ=0/0'dır; hata marker'sız kesilme S540/S543'ten farklı yeni bir sınıftır.",
      "Daraltılmış kaynak nedeni deterministiktir: S544 boot hook'u S431–S535 ledger'ının tamamlanmasını ister; ledger'ın S430 çapası yalnız exceptions.rs:3173'teki CPU1 generic-timer PPI27 yolunda üretilir ve bu yol G8h erken dönüşünün (exceptions.rs:1326) altındadır — G8h'den önce hiç koşmaz, G8h sonrası timer kapalıdır.",
      "Hook bu yüzden AcceptanceLedgerNotReady (diagnostic 7) döner, CPU1 secondary_fail(ERR_PRIMARY_VALIDATION=43, 544, 7) yayımlar, CPU0 wait_for_cpu1_epoch hatayı görür ve primary_fail hiçbir UART satırı yazmadan sessiz park eder; raw bu yüzden BOOT8G'de biter.",
      "İkincil bulgu: primary_fail hiçbir şey yazmadığı için her pre-BOOT8H arızası UART'ta görünmezdir; remediation hem R1 marker zincirini erişilemeyen ledger'dan ayırmalı hem de G8h primary failure yoluna bounded bir UART hata satırı eklemelidir.",
      "Kernel modülü kaydedilen RED'i sabitler: S546_PHYSICAL_RUN_RECORDED=true, S546_PHYSICAL_VERDICT_PENDING=false, S546_PHYSICAL_GATE_RED=true, S546_RED_CLASS=Boot8hAbsentPrimaryFailSilent, S546_RAW_BYTES=16990 ve S546_RAW_SHA256 exact bağlanır; Pass iddiası hiçbir istekte kabul edilmez.",
      "classify(raw) sınıflandırıcısına RedBoot8hAbsentPrimaryFailSilent varyantı eklendi: BOOT8H yok + BOOT8G>=1 + sıfır hata/panic/unknown-IRQ token'ı bu sınıfı verir; focused test immutable S546 raw'ını include_bytes! ile bu sınıfa, S540 raw'ını RedAwaitingPreflight'a ve S543 raw'ını RedCpu0ReadinessTimeout'a değişmeden sınıflandırır.",
      "Focused target 1 grup / 24 passed / 0 failed / 0 ignored / 0 filtered verdi; bu yalnız RED kaydının bütünlüğünü doğrular, fiziksel PASS değildir.",
      "Implementation 28279 B / 4e45fbd2d02a275ac2395f0e3ec26a76d72ece51afbf1ac247882d5ca149cb05; focused test 34015 B / 4d9b7da4d243e5311ccb8404b1660b32cebcc6cfc54bd43ec1cd1abb6c660935 SHA-256'dır.",
      "Proof 8626 B'dır.",
      "RUNBOOK_EXECUTED_IN_S546=YES: on adımlı runbook eksiksiz uygulandı (preflight PASS, staged write/read-back/sync/eject PASS, UART pre-arm PASS, tek power-on, host capture kapanışı, operatör power-off); bu partideki tek runbook'u koşulmuş S-kapısıdır.",
      "S546 sayaçları: physical observations=1, SD write transaction=1 (4 payload commit), UART open=1, yeni immutable raw=1; güç geçişleri operatör-bildirimli 2, bağımsız gözlem 0'dır.",
      "S540 raw'ı 20525 B / fc3f934543ab5d829ad8a16e2b332dd2bdc35a81c6c0f6423256101448e45114 ve S543 raw'ı 20509 B / 1f1111a1a39ab6263b505b0889d025df19d5c48bb2f84e30708412b0da47dc11 byte-exact immutable RED olarak korunur; hiçbir sonuç bunları yükseltmez.",
      "Otomatik S547 promotion yoktur; remediation zinciri plan olarak S569 (kaynak: R1 marker zincirini erişilemeyen ledger'dan ayır + G8h primary_fail'e bounded UART hata satırı), S570 (candidate freeze) ve S571 (ayrı yetkili fiziksel koşu) şeklindedir — numaralandırma taahhüt değildir.",
    ],
    commands: [
      "scripts/flash-rpi5-s546-r1-candidate.sh EXACT_AUTH S545_PACKAGE /Volumes/ASELSANBOOT /dev/disk6",
      "build scripts/capture-rpi5-s546-r1-uart.c with strict warnings; pre-arm the exact Debug Probe UART and capture one power-on",
      "CARGO_INCREMENTAL=0 cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s546_r1_reachable_producer_physical_boot_uart_run -- --test-threads=1",
    ],
    terminalSessions: [
      {
        id: "s546-sd-write-readback-eject",
        title: "S546 exact target, SD write/read-back ve eject",
        commandLines: [
          "run zero-write exact target preflight",
          "scripts/flash-rpi5-s546-r1-candidate.sh EXACT_AUTH S545_PACKAGE /Volumes/ASELSANBOOT /dev/disk6",
        ],
        outputLines: [
          "zero-write preflight=PASS; write/eject/UART/power=0/0/0/0",
          "candidate=945760 B / ed1901a9…08d467; card=0x425001fa",
          "PASS: S546 reachable-producer candidate exact4 staged/commit/read-back/sync/eject",
          "S546_LOCK RETAINED=YES DEVICE=/dev/disk6 EJECT=PASS UART=NOT_OPENED POWER=NOT_RUN",
          "flash exit=0",
        ],
        exitCode: 0,
        outputMode: "complete",
      },
      {
        id: "s546-one-power-uart-capture",
        title: "S546 tek power-on immutable UART koşusu — sessiz pre-BOOT8H RED",
        commandLines: [
          "strict-build S546 wrapper + audited capture engine",
          "pre-arm exact Debug Probe at exclusive 115200/8N1; operator power-on; capture; operator power-off",
        ],
        outputLines: [
          "capture armed before power-on: TIOCEXCL + 115200/8N1 + TCIFLUSH + O_EXCL",
          "capture_signal_before_complete=YES (host SIGTERM after >60 s quiescence)",
          "capture_closed=true terminal_seen=false grace_complete=false success=false",
          "raw=16990 B / a71a9107…3e485d / 0444 / nlink1; leading NUL=7; CR/LF=206/206",
          "BOOT8G=1; BOOT8H=0; BOOT_TO_UI_READY=0; S538ERR/S541ERR/panic/unknown IRQ=0",
          "physical verdict=RED Boot8hAbsentPrimaryFailSilent; no error marker on any line",
          "operator power-off reported; UART holders=0; independent electrical observation=0",
        ],
        exitCode: 1,
        outputMode: "complete",
        outputNote:
          "TAM ÇIKTI · exit 1 fiziksel RED sonucudur; capture helper arızası değildir — success marker'ı hiç gelmedi ve host kapattı.",
      },
    ],
    terminalSessionsNote:
      "S546 fiziksel kapısı immutable RED'dir (sessiz pre-BOOT8H takılması); focused 24/24 PASS yalnız kaydın bütünlüğünü doğrular. S540 ve S543 RED raw'ları ve kararları değişmez.",
    limitations: [
      "S546 immutable fiziksel RED'dir; koşu tekrarlanamaz ve geriye dönük yükseltilemez — hiçbir sınıflandırıcı sonucu veya state geçişi RED'i PASS yapamaz.",
      "S540 ve S543 fiziksel RED immutable kalır; S546 sonucu bunları ne yükseltir ne yeniden yorumlar.",
      "BOOT_TO_UI_READY hiçbir konumda görülmedi; Boot-to-UI physically observed=false ve R1 acceptance=false kalır.",
      "Güç geçişleri yalnız operatör bildirimlidir (2); bağımsız elektriksel gözlem 0'dır ve sessiz takılmanın board-içi zamanlaması UART'tan ölçülemez.",
      "primary_fail UART'a hiçbir şey yazmadığı için pre-BOOT8H arızaları görünmezdir; bu, S569 kaynak remediation'ının kapsamındadır.",
      "Otomatik S547 promotion yoktur; S547–S568 sıfır donanım iddialı source-model kapılar olarak devam eder ve S569 → S570 → S571 remediation zinciri plan olup taahhüt değildir.",
    ],
  },
snippet sha256: da264df862e1file sha256: 9726dbf00f84
Focused test komutu
CARGO_INCREMENTAL=0 cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s546_r1_reachable_producer_physical_boot_uart_run -- --test-threads=1
proof: docs/M8.1-RPi5-G8l-S546-R1-Reachable-Producer-Physical-Boot-Uart-Run-Evidence-Contract-Proof.md
Registry schema v5 · generator website/scripts/generate-code-gates.mjs · Tam SHA-256: 91d38c7b6222f0b4c117be786454853543da55a160e543d9b951057cc20dcc06