S566 · SOURCE-BOUND GATE EVIDENCE
S566 · R1 güncelleme: laboratuvar güncelleme gösterimi runbook sözleşmesi
tam S566 implementation modülü → Operations --test hedefi ile bağlı tam focused test → ayrı Operations kaydı Bu sayfa yalnız S566 kapısına aittir; komşu kapıların kaynakları bu kabulün içine katılmaz.
S566Focused kod testiOperations id exactsource SHA exacttest target exact
operation: g8l-s566-r1-lab-update-demonstration-runbook-contract
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–L868
kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s566_r1_lab_update_demonstration_runbook_contract.rs::S566 r1 lab update demonstration runbook contract implementation
//! S566 models the laboratory update demonstration runbook contract for the
//! R1 application/recovery/update stage. It is a host-side source model only:
//! the runbook is described, ordered and type-checked here, it is never
//! executed.
//!
//! The contract fixes six ordered steps (freeze package, verify manifest,
//! stage to the inactive slot, reboot, confirm boot markers, commit or
//! rollback). Every step carries a required evidence kind (hash, UART marker
//! or operator report) and an observation class (host-observed or
//! operator-reported). The frozen S545 package identities are reused as the
//! fixture "current image" so that later demonstrations bind to an exact,
//! already frozen artifact instead of an ad-hoc build. A demo-boundary
//! statement is part of the contract: the subject is a laboratory
//! demonstrator and no field or product claim is derivable from it.
//!
//! Fail-closed conditions: step reordering, duplicated or missing steps, a
//! missing or mismatched evidence kind, a mismatched observation class, a
//! current image that differs from the S545 fixture, malformed digests, any
//! field/product claim, any claim flag set without recorded evidence, any
//! claim that a step was executed or evidence was recorded, and divergence
//! after publication.
//!
//! The module performs no device operation, opens no UART, writes no SD card,
//! reports no power transition, and is not wired into any boot, IRQ,
//! scheduler or driver path. It cannot promote the immutable S540 or S543
//! physical RED verdicts. `RUNBOOK_EXECUTED_IN_S566` is `false`.
//!
//! Predecessor: S565 (staged update apply/rollback model). Next gate: S567
//! (application/recovery/update acceptance matrix).
pub const S566_SEQUENCE: usize = 566;
pub const S566_EXPECTED_PREDECESSOR: usize = 565;
pub const S566_NEXT_SEQUENCE: usize = 567;
pub const S566_R1_STAGE: u8 = 4;
pub const S566_R1_RANGE_FIRST: usize = 536;
pub const S566_R1_RANGE_LAST: usize = 568;
pub const S566_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS: usize = 0;
pub const S566_PHYSICAL_OBSERVATIONS: usize = 0;
pub const S566_PHYSICAL_OR_DEVICE_OPERATIONS: usize = 0;
pub const S566_SD_WRITES: usize = 0;
pub const S566_UART_OPENS: usize = 0;
pub const S566_POWER_TRANSITIONS: usize = 0;
pub const S566_NEW_IMMUTABLE_RAW_CAPTURES: usize = 0;
pub const S566_S540_PHYSICAL_VERDICT_RETAINED_RED: bool = true;
pub const S566_S543_PHYSICAL_VERDICT_RETAINED_RED: bool = true;
pub const S566_AUTOMATIC_PROMOTION: bool = false;
pub const S566_BOOT_TO_UI_PHYSICALLY_OBSERVED: bool = false;
pub const S566_HARDWARE_PRESENT: bool = false;
pub const S566_R1_ACCEPTANCE_COMPLETE: bool = false;
pub const RUNBOOK_EXECUTED_IN_S566: bool = false;
// Runbook shape.
pub const S566_RUNBOOK_STEP_COUNT: usize = 6;
pub const S566_HOST_OBSERVED_STEPS: usize = 4;
pub const S566_OPERATOR_REPORTED_STEPS: usize = 2;
pub const S566_HASH_EVIDENCE_STEPS: usize = 3;
pub const S566_UART_MARKER_EVIDENCE_STEPS: usize = 1;
pub const S566_OPERATOR_REPORT_EVIDENCE_STEPS: usize = 2;
pub const S566_EXECUTED_STEPS: usize = 0;
pub const S566_EVIDENCE_RECORDS: usize = 0;
pub const S566_DEMO_BOUNDARY_STATEMENT: &str =
"LAB_DEMONSTRATOR_ONLY; NO_FIELD_CLAIM; NO_PRODUCT_CLAIM";
pub const S566_ACTIVE_SLOT: G8lS566Slot = G8lS566Slot::A;
pub const S566_INACTIVE_SLOT: G8lS566Slot = G8lS566Slot::B;
// Fixture "current image": the frozen S545 package identities, byte-exact.
pub const S566_CURRENT_PACKAGE_ENTRIES: usize = 4;
pub const S566_CURRENT_IMAGE_NAME: &str = "aselsanos-rpi5.img";
pub const S566_CURRENT_IMAGE_BYTES: u64 = 945_760;
pub const S566_CURRENT_IMAGE_SHA256: &str =
"ed1901a991e2f9e9ae3c16f254147a2b0180686a8d70ca5d7353374fee08d467";
pub const S566_CURRENT_DTB_NAME: &str = "bcm2712-rpi-5-b.dtb";
pub const S566_CURRENT_DTB_BYTES: u64 = 78_703;
pub const S566_CURRENT_DTB_SHA256: &str =
"40a2fbe9c29e8b9a4912cf726a943068defb779fc052ec38e457a79c58abca00";
pub const S566_CURRENT_CONFIG_NAME: &str = "config.txt";
pub const S566_CURRENT_CONFIG_BYTES: u64 = 420;
pub const S566_CURRENT_CONFIG_SHA256: &str =
"aef848bf6e0c324148eade5054a15c71a1e8c04814a3ed2e680056f87c1f9bba";
pub const S566_CURRENT_MANIFEST_NAME: &str = "SHA256SUMS";
pub const S566_CURRENT_MANIFEST_BYTES: u64 = 248;
pub const S566_CURRENT_MANIFEST_SHA256: &str =
"4accd201849f68107db4d21e4657b1510f043d7f900f713c383bd8909d33e586";
pub const S566_CURRENT_MANIFEST_LINES: usize = 3;
// Boot markers the demonstration must confirm after the staged reboot.
pub const S566_BOOT_MARKER: &str = "ASELSAN/BOOT8H";
pub const S566_BOOT_TO_UI_MARKER: &str = "[R1:S536] BOOT_TO_UI_READY";
pub const S566_BOOT_MARKER_MINIMUM: usize = 1;
pub const S566_BOOT_TO_UI_MARKER_EXACT: usize = 1;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS566Slot {
A,
B,
}
impl G8lS566Slot {
pub const fn other(self) -> Self {
match self {
Self::A => Self::B,
Self::B => Self::A,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS566RunbookStep {
FreezePackage,
VerifyManifest,
StageToInactiveSlot,
Reboot,
ConfirmBootMarkers,
CommitOrRollback,
}
impl G8lS566RunbookStep {
pub const fn ordinal(self) -> usize {
match self {
Self::FreezePackage => 0,
Self::VerifyManifest => 1,
Self::StageToInactiveSlot => 2,
Self::Reboot => 3,
Self::ConfirmBootMarkers => 4,
Self::CommitOrRollback => 5,
}
}
pub const fn from_ordinal(ordinal: usize) -> Option<Self> {
match ordinal {
0 => Some(Self::FreezePackage),
1 => Some(Self::VerifyManifest),
2 => Some(Self::StageToInactiveSlot),
3 => Some(Self::Reboot),
4 => Some(Self::ConfirmBootMarkers),
5 => Some(Self::CommitOrRollback),
_ => None,
}
}
pub const fn next(self) -> Option<Self> {
Self::from_ordinal(self.ordinal() + 1)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS566EvidenceKind {
Hash,
UartMarker,
OperatorReport,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS566ObservationClass {
HostObserved,
OperatorReported,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566StepSpec {
pub step: G8lS566RunbookStep,
pub evidence_kind: G8lS566EvidenceKind,
pub observation_class: G8lS566ObservationClass,
}
pub const S566_RUNBOOK_TABLE: [G8lS566StepSpec; S566_RUNBOOK_STEP_COUNT] = [
G8lS566StepSpec {
step: G8lS566RunbookStep::FreezePackage,
evidence_kind: G8lS566EvidenceKind::Hash,
observation_class: G8lS566ObservationClass::HostObserved,
},
G8lS566StepSpec {
step: G8lS566RunbookStep::VerifyManifest,
evidence_kind: G8lS566EvidenceKind::Hash,
observation_class: G8lS566ObservationClass::HostObserved,
},
G8lS566StepSpec {
step: G8lS566RunbookStep::StageToInactiveSlot,
evidence_kind: G8lS566EvidenceKind::Hash,
observation_class: G8lS566ObservationClass::HostObserved,
},
G8lS566StepSpec {
step: G8lS566RunbookStep::Reboot,
evidence_kind: G8lS566EvidenceKind::OperatorReport,
observation_class: G8lS566ObservationClass::OperatorReported,
},
G8lS566StepSpec {
step: G8lS566RunbookStep::ConfirmBootMarkers,
evidence_kind: G8lS566EvidenceKind::UartMarker,
observation_class: G8lS566ObservationClass::HostObserved,
},
G8lS566StepSpec {
step: G8lS566RunbookStep::CommitOrRollback,
evidence_kind: G8lS566EvidenceKind::OperatorReport,
observation_class: G8lS566ObservationClass::OperatorReported,
},
];
pub const fn s566_runbook_spec(step: G8lS566RunbookStep) -> G8lS566StepSpec {
S566_RUNBOOK_TABLE[step.ordinal()]
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566ArtifactIdentity<'a> {
pub name: &'a str,
pub bytes: u64,
pub sha256: &'a str,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566PackageIdentity<'a> {
pub image: G8lS566ArtifactIdentity<'a>,
pub dtb: G8lS566ArtifactIdentity<'a>,
pub config: G8lS566ArtifactIdentity<'a>,
pub manifest: G8lS566ArtifactIdentity<'a>,
pub manifest_lines: usize,
}
pub const fn s566_current_image_fixture() -> G8lS566PackageIdentity<'static> {
G8lS566PackageIdentity {
image: G8lS566ArtifactIdentity {
name: S566_CURRENT_IMAGE_NAME,
bytes: S566_CURRENT_IMAGE_BYTES,
sha256: S566_CURRENT_IMAGE_SHA256,
},
dtb: G8lS566ArtifactIdentity {
name: S566_CURRENT_DTB_NAME,
bytes: S566_CURRENT_DTB_BYTES,
sha256: S566_CURRENT_DTB_SHA256,
},
config: G8lS566ArtifactIdentity {
name: S566_CURRENT_CONFIG_NAME,
bytes: S566_CURRENT_CONFIG_BYTES,
sha256: S566_CURRENT_CONFIG_SHA256,
},
manifest: G8lS566ArtifactIdentity {
name: S566_CURRENT_MANIFEST_NAME,
bytes: S566_CURRENT_MANIFEST_BYTES,
sha256: S566_CURRENT_MANIFEST_SHA256,
},
manifest_lines: S566_CURRENT_MANIFEST_LINES,
}
}
/// A demo-boundary statement. Only `{lab_demonstrator: true, field_claim:
/// false, product_claim: false}` is accepted.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566DemoBoundary {
pub lab_demonstrator: bool,
pub field_claim: bool,
pub product_claim: bool,
}
pub const S566_DEMO_BOUNDARY: G8lS566DemoBoundary = G8lS566DemoBoundary {
lab_demonstrator: true,
field_claim: false,
product_claim: false,
};
/// Claim flags. A flag may only be set when the ledger derives it from
/// recorded evidence; the contract itself has no evidence, so every flag must
/// be `false` at publication.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct G8lS566ClaimFlags {
pub update_demonstrated: bool,
pub rollback_demonstrated: bool,
pub boot_markers_confirmed: bool,
pub package_identity_verified: bool,
}
impl G8lS566ClaimFlags {
pub const NONE: Self = Self {
update_demonstrated: false,
rollback_demonstrated: false,
boot_markers_confirmed: false,
package_identity_verified: false,
};
pub const fn any(self) -> bool {
self.update_demonstrated
|| self.rollback_demonstrated
|| self.boot_markers_confirmed
|| self.package_identity_verified
}
/// `self` is a subset of `evidence`-derived flags.
pub const fn is_covered_by(self, derived: Self) -> bool {
(!self.update_demonstrated || derived.update_demonstrated)
&& (!self.rollback_demonstrated || derived.rollback_demonstrated)
&& (!self.boot_markers_confirmed || derived.boot_markers_confirmed)
&& (!self.package_identity_verified || derived.package_identity_verified)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566StepDeclaration {
pub ordinal: usize,
pub step: G8lS566RunbookStep,
pub evidence_kind: Option<G8lS566EvidenceKind>,
pub observation_class: G8lS566ObservationClass,
}
pub fn s566_canonical_declarations() -> [G8lS566StepDeclaration; S566_RUNBOOK_STEP_COUNT] {
let mut declarations = [G8lS566StepDeclaration {
ordinal: 0,
step: G8lS566RunbookStep::FreezePackage,
evidence_kind: None,
observation_class: G8lS566ObservationClass::HostObserved,
}; S566_RUNBOOK_STEP_COUNT];
let mut index = 0;
while index < S566_RUNBOOK_STEP_COUNT {
let spec = S566_RUNBOOK_TABLE[index];
declarations[index] = G8lS566StepDeclaration {
ordinal: index,
step: spec.step,
evidence_kind: Some(spec.evidence_kind),
observation_class: spec.observation_class,
};
index += 1;
}
declarations
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566RunbookContractRequest<'a> {
pub contract_anchor_id: u64,
pub predecessor_sequence: usize,
pub current_image: G8lS566PackageIdentity<'a>,
pub active_slot: G8lS566Slot,
pub steps: &'a [G8lS566StepDeclaration],
pub boundary: G8lS566DemoBoundary,
pub claims: G8lS566ClaimFlags,
pub executed_steps: usize,
pub evidence_records: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566RunbookContractReceipt {
pub sequence: usize,
pub predecessor_sequence: usize,
pub next_sequence: usize,
pub r1_stage: u8,
pub contract_anchor_id: u64,
pub step_count: usize,
pub host_observed_steps: usize,
pub operator_reported_steps: usize,
pub hash_evidence_steps: usize,
pub uart_marker_evidence_steps: usize,
pub operator_report_evidence_steps: usize,
pub current_image_bytes: u64,
pub current_image_digest_prefix: u64,
pub current_package_entries: usize,
pub active_slot: G8lS566Slot,
pub staging_slot: G8lS566Slot,
pub boundary: G8lS566DemoBoundary,
pub claims: G8lS566ClaimFlags,
pub contract_published: bool,
pub executed_steps: usize,
pub evidence_records: usize,
pub s540_physical_verdict_retained_red: bool,
pub s543_physical_verdict_retained_red: bool,
pub automatic_promotion: bool,
pub hardware_present: 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)]
pub struct G8lS566RunbookContractState {
receipt: Option<G8lS566RunbookContractReceipt>,
}
impl G8lS566RunbookContractState {
pub const fn new() -> Self {
Self { receipt: None }
}
pub const fn receipt(&self) -> Option<G8lS566RunbookContractReceipt> {
self.receipt
}
}
impl Default for G8lS566RunbookContractState {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS566RunbookContractOutcome {
ContractPublished(G8lS566RunbookContractReceipt),
ContractRetained(G8lS566RunbookContractReceipt),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS566RunbookContractError {
WrongPredecessor,
ZeroAnchor,
WrongStepCount,
StepOutOfOrder,
DuplicateStep,
EvidenceKindMissing,
EvidenceKindMismatch,
ObservationClassMismatch,
CurrentImageMismatch,
InvalidDigest,
ActiveSlotIsStagingSlot,
DemoBoundaryViolated,
FieldClaimForbidden,
ProductClaimForbidden,
ClaimWithoutEvidence,
ExecutionClaimed,
EvidenceRecordsClaimed,
LedgerComplete,
HashEvidenceMismatch,
MarkerMatrixMismatch,
DecisionMismatch,
CounterOverflow,
PublishedStateDrift,
}
impl G8lS566RunbookContractError {
pub const fn diagnostic_code(self) -> u64 {
match self {
Self::WrongPredecessor => 1,
Self::ZeroAnchor => 2,
Self::WrongStepCount => 3,
Self::StepOutOfOrder => 4,
Self::DuplicateStep => 5,
Self::EvidenceKindMissing => 6,
Self::EvidenceKindMismatch => 7,
Self::ObservationClassMismatch => 8,
Self::CurrentImageMismatch => 9,
Self::InvalidDigest => 10,
Self::ActiveSlotIsStagingSlot => 11,
Self::DemoBoundaryViolated => 12,
Self::FieldClaimForbidden => 13,
Self::ProductClaimForbidden => 14,
Self::ClaimWithoutEvidence => 15,
Self::ExecutionClaimed => 16,
Self::EvidenceRecordsClaimed => 17,
Self::LedgerComplete => 18,
Self::HashEvidenceMismatch => 19,
Self::MarkerMatrixMismatch => 20,
Self::DecisionMismatch => 21,
Self::CounterOverflow => 22,
Self::PublishedStateDrift => 23,
}
}
}
const fn hex_nibble(byte: u8) -> Option<u64> {
match byte {
b'0'..=b'9' => Some((byte - b'0') as u64),
b'a'..=b'f' => Some((byte - b'a' + 10) as u64),
_ => None,
}
}
/// Validates a 64-character lowercase hex digest and folds its first sixteen
/// characters into a `u64` fingerprint.
pub const fn s566_digest_prefix(digest: &str) -> Option<u64> {
let bytes = digest.as_bytes();
if bytes.len() != 64 {
return None;
}
let mut prefix = 0u64;
let mut index = 0;
while index < 64 {
let nibble = match hex_nibble(bytes[index]) {
Some(nibble) => nibble,
None => return None,
};
if index < 16 {
prefix = (prefix << 4) | nibble;
}
index += 1;
}
Some(prefix)
}
const fn str_eq(left: &str, right: &str) -> bool {
let left = left.as_bytes();
let right = right.as_bytes();
if left.len() != right.len() {
return false;
}
let mut index = 0;
while index < left.len() {
if left[index] != right[index] {
return false;
}
index += 1;
}
true
}
fn artifact_matches(
observed: G8lS566ArtifactIdentity<'_>,
expected: G8lS566ArtifactIdentity<'static>,
) -> Result<(), G8lS566RunbookContractError> {
let observed_prefix =
s566_digest_prefix(observed.sha256).ok_or(G8lS566RunbookContractError::InvalidDigest)?;
let expected_prefix =
s566_digest_prefix(expected.sha256).ok_or(G8lS566RunbookContractError::InvalidDigest)?;
if !str_eq(observed.name, expected.name)
|| observed.bytes != expected.bytes
|| observed_prefix != expected_prefix
|| !str_eq(observed.sha256, expected.sha256)
{
return Err(G8lS566RunbookContractError::CurrentImageMismatch);
}
Ok(())
}
pub fn check_s566_current_image(
observed: G8lS566PackageIdentity<'_>,
) -> Result<u64, G8lS566RunbookContractError> {
let fixture = s566_current_image_fixture();
artifact_matches(observed.image, fixture.image)?;
artifact_matches(observed.dtb, fixture.dtb)?;
artifact_matches(observed.config, fixture.config)?;
artifact_matches(observed.manifest, fixture.manifest)?;
if observed.manifest_lines != fixture.manifest_lines {
return Err(G8lS566RunbookContractError::CurrentImageMismatch);
}
s566_digest_prefix(observed.image.sha256).ok_or(G8lS566RunbookContractError::InvalidDigest)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct G8lS566StepTally {
pub host_observed: usize,
pub operator_reported: usize,
pub hash: usize,
pub uart_marker: usize,
pub operator_report: usize,
}
/// Checks the declared step list against the canonical table: exact count,
/// exact order, no duplicates, present and matching evidence kind, matching
/// observation class. Returns the per-class tallies.
pub fn check_s566_step_declarations(
steps: &[G8lS566StepDeclaration],
) -> Result<G8lS566StepTally, G8lS566RunbookContractError> {
if steps.len() != S566_RUNBOOK_STEP_COUNT {
return Err(G8lS566RunbookContractError::WrongStepCount);
}
let mut seen = [false; S566_RUNBOOK_STEP_COUNT];
let mut tally = G8lS566StepTally::default();
for (index, declaration) in steps.iter().enumerate() {
let spec = S566_RUNBOOK_TABLE[index];
if seen[declaration.step.ordinal()] {
return Err(G8lS566RunbookContractError::DuplicateStep);
}
seen[declaration.step.ordinal()] = true;
if declaration.ordinal != index || declaration.step != spec.step {
return Err(G8lS566RunbookContractError::StepOutOfOrder);
}
let kind = declaration
.evidence_kind
.ok_or(G8lS566RunbookContractError::EvidenceKindMissing)?;
if kind != spec.evidence_kind {
return Err(G8lS566RunbookContractError::EvidenceKindMismatch);
}
if declaration.observation_class != spec.observation_class {
return Err(G8lS566RunbookContractError::ObservationClassMismatch);
}
let overflow = G8lS566RunbookContractError::CounterOverflow;
match spec.observation_class {
G8lS566ObservationClass::HostObserved => {
tally.host_observed = tally.host_observed.checked_add(1).ok_or(overflow)?
}
G8lS566ObservationClass::OperatorReported => {
tally.operator_reported = tally.operator_reported.checked_add(1).ok_or(overflow)?
}
}
match spec.evidence_kind {
G8lS566EvidenceKind::Hash => tally.hash = tally.hash.checked_add(1).ok_or(overflow)?,
G8lS566EvidenceKind::UartMarker => {
tally.uart_marker = tally.uart_marker.checked_add(1).ok_or(overflow)?
}
G8lS566EvidenceKind::OperatorReport => {
tally.operator_report = tally.operator_report.checked_add(1).ok_or(overflow)?
}
}
}
Ok(tally)
}
pub const fn check_s566_demo_boundary(
boundary: G8lS566DemoBoundary,
) -> Result<(), G8lS566RunbookContractError> {
if boundary.field_claim {
return Err(G8lS566RunbookContractError::FieldClaimForbidden);
}
if boundary.product_claim {
return Err(G8lS566RunbookContractError::ProductClaimForbidden);
}
if !boundary.lab_demonstrator {
return Err(G8lS566RunbookContractError::DemoBoundaryViolated);
}
Ok(())
}
pub fn service_s566_model_runbook_contract(
state: &mut G8lS566RunbookContractState,
request: G8lS566RunbookContractRequest<'_>,
) -> Result<G8lS566RunbookContractOutcome, G8lS566RunbookContractError> {
if request.predecessor_sequence != S566_EXPECTED_PREDECESSOR {
return Err(G8lS566RunbookContractError::WrongPredecessor);
}
if request.contract_anchor_id == 0 {
return Err(G8lS566RunbookContractError::ZeroAnchor);
}
let tally = check_s566_step_declarations(request.steps)?;
let digest_prefix = check_s566_current_image(request.current_image)?;
if request.active_slot != S566_ACTIVE_SLOT {
return Err(G8lS566RunbookContractError::ActiveSlotIsStagingSlot);
}
check_s566_demo_boundary(request.boundary)?;
if request.executed_steps != S566_EXECUTED_STEPS {
return Err(G8lS566RunbookContractError::ExecutionClaimed);
}
if request.evidence_records != S566_EVIDENCE_RECORDS {
return Err(G8lS566RunbookContractError::EvidenceRecordsClaimed);
}
// The contract carries no evidence; the derivable claim set is empty.
let derived = G8lS566RunbookLedger::new().derive_claims();
if !request.claims.is_covered_by(derived) {
return Err(G8lS566RunbookContractError::ClaimWithoutEvidence);
}
let receipt = G8lS566RunbookContractReceipt {
sequence: S566_SEQUENCE,
predecessor_sequence: S566_EXPECTED_PREDECESSOR,
next_sequence: S566_NEXT_SEQUENCE,
r1_stage: S566_R1_STAGE,
contract_anchor_id: request.contract_anchor_id,
step_count: S566_RUNBOOK_STEP_COUNT,
host_observed_steps: tally.host_observed,
operator_reported_steps: tally.operator_reported,
hash_evidence_steps: tally.hash,
uart_marker_evidence_steps: tally.uart_marker,
operator_report_evidence_steps: tally.operator_report,
current_image_bytes: request.current_image.image.bytes,
current_image_digest_prefix: digest_prefix,
current_package_entries: S566_CURRENT_PACKAGE_ENTRIES,
active_slot: request.active_slot,
staging_slot: request.active_slot.other(),
boundary: request.boundary,
claims: request.claims,
contract_published: true,
executed_steps: S566_EXECUTED_STEPS,
evidence_records: S566_EVIDENCE_RECORDS,
s540_physical_verdict_retained_red: S566_S540_PHYSICAL_VERDICT_RETAINED_RED,
s543_physical_verdict_retained_red: S566_S543_PHYSICAL_VERDICT_RETAINED_RED,
automatic_promotion: S566_AUTOMATIC_PROMOTION,
hardware_present: S566_HARDWARE_PRESENT,
supported_profile_runtime_observations: S566_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS,
physical_observations: S566_PHYSICAL_OBSERVATIONS,
boot_to_ui_physically_observed: S566_BOOT_TO_UI_PHYSICALLY_OBSERVED,
r1_acceptance_complete: S566_R1_ACCEPTANCE_COMPLETE,
runbook_executed: RUNBOOK_EXECUTED_IN_S566,
};
if let Some(published) = state.receipt {
if published != receipt {
return Err(G8lS566RunbookContractError::PublishedStateDrift);
}
return Ok(G8lS566RunbookContractOutcome::ContractRetained(published));
}
state.receipt = Some(receipt);
Ok(G8lS566RunbookContractOutcome::ContractPublished(receipt))
}
// ---------------------------------------------------------------------------
// Runbook ledger: the host-side model of how a future demonstration would have
// to record evidence. It is driven only by the focused test with synthetic
// evidence; nothing here executes a step.
// ---------------------------------------------------------------------------
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS566Decision {
Reboot,
Commit,
Rollback,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566MarkerMatrix {
pub boot8h: usize,
pub boot_to_ui_ready: usize,
}
impl G8lS566MarkerMatrix {
pub const fn total(self) -> Option<usize> {
self.boot8h.checked_add(self.boot_to_ui_ready)
}
pub const fn is_exact(self) -> bool {
self.boot8h >= S566_BOOT_MARKER_MINIMUM
&& self.boot_to_ui_ready == S566_BOOT_TO_UI_MARKER_EXACT
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS566EvidenceRecord<'a> {
Hash(G8lS566ArtifactIdentity<'a>),
UartMarker(G8lS566MarkerMatrix),
OperatorReport {
report_id: u64,
decision: G8lS566Decision,
},
}
impl G8lS566EvidenceRecord<'_> {
pub const fn kind(self) -> G8lS566EvidenceKind {
match self {
Self::Hash(..) => G8lS566EvidenceKind::Hash,
Self::UartMarker(..) => G8lS566EvidenceKind::UartMarker,
Self::OperatorReport { .. } => G8lS566EvidenceKind::OperatorReport,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS566RunbookLedger {
recorded: [bool; S566_RUNBOOK_STEP_COUNT],
next: Option<G8lS566RunbookStep>,
evidence_records: usize,
terminal_decision: Option<G8lS566Decision>,
}
impl G8lS566RunbookLedger {
pub const fn new() -> Self {
Self {
recorded: [false; S566_RUNBOOK_STEP_COUNT],
next: Some(G8lS566RunbookStep::FreezePackage),
evidence_records: 0,
terminal_decision: None,
}
}
pub const fn next_step(&self) -> Option<G8lS566RunbookStep> {
self.next
}
pub const fn evidence_records(&self) -> usize {
self.evidence_records
}
pub const fn terminal_decision(&self) -> Option<G8lS566Decision> {
self.terminal_decision
}
pub const fn is_complete(&self) -> bool {
self.next.is_none()
}
/// Claims derivable from recorded evidence. Field and product claims are
/// never derivable; the boundary is structural.
pub const fn derive_claims(&self) -> G8lS566ClaimFlags {
let package_identity_verified = self.recorded[0] && self.recorded[1] && self.recorded[2];
let boot_markers_confirmed =
package_identity_verified && self.recorded[3] && self.recorded[4];
let (update_demonstrated, rollback_demonstrated) = match self.terminal_decision {
Some(G8lS566Decision::Commit) => (boot_markers_confirmed, false),
Some(G8lS566Decision::Rollback) => (false, boot_markers_confirmed),
_ => (false, false),
};
G8lS566ClaimFlags {
update_demonstrated,
rollback_demonstrated,
boot_markers_confirmed,
package_identity_verified,
}
}
/// Records one step. Fails closed and leaves the ledger unchanged on any
/// ordering, class, kind or payload violation.
pub fn record(
&mut self,
step: G8lS566RunbookStep,
reporter: G8lS566ObservationClass,
evidence: G8lS566EvidenceRecord<'_>,
) -> Result<G8lS566ClaimFlags, G8lS566RunbookContractError> {
let expected = self
.next
.ok_or(G8lS566RunbookContractError::LedgerComplete)?;
if self.recorded[step.ordinal()] {
return Err(G8lS566RunbookContractError::DuplicateStep);
}
if step != expected {
return Err(G8lS566RunbookContractError::StepOutOfOrder);
}
let spec = s566_runbook_spec(step);
if reporter != spec.observation_class {
return Err(G8lS566RunbookContractError::ObservationClassMismatch);
}
if evidence.kind() != spec.evidence_kind {
return Err(G8lS566RunbookContractError::EvidenceKindMismatch);
}
let fixture = s566_current_image_fixture();
let mut decision = None;
match (step, evidence) {
(G8lS566RunbookStep::FreezePackage, G8lS566EvidenceRecord::Hash(identity))
| (G8lS566RunbookStep::StageToInactiveSlot, G8lS566EvidenceRecord::Hash(identity)) => {
artifact_matches(identity, fixture.image)
.map_err(|_| G8lS566RunbookContractError::HashEvidenceMismatch)?;
}
(G8lS566RunbookStep::VerifyManifest, G8lS566EvidenceRecord::Hash(identity)) => {
artifact_matches(identity, fixture.manifest)
.map_err(|_| G8lS566RunbookContractError::HashEvidenceMismatch)?;
}
(
G8lS566RunbookStep::Reboot,
G8lS566EvidenceRecord::OperatorReport {
report_id,
decision: reported,
},
) => {
if report_id == 0 || reported != G8lS566Decision::Reboot {
return Err(G8lS566RunbookContractError::DecisionMismatch);
}
}
(G8lS566RunbookStep::ConfirmBootMarkers, G8lS566EvidenceRecord::UartMarker(matrix)) => {
matrix
.total()
.ok_or(G8lS566RunbookContractError::CounterOverflow)?;
if !matrix.is_exact() {
return Err(G8lS566RunbookContractError::MarkerMatrixMismatch);
}
}
(
G8lS566RunbookStep::CommitOrRollback,
G8lS566EvidenceRecord::OperatorReport {
report_id,
decision: reported,
},
) => {
if report_id == 0 || reported == G8lS566Decision::Reboot {
return Err(G8lS566RunbookContractError::DecisionMismatch);
}
decision = Some(reported);
}
_ => return Err(G8lS566RunbookContractError::EvidenceKindMismatch),
}
let evidence_records = self
.evidence_records
.checked_add(1)
.ok_or(G8lS566RunbookContractError::CounterOverflow)?;
self.recorded[step.ordinal()] = true;
self.next = step.next();
self.evidence_records = evidence_records;
if decision.is_some() {
self.terminal_decision = decision;
}
Ok(self.derive_claims())
}
}
impl Default for G8lS566RunbookLedger {
fn default() -> Self {
Self::new()
}
}
snippet sha256: f00d03362818…file sha256: f00d03362818…
02 · Doğrulayan test kodu
Operations komutuna bağlı focused test
tam dosyaL1–L860
simulation/tests/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s566_r1_lab_update_demonstration_runbook_contract.rs::S566 r1 lab update demonstration runbook contract focused tests
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s545_r1_reachable_producer_candidate_freeze_prearm_contract::{
S545_CONFIG_BYTES, S545_CONFIG_NAME, S545_CONFIG_SHA256, S545_DTB_BYTES, S545_DTB_NAME,
S545_DTB_SHA256, S545_IMAGE_BYTES, S545_IMAGE_NAME, S545_IMAGE_SHA256, S545_MANIFEST_BYTES,
S545_MANIFEST_LINES, S545_MANIFEST_NAME, S545_MANIFEST_SHA256, S545_PACKAGE_ENTRIES,
};
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s566_r1_lab_update_demonstration_runbook_contract::*;
use std::collections::BTreeSet;
const SOURCE: &str = include_str!(
"../../kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s566_r1_lab_update_demonstration_runbook_contract.rs"
);
const MAIN: &str = include_str!("../../kernel/src/main.rs");
const SIMULATION_LIB: &str = include_str!("../src/lib.rs");
const MODULE: &str = "g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s566_r1_lab_update_demonstration_runbook_contract";
const ANCHOR: u64 = 0x5660_0000_0000_0001;
fn request<'a>(
anchor: u64,
steps: &'a [G8lS566StepDeclaration],
) -> G8lS566RunbookContractRequest<'a> {
G8lS566RunbookContractRequest {
contract_anchor_id: anchor,
predecessor_sequence: S566_EXPECTED_PREDECESSOR,
current_image: s566_current_image_fixture(),
active_slot: S566_ACTIVE_SLOT,
steps,
boundary: S566_DEMO_BOUNDARY,
claims: G8lS566ClaimFlags::NONE,
executed_steps: 0,
evidence_records: 0,
}
}
fn publish(
state: &mut G8lS566RunbookContractState,
request: G8lS566RunbookContractRequest<'_>,
) -> Result<G8lS566RunbookContractOutcome, G8lS566RunbookContractError> {
service_s566_model_runbook_contract(state, request)
}
fn image_hash() -> G8lS566EvidenceRecord<'static> {
G8lS566EvidenceRecord::Hash(s566_current_image_fixture().image)
}
fn manifest_hash() -> G8lS566EvidenceRecord<'static> {
G8lS566EvidenceRecord::Hash(s566_current_image_fixture().manifest)
}
fn exact_markers() -> G8lS566EvidenceRecord<'static> {
G8lS566EvidenceRecord::UartMarker(G8lS566MarkerMatrix {
boot8h: 1,
boot_to_ui_ready: 1,
})
}
fn report(decision: G8lS566Decision) -> G8lS566EvidenceRecord<'static> {
G8lS566EvidenceRecord::OperatorReport {
report_id: 7,
decision,
}
}
fn drive_ledger_to_decision(decision: G8lS566Decision) -> G8lS566RunbookLedger {
use G8lS566ObservationClass::{HostObserved, OperatorReported};
use G8lS566RunbookStep::*;
let mut ledger = G8lS566RunbookLedger::new();
ledger.record(FreezePackage, HostObserved, image_hash()).unwrap();
ledger.record(VerifyManifest, HostObserved, manifest_hash()).unwrap();
ledger.record(StageToInactiveSlot, HostObserved, image_hash()).unwrap();
ledger
.record(Reboot, OperatorReported, report(G8lS566Decision::Reboot))
.unwrap();
ledger
.record(ConfirmBootMarkers, HostObserved, exact_markers())
.unwrap();
ledger
.record(CommitOrRollback, OperatorReported, report(decision))
.unwrap();
ledger
}
#[test]
fn sequence_scope_and_nonpromotion_are_exact() {
assert_eq!(S566_SEQUENCE, 566);
assert_eq!(S566_EXPECTED_PREDECESSOR, 565);
assert_eq!(S566_NEXT_SEQUENCE, 567);
assert_eq!(S566_R1_STAGE, 4);
assert_eq!(S566_R1_RANGE_FIRST, 536);
assert_eq!(S566_R1_RANGE_LAST, 568);
assert_eq!(S566_SUPPORTED_PROFILE_RUNTIME_OBSERVATIONS, 0);
assert_eq!(S566_PHYSICAL_OBSERVATIONS, 0);
assert_eq!(S566_PHYSICAL_OR_DEVICE_OPERATIONS, 0);
assert_eq!(S566_SD_WRITES, 0);
assert_eq!(S566_UART_OPENS, 0);
assert_eq!(S566_POWER_TRANSITIONS, 0);
assert_eq!(S566_NEW_IMMUTABLE_RAW_CAPTURES, 0);
assert!(S566_S540_PHYSICAL_VERDICT_RETAINED_RED);
assert!(S566_S543_PHYSICAL_VERDICT_RETAINED_RED);
assert!(!S566_AUTOMATIC_PROMOTION);
assert!(!S566_BOOT_TO_UI_PHYSICALLY_OBSERVED);
assert!(!S566_HARDWARE_PRESENT);
assert!(!S566_R1_ACCEPTANCE_COMPLETE);
assert!(!RUNBOOK_EXECUTED_IN_S566);
assert_eq!(S566_EXECUTED_STEPS, 0);
assert_eq!(S566_EVIDENCE_RECORDS, 0);
assert_eq!(S566_RUNBOOK_STEP_COUNT, 6);
assert_eq!(
S566_HOST_OBSERVED_STEPS + S566_OPERATOR_REPORTED_STEPS,
S566_RUNBOOK_STEP_COUNT
);
assert_eq!(
S566_HASH_EVIDENCE_STEPS
+ S566_UART_MARKER_EVIDENCE_STEPS
+ S566_OPERATOR_REPORT_EVIDENCE_STEPS,
S566_RUNBOOK_STEP_COUNT
);
assert_eq!(
S566_DEMO_BOUNDARY_STATEMENT,
"LAB_DEMONSTRATOR_ONLY; NO_FIELD_CLAIM; NO_PRODUCT_CLAIM"
);
assert_eq!(S566_ACTIVE_SLOT, G8lS566Slot::A);
assert_eq!(S566_INACTIVE_SLOT, G8lS566Slot::B);
assert_eq!(S566_ACTIVE_SLOT.other(), S566_INACTIVE_SLOT);
}
#[test]
fn module_is_registered_in_kernel_and_simulation() {
let kernel_line = format!("mod {MODULE};");
let simulation_line = format!("pub mod {MODULE};");
assert!(MAIN.lines().any(|line| line == kernel_line));
assert!(SIMULATION_LIB.lines().any(|line| line == simulation_line));
assert!(SIMULATION_LIB.contains(&format!("#[path = \"../../kernel/src/{MODULE}.rs\"]")));
}
#[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/",
"diskutil",
"TIOCEXCL",
] {
assert!(!SOURCE.contains(forbidden), "forbidden token: {forbidden}");
}
assert!(SOURCE.contains("performs no device operation"));
assert!(SOURCE.contains("it is never\n//! executed"));
assert!(SOURCE.contains("RUNBOOK_EXECUTED_IN_S566: bool = false"));
assert!(SOURCE.contains("S566_HARDWARE_PRESENT: bool = false"));
assert!(SOURCE.contains("S566_PHYSICAL_OBSERVATIONS: usize = 0"));
assert!(SOURCE.contains("S566_R1_ACCEPTANCE_COMPLETE: bool = false"));
}
#[test]
fn diagnostic_codes_are_nonzero_and_unique() {
use G8lS566RunbookContractError::*;
let errors = [
WrongPredecessor,
ZeroAnchor,
WrongStepCount,
StepOutOfOrder,
DuplicateStep,
EvidenceKindMissing,
EvidenceKindMismatch,
ObservationClassMismatch,
CurrentImageMismatch,
InvalidDigest,
ActiveSlotIsStagingSlot,
DemoBoundaryViolated,
FieldClaimForbidden,
ProductClaimForbidden,
ClaimWithoutEvidence,
ExecutionClaimed,
EvidenceRecordsClaimed,
LedgerComplete,
HashEvidenceMismatch,
MarkerMatrixMismatch,
DecisionMismatch,
CounterOverflow,
PublishedStateDrift,
];
let codes: BTreeSet<u64> = errors
.iter()
.map(|error| error.diagnostic_code())
.collect();
assert_eq!(codes.len(), errors.len());
assert_eq!(codes.len(), 23);
assert!(!codes.contains(&0));
}
#[test]
fn current_image_fixture_matches_s545_package_identities() {
let fixture = s566_current_image_fixture();
assert_eq!(fixture.image.name, S545_IMAGE_NAME);
assert_eq!(fixture.image.bytes, S545_IMAGE_BYTES);
assert_eq!(fixture.image.sha256, S545_IMAGE_SHA256);
assert_eq!(fixture.dtb.name, S545_DTB_NAME);
assert_eq!(fixture.dtb.bytes, S545_DTB_BYTES);
assert_eq!(fixture.dtb.sha256, S545_DTB_SHA256);
assert_eq!(fixture.config.name, S545_CONFIG_NAME);
assert_eq!(fixture.config.bytes, S545_CONFIG_BYTES);
assert_eq!(fixture.config.sha256, S545_CONFIG_SHA256);
assert_eq!(fixture.manifest.name, S545_MANIFEST_NAME);
assert_eq!(fixture.manifest.bytes, S545_MANIFEST_BYTES);
assert_eq!(fixture.manifest.sha256, S545_MANIFEST_SHA256);
assert_eq!(fixture.manifest_lines, S545_MANIFEST_LINES);
assert_eq!(S566_CURRENT_PACKAGE_ENTRIES, S545_PACKAGE_ENTRIES);
assert_eq!(
check_s566_current_image(fixture).unwrap(),
0xed19_01a9_91e2_f9e9
);
}
#[test]
fn runbook_table_is_ordered_with_required_evidence_and_observation_classes() {
use G8lS566EvidenceKind::*;
use G8lS566ObservationClass::*;
use G8lS566RunbookStep::*;
let expected = [
(FreezePackage, Hash, HostObserved),
(VerifyManifest, Hash, HostObserved),
(StageToInactiveSlot, Hash, HostObserved),
(Reboot, OperatorReport, OperatorReported),
(ConfirmBootMarkers, UartMarker, HostObserved),
(CommitOrRollback, OperatorReport, OperatorReported),
];
for (index, (step, kind, class)) in expected.into_iter().enumerate() {
let spec = S566_RUNBOOK_TABLE[index];
assert_eq!(spec.step, step);
assert_eq!(spec.evidence_kind, kind);
assert_eq!(spec.observation_class, class);
assert_eq!(step.ordinal(), index);
assert_eq!(G8lS566RunbookStep::from_ordinal(index), Some(step));
assert_eq!(s566_runbook_spec(step), spec);
}
assert_eq!(G8lS566RunbookStep::from_ordinal(6), None);
assert_eq!(CommitOrRollback.next(), None);
assert_eq!(FreezePackage.next(), Some(VerifyManifest));
let tally = check_s566_step_declarations(&s566_canonical_declarations()).unwrap();
assert_eq!(tally.host_observed, S566_HOST_OBSERVED_STEPS);
assert_eq!(tally.operator_reported, S566_OPERATOR_REPORTED_STEPS);
assert_eq!(tally.hash, S566_HASH_EVIDENCE_STEPS);
assert_eq!(tally.uart_marker, S566_UART_MARKER_EVIDENCE_STEPS);
assert_eq!(tally.operator_report, S566_OPERATOR_REPORT_EVIDENCE_STEPS);
}
#[test]
fn contract_publishes_with_canonical_declarations() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
assert_eq!(state.receipt(), None);
let G8lS566RunbookContractOutcome::ContractPublished(receipt) =
publish(&mut state, request(ANCHOR, &steps)).unwrap()
else {
panic!("first publication must publish")
};
assert_eq!(receipt.sequence, 566);
assert_eq!(receipt.predecessor_sequence, 565);
assert_eq!(receipt.next_sequence, 567);
assert_eq!(receipt.r1_stage, 4);
assert_eq!(receipt.contract_anchor_id, ANCHOR);
assert_eq!(receipt.step_count, 6);
assert_eq!(receipt.host_observed_steps, 4);
assert_eq!(receipt.operator_reported_steps, 2);
assert_eq!(receipt.hash_evidence_steps, 3);
assert_eq!(receipt.uart_marker_evidence_steps, 1);
assert_eq!(receipt.operator_report_evidence_steps, 2);
assert_eq!(receipt.current_image_bytes, 945_760);
assert_eq!(receipt.current_image_digest_prefix, 0xed19_01a9_91e2_f9e9);
assert_eq!(receipt.current_package_entries, 4);
assert_eq!(receipt.active_slot, G8lS566Slot::A);
assert_eq!(receipt.staging_slot, G8lS566Slot::B);
assert_eq!(receipt.boundary, S566_DEMO_BOUNDARY);
assert_eq!(receipt.claims, G8lS566ClaimFlags::NONE);
assert!(!receipt.claims.any());
assert!(receipt.contract_published);
assert_eq!(receipt.executed_steps, 0);
assert_eq!(receipt.evidence_records, 0);
assert!(receipt.s540_physical_verdict_retained_red);
assert!(receipt.s543_physical_verdict_retained_red);
assert!(!receipt.automatic_promotion);
assert!(!receipt.hardware_present);
assert_eq!(receipt.supported_profile_runtime_observations, 0);
assert_eq!(receipt.physical_observations, 0);
assert!(!receipt.boot_to_ui_physically_observed);
assert!(!receipt.r1_acceptance_complete);
assert!(!receipt.runbook_executed);
assert_eq!(state.receipt(), Some(receipt));
}
#[test]
fn exact_replay_retains_the_same_receipt() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::default();
let first = publish(&mut state, request(ANCHOR, &steps)).unwrap();
let G8lS566RunbookContractOutcome::ContractPublished(published) = first else {
panic!("first publication must publish")
};
for _ in 0..3 {
assert_eq!(
publish(&mut state, request(ANCHOR, &steps)),
Ok(G8lS566RunbookContractOutcome::ContractRetained(published))
);
}
assert_eq!(state.receipt(), Some(published));
}
#[test]
fn divergent_input_after_publication_fails_closed() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
let G8lS566RunbookContractOutcome::ContractPublished(published) =
publish(&mut state, request(ANCHOR, &steps)).unwrap()
else {
panic!("first publication must publish")
};
assert_eq!(
publish(&mut state, request(ANCHOR + 1, &steps)),
Err(G8lS566RunbookContractError::PublishedStateDrift)
);
assert_eq!(state.receipt(), Some(published));
let mut reordered = steps;
reordered.swap(4, 5);
assert_eq!(
publish(&mut state, request(ANCHOR, &reordered)),
Err(G8lS566RunbookContractError::StepOutOfOrder)
);
assert_eq!(state.receipt(), Some(published));
}
#[test]
fn reordered_duplicated_or_truncated_steps_fail_closed() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
for (left, right) in [(0, 1), (2, 3), (3, 4), (0, 5)] {
let mut reordered = steps;
reordered.swap(left, right);
assert_eq!(
publish(&mut state, request(ANCHOR, &reordered)),
Err(G8lS566RunbookContractError::StepOutOfOrder),
"swap {left}<->{right}"
);
}
let mut wrong_ordinal = steps;
wrong_ordinal[2].ordinal = 3;
assert_eq!(
publish(&mut state, request(ANCHOR, &wrong_ordinal)),
Err(G8lS566RunbookContractError::StepOutOfOrder)
);
let mut duplicated = steps;
duplicated[5] = duplicated[4];
duplicated[5].ordinal = 5;
assert_eq!(
publish(&mut state, request(ANCHOR, &duplicated)),
Err(G8lS566RunbookContractError::DuplicateStep)
);
assert_eq!(
publish(&mut state, request(ANCHOR, &steps[..5])),
Err(G8lS566RunbookContractError::WrongStepCount)
);
let mut seven = steps.to_vec();
seven.push(steps[5]);
assert_eq!(
publish(&mut state, request(ANCHOR, &seven)),
Err(G8lS566RunbookContractError::WrongStepCount)
);
assert_eq!(
publish(&mut state, request(ANCHOR, &[])),
Err(G8lS566RunbookContractError::WrongStepCount)
);
assert_eq!(state.receipt(), None);
}
#[test]
fn missing_or_mismatched_evidence_kind_or_class_fails_closed() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
for index in 0..S566_RUNBOOK_STEP_COUNT {
let mut missing = steps;
missing[index].evidence_kind = None;
assert_eq!(
publish(&mut state, request(ANCHOR, &missing)),
Err(G8lS566RunbookContractError::EvidenceKindMissing),
"missing kind at {index}"
);
}
let mut hash_for_reboot = steps;
hash_for_reboot[3].evidence_kind = Some(G8lS566EvidenceKind::Hash);
assert_eq!(
publish(&mut state, request(ANCHOR, &hash_for_reboot)),
Err(G8lS566RunbookContractError::EvidenceKindMismatch)
);
let mut report_for_markers = steps;
report_for_markers[4].evidence_kind = Some(G8lS566EvidenceKind::OperatorReport);
assert_eq!(
publish(&mut state, request(ANCHOR, &report_for_markers)),
Err(G8lS566RunbookContractError::EvidenceKindMismatch)
);
let mut operator_freeze = steps;
operator_freeze[0].observation_class = G8lS566ObservationClass::OperatorReported;
assert_eq!(
publish(&mut state, request(ANCHOR, &operator_freeze)),
Err(G8lS566RunbookContractError::ObservationClassMismatch)
);
let mut host_reboot = steps;
host_reboot[3].observation_class = G8lS566ObservationClass::HostObserved;
assert_eq!(
publish(&mut state, request(ANCHOR, &host_reboot)),
Err(G8lS566RunbookContractError::ObservationClassMismatch)
);
assert_eq!(state.receipt(), None);
}
#[test]
fn claim_flags_without_evidence_fail_closed() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
let claims = [
G8lS566ClaimFlags {
update_demonstrated: true,
..G8lS566ClaimFlags::NONE
},
G8lS566ClaimFlags {
rollback_demonstrated: true,
..G8lS566ClaimFlags::NONE
},
G8lS566ClaimFlags {
boot_markers_confirmed: true,
..G8lS566ClaimFlags::NONE
},
G8lS566ClaimFlags {
package_identity_verified: true,
..G8lS566ClaimFlags::NONE
},
];
for claim in claims {
assert!(claim.any());
let mut claimed = request(ANCHOR, &steps);
claimed.claims = claim;
assert_eq!(
publish(&mut state, claimed),
Err(G8lS566RunbookContractError::ClaimWithoutEvidence),
"{claim:?}"
);
}
assert_eq!(G8lS566ClaimFlags::default(), G8lS566ClaimFlags::NONE);
assert!(G8lS566ClaimFlags::NONE.is_covered_by(G8lS566ClaimFlags::NONE));
assert_eq!(state.receipt(), None);
}
#[test]
fn demo_boundary_field_or_product_claim_fails_closed() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
let cases = [
(
G8lS566DemoBoundary {
lab_demonstrator: true,
field_claim: true,
product_claim: false,
},
G8lS566RunbookContractError::FieldClaimForbidden,
),
(
G8lS566DemoBoundary {
lab_demonstrator: true,
field_claim: false,
product_claim: true,
},
G8lS566RunbookContractError::ProductClaimForbidden,
),
(
G8lS566DemoBoundary {
lab_demonstrator: false,
field_claim: true,
product_claim: true,
},
G8lS566RunbookContractError::FieldClaimForbidden,
),
(
G8lS566DemoBoundary {
lab_demonstrator: false,
field_claim: false,
product_claim: false,
},
G8lS566RunbookContractError::DemoBoundaryViolated,
),
];
for (boundary, error) in cases {
assert_eq!(check_s566_demo_boundary(boundary), Err(error));
let mut violated = request(ANCHOR, &steps);
violated.boundary = boundary;
assert_eq!(publish(&mut state, violated), Err(error));
}
assert_eq!(check_s566_demo_boundary(S566_DEMO_BOUNDARY), Ok(()));
assert_eq!(state.receipt(), None);
}
#[test]
fn execution_or_evidence_record_claims_fail_closed() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
for executed in [1, 6, usize::MAX] {
let mut executed_request = request(ANCHOR, &steps);
executed_request.executed_steps = executed;
assert_eq!(
publish(&mut state, executed_request),
Err(G8lS566RunbookContractError::ExecutionClaimed)
);
}
for records in [1, 6, usize::MAX] {
let mut recorded = request(ANCHOR, &steps);
recorded.evidence_records = records;
assert_eq!(
publish(&mut state, recorded),
Err(G8lS566RunbookContractError::EvidenceRecordsClaimed)
);
}
let mut wrong_slot = request(ANCHOR, &steps);
wrong_slot.active_slot = S566_INACTIVE_SLOT;
assert_eq!(
publish(&mut state, wrong_slot),
Err(G8lS566RunbookContractError::ActiveSlotIsStagingSlot)
);
assert_eq!(state.receipt(), None);
}
#[test]
fn wrong_predecessor_and_zero_anchor_fail_closed() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
for predecessor in [0, 544, 564, 566, 567, usize::MAX] {
let mut wrong = request(ANCHOR, &steps);
wrong.predecessor_sequence = predecessor;
assert_eq!(
publish(&mut state, wrong),
Err(G8lS566RunbookContractError::WrongPredecessor)
);
}
assert_eq!(
publish(&mut state, request(0, &steps)),
Err(G8lS566RunbookContractError::ZeroAnchor)
);
assert_eq!(state.receipt(), None);
}
#[test]
fn current_image_drift_or_malformed_digest_fails_closed() {
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
let fixture = s566_current_image_fixture();
let mut wrong_bytes = fixture;
wrong_bytes.image.bytes = 941_392;
let mut wrong_name = fixture;
wrong_name.dtb.name = "bcm2711-rpi-4-b.dtb";
let mut wrong_lines = fixture;
wrong_lines.manifest_lines = 4;
let mut swapped_digest = fixture;
swapped_digest.config.sha256 = S566_CURRENT_MANIFEST_SHA256;
for drifted in [wrong_bytes, wrong_name, wrong_lines, swapped_digest] {
assert_eq!(
check_s566_current_image(drifted),
Err(G8lS566RunbookContractError::CurrentImageMismatch)
);
let mut drifted_request = request(ANCHOR, &steps);
drifted_request.current_image = drifted;
assert_eq!(
publish(&mut state, drifted_request),
Err(G8lS566RunbookContractError::CurrentImageMismatch)
);
}
let uppercase = "ED1901A991E2F9E9AE3C16F254147A2B0180686A8D70CA5D7353374FEE08D467";
let short = "ed1901a991e2f9e9";
let long = "ed1901a991e2f9e9ae3c16f254147a2b0180686a8d70ca5d7353374fee08d46700";
let non_hex = "ed1901a991e2f9e9ae3c16f254147a2b0180686a8d70ca5d7353374fee08d46g";
for digest in [uppercase, short, long, non_hex, ""] {
assert_eq!(s566_digest_prefix(digest), None, "{digest:?}");
let mut malformed = fixture;
malformed.image.sha256 = digest;
assert_eq!(
check_s566_current_image(malformed),
Err(G8lS566RunbookContractError::InvalidDigest)
);
let mut malformed_request = request(ANCHOR, &steps);
malformed_request.current_image = malformed;
assert_eq!(
publish(&mut state, malformed_request),
Err(G8lS566RunbookContractError::InvalidDigest)
);
}
assert_eq!(
s566_digest_prefix(S566_CURRENT_MANIFEST_SHA256),
Some(0x4acc_d201_849f_6810)
);
assert_eq!(
s566_digest_prefix(&"0".repeat(64)),
Some(0)
);
assert_eq!(
s566_digest_prefix(&"f".repeat(64)),
Some(u64::MAX)
);
assert_eq!(state.receipt(), None);
}
#[test]
fn ledger_accepts_exact_ordered_evidence_and_derives_commit_claims() {
use G8lS566ObservationClass::{HostObserved, OperatorReported};
use G8lS566RunbookStep::*;
let mut ledger = G8lS566RunbookLedger::default();
assert_eq!(ledger.next_step(), Some(FreezePackage));
assert_eq!(ledger.derive_claims(), G8lS566ClaimFlags::NONE);
assert!(!ledger.is_complete());
let after_freeze = ledger.record(FreezePackage, HostObserved, image_hash()).unwrap();
assert_eq!(after_freeze, G8lS566ClaimFlags::NONE);
let after_manifest = ledger
.record(VerifyManifest, HostObserved, manifest_hash())
.unwrap();
assert_eq!(after_manifest, G8lS566ClaimFlags::NONE);
let after_stage = ledger
.record(StageToInactiveSlot, HostObserved, image_hash())
.unwrap();
assert!(after_stage.package_identity_verified);
assert!(!after_stage.boot_markers_confirmed);
let after_reboot = ledger
.record(Reboot, OperatorReported, report(G8lS566Decision::Reboot))
.unwrap();
assert!(!after_reboot.boot_markers_confirmed);
let after_markers = ledger
.record(ConfirmBootMarkers, HostObserved, exact_markers())
.unwrap();
assert!(after_markers.boot_markers_confirmed);
assert!(!after_markers.update_demonstrated);
assert_eq!(ledger.next_step(), Some(CommitOrRollback));
let after_commit = ledger
.record(
CommitOrRollback,
OperatorReported,
report(G8lS566Decision::Commit),
)
.unwrap();
assert_eq!(
after_commit,
G8lS566ClaimFlags {
update_demonstrated: true,
rollback_demonstrated: false,
boot_markers_confirmed: true,
package_identity_verified: true,
}
);
assert!(ledger.is_complete());
assert_eq!(ledger.next_step(), None);
assert_eq!(ledger.evidence_records(), 6);
assert_eq!(ledger.terminal_decision(), Some(G8lS566Decision::Commit));
assert_eq!(
ledger.record(FreezePackage, HostObserved, image_hash()),
Err(G8lS566RunbookContractError::LedgerComplete)
);
}
#[test]
fn ledger_rollback_path_derives_rollback_claim_only() {
let ledger = drive_ledger_to_decision(G8lS566Decision::Rollback);
assert_eq!(ledger.terminal_decision(), Some(G8lS566Decision::Rollback));
let claims = ledger.derive_claims();
assert!(claims.rollback_demonstrated);
assert!(!claims.update_demonstrated);
assert!(claims.boot_markers_confirmed);
assert!(claims.package_identity_verified);
let commit = drive_ledger_to_decision(G8lS566Decision::Commit).derive_claims();
assert!(commit.update_demonstrated && !commit.rollback_demonstrated);
// Even a fully driven ledger cannot make the demo boundary claim anything
// beyond a lab demonstrator: the claim set has no field/product member and
// the contract still refuses these flags because it carries no evidence.
let steps = s566_canonical_declarations();
let mut state = G8lS566RunbookContractState::new();
let mut claimed = request(ANCHOR, &steps);
claimed.claims = claims;
assert_eq!(
publish(&mut state, claimed),
Err(G8lS566RunbookContractError::ClaimWithoutEvidence)
);
}
#[test]
fn ledger_rejects_out_of_order_wrong_class_wrong_kind_and_bad_payload() {
use G8lS566ObservationClass::{HostObserved, OperatorReported};
use G8lS566RunbookStep::*;
let mut ledger = G8lS566RunbookLedger::new();
let pristine = ledger;
assert_eq!(
ledger.record(VerifyManifest, HostObserved, manifest_hash()),
Err(G8lS566RunbookContractError::StepOutOfOrder)
);
assert_eq!(
ledger.record(FreezePackage, OperatorReported, image_hash()),
Err(G8lS566RunbookContractError::ObservationClassMismatch)
);
assert_eq!(
ledger.record(FreezePackage, HostObserved, exact_markers()),
Err(G8lS566RunbookContractError::EvidenceKindMismatch)
);
assert_eq!(
ledger.record(FreezePackage, HostObserved, manifest_hash()),
Err(G8lS566RunbookContractError::HashEvidenceMismatch)
);
let mut malformed = s566_current_image_fixture().image;
malformed.sha256 = "not-a-digest";
assert_eq!(
ledger.record(FreezePackage, HostObserved, G8lS566EvidenceRecord::Hash(malformed)),
Err(G8lS566RunbookContractError::HashEvidenceMismatch)
);
assert_eq!(ledger, pristine);
ledger.record(FreezePackage, HostObserved, image_hash()).unwrap();
assert_eq!(
ledger.record(FreezePackage, HostObserved, image_hash()),
Err(G8lS566RunbookContractError::DuplicateStep)
);
assert_eq!(
ledger.record(VerifyManifest, HostObserved, image_hash()),
Err(G8lS566RunbookContractError::HashEvidenceMismatch)
);
ledger.record(VerifyManifest, HostObserved, manifest_hash()).unwrap();
ledger.record(StageToInactiveSlot, HostObserved, image_hash()).unwrap();
assert_eq!(
ledger.record(Reboot, OperatorReported, report(G8lS566Decision::Commit)),
Err(G8lS566RunbookContractError::DecisionMismatch)
);
assert_eq!(
ledger.record(
Reboot,
OperatorReported,
G8lS566EvidenceRecord::OperatorReport {
report_id: 0,
decision: G8lS566Decision::Reboot,
},
),
Err(G8lS566RunbookContractError::DecisionMismatch)
);
ledger
.record(Reboot, OperatorReported, report(G8lS566Decision::Reboot))
.unwrap();
for (boot8h, boot_to_ui_ready) in [(0, 1), (1, 0), (1, 2), (3, 0), (0, 0)] {
let matrix = G8lS566MarkerMatrix {
boot8h,
boot_to_ui_ready,
};
assert!(!matrix.is_exact());
assert_eq!(
ledger.record(
ConfirmBootMarkers,
HostObserved,
G8lS566EvidenceRecord::UartMarker(matrix),
),
Err(G8lS566RunbookContractError::MarkerMatrixMismatch),
"{boot8h}/{boot_to_ui_ready}"
);
}
let before_markers = ledger;
assert_eq!(ledger, before_markers);
ledger
.record(ConfirmBootMarkers, HostObserved, exact_markers())
.unwrap();
assert_eq!(
ledger.record(
CommitOrRollback,
OperatorReported,
report(G8lS566Decision::Reboot),
),
Err(G8lS566RunbookContractError::DecisionMismatch)
);
assert_eq!(
ledger.record(CommitOrRollback, HostObserved, report(G8lS566Decision::Commit)),
Err(G8lS566RunbookContractError::ObservationClassMismatch)
);
assert_eq!(ledger.terminal_decision(), None);
assert_eq!(ledger.evidence_records(), 5);
}
#[test]
fn marker_matrix_total_uses_checked_arithmetic() {
use G8lS566ObservationClass::{HostObserved, OperatorReported};
use G8lS566RunbookStep::*;
let overflowing = G8lS566MarkerMatrix {
boot8h: usize::MAX,
boot_to_ui_ready: 1,
};
assert_eq!(overflowing.total(), None);
assert!(overflowing.is_exact());
let exact = G8lS566MarkerMatrix {
boot8h: 2,
boot_to_ui_ready: 1,
};
assert_eq!(exact.total(), Some(3));
assert!(exact.is_exact());
let mut ledger = G8lS566RunbookLedger::new();
ledger.record(FreezePackage, HostObserved, image_hash()).unwrap();
ledger.record(VerifyManifest, HostObserved, manifest_hash()).unwrap();
ledger.record(StageToInactiveSlot, HostObserved, image_hash()).unwrap();
ledger
.record(Reboot, OperatorReported, report(G8lS566Decision::Reboot))
.unwrap();
assert_eq!(
ledger.record(
ConfirmBootMarkers,
HostObserved,
G8lS566EvidenceRecord::UartMarker(overflowing),
),
Err(G8lS566RunbookContractError::CounterOverflow)
);
assert_eq!(ledger.next_step(), Some(ConfirmBootMarkers));
assert_eq!(ledger.evidence_records(), 4);
assert_eq!(
ledger.record(
ConfirmBootMarkers,
HostObserved,
G8lS566EvidenceRecord::UartMarker(exact),
),
Ok(G8lS566ClaimFlags {
update_demonstrated: false,
rollback_demonstrated: false,
boot_markers_confirmed: true,
package_identity_verified: true,
})
);
}
#[test]
fn boot_marker_literals_and_slots_match_the_frozen_candidate_contract() {
assert_eq!(S566_BOOT_MARKER, "ASELSAN/BOOT8H");
assert_eq!(S566_BOOT_TO_UI_MARKER, "[R1:S536] BOOT_TO_UI_READY");
assert_eq!(S566_BOOT_MARKER_MINIMUM, 1);
assert_eq!(S566_BOOT_TO_UI_MARKER_EXACT, 1);
assert_eq!(G8lS566Slot::A.other(), G8lS566Slot::B);
assert_eq!(G8lS566Slot::B.other(), G8lS566Slot::A);
let evidence = [
(image_hash(), G8lS566EvidenceKind::Hash),
(exact_markers(), G8lS566EvidenceKind::UartMarker),
(report(G8lS566Decision::Commit), G8lS566EvidenceKind::OperatorReport),
];
for (record, kind) in evidence {
assert_eq!(record.kind(), kind);
}
}
snippet sha256: b686a47b5b8d…file sha256: b686a47b5b8d…
03 · Kapı kimlik kaydı
Operations sıra, kimlik ve başlık bağı
tam Operations kaydıL1952–L2011
website/src/lib/operations.ts::g8l-s566-r1-lab-update-demonstration-runbook-contract
{
id: "g8l-s566-r1-lab-update-demonstration-runbook-contract",
date: "2026-08-30",
sequence: 566,
status: "passed",
umbrella_status: "partial",
title: "S566 · R1 güncelleme: laboratuvar güncelleme gösterimi runbook sözleşmesi",
summary:
"S566 laboratuvar güncelleme gösterimi runbook sözleşmesini host tarafında yayımlar; hiçbir runbook adımı yürütülmez ve RUNBOOK_EXECUTED_IN_S566=NO'dur. Sözleşme altı sıralı adımı (paketi dondur → manifest doğrula → inactive slot'a stage et → reboot → boot marker'larını doğrula → commit veya rollback) her adımın zorunlu kanıt türü (hash, UART marker, operatör raporu) ve gözlem sınıfı (host-gözlemli / operatör-bildirimli) ile birlikte fail-closed bir tabloya bağlar; S545'in dondurulmuş dört girdili paketi (945760 B / ed1901a9…08d467 image) fixture 'current image' olarak byte-exact yeniden kullanılır. Adım yeniden sıralama, eksik veya yanlış kanıt türü, yanlış gözlem sınıfı, fixture'dan sapan image kimliği, bozuk digest, saha/ürün iddiası ve kanıtsız kurulan her claim bayrağı fail-closed reddedilir; demo-boundary ifadesi laboratuvar göstericisidir ve saha veya ürün iddiası içermez. Focused 21/21 PASS'tir; S540 ve S543 fiziksel RED değişmez, physical observation=0, SD/UART/power/new-raw=0/0/0/0, Boot-to-UI=false ve R1 acceptance=false'dur. S567 uygulama/recovery/güncelleme kabul matrisi kapısıdır.",
evidence: [
"S566, S565'ten ayrı bir kernel/simulation kaynak modülü, 21-test focused binary, proof, status manifest, Operations kaydı ve complete Code kartına sahiptir; hiçbir production callsite'a bağlanmamıştır.",
"Dar S566 durumu PASS'tir ve yalnız kaynak/host sözleşme kabulüdür; R1 umbrella=PARTIAL ve S540/S543 fiziksel kapı durumları RED olarak ayrı tutulur.",
"Runbook tablosu altı sıralı adımı sabitler: freeze package (hash, host), verify manifest (hash, host), stage to inactive slot (hash, host), reboot (operatör raporu, operatör), confirm boot markers (UART marker, host), commit veya rollback (operatör raporu, operatör); host-gözlemli adım=4, operatör-bildirimli adım=2'dir.",
"Fixture 'current image' S545 paket kimlikleriyle byte-exact aynıdır: aselsanos-rpi5.img 945760 B / ed1901a991e2f9e9ae3c16f254147a2b0180686a8d70ca5d7353374fee08d467, bcm2712-rpi-5-b.dtb 78703 B, config.txt 420 B ve SHA256SUMS 248 B / 3 satır; focused test bu sabitleri S545 modül sabitlerine eşitlikle bağlar.",
"Her digest tam 64 küçük-harf hex olmak zorundadır; receipt image byte sayısını ve ilk on altı hex karakterin u64 katlamasını (0xed1901a991e2f9e9) taşır; büyük harf, kısa, uzun, hex-dışı ve boş digest'ler InvalidDigest ile reddedilir.",
"Sözleşme servisi yanlış predecessor, sıfır anchor, yanlış adım sayısı (0/5/7), yer değiştirmiş adımlar, yanlış ordinal, tekrarlanan adım, eksik kanıt türü, yanlış kanıt türü, yanlış gözlem sınıfı, fixture'dan sapan image, aktif slot'un staging slot'a eşitlenmesi, saha iddiası, ürün iddiası, gösterici-dışı boundary, kanıtsız claim bayrağı, yürütülmüş adım iddiası ve kanıt kaydı iddiasını fail-closed reddeder.",
"Demo-boundary ifadesi 'LAB_DEMONSTRATOR_ONLY; NO_FIELD_CLAIM; NO_PRODUCT_CLAIM' sabitine bağlıdır; claim kümesinde saha veya ürün üyesi yoktur ve boundary yalnız {lab_demonstrator=true, field_claim=false, product_claim=false} iken kabul edilir.",
"Runbook ledger'ı yalnız focused testin sentetik kayıtlarıyla sürülen bir host modelidir: adım ancak sıradaki adımsa, tekrarlanmamışsa, raporlayan gözlem sınıfıyla ve kanıt türü tabloyla eşleşiyorsa ve payload exact ise kabul edilir; ihlal ledger'ı değiştirmeden hata döner.",
"Ledger payload kuralları: adım 0 ve 2 image kimliği, adım 1 manifest kimliği, adım 3 sıfır-olmayan Reboot raporu, adım 4 exact marker matrisi (ASELSAN/BOOT8H>=1 ve [R1:S536] BOOT_TO_UI_READY tam 1; toplam checked_add ile), adım 5 sıfır-olmayan Commit veya Rollback raporu ister.",
"Türetilen claim'ler kanıttan gelir: package_identity_verified adım 0–2, boot_markers_confirmed adım 3–4, update_demonstrated yalnız commit ve rollback_demonstrated yalnız rollback sonrası; sözleşmenin kendisi kanıt taşımadığından yayım anında her claim bayrağı false olmak zorundadır ve kanıtsız bayrak ClaimWithoutEvidence verir.",
"Exact replay aynı receipt'i ContractRetained ile korur; yayından sonra farklı anchor veya farklı adım listesi PublishedStateDrift/StepOutOfOrder ile reddedilir ve receipt değişmez.",
"Yirmi üç diagnostic code sıfırdan farklı ve benzersizdir.",
"Focused target 1 grup / 21 passed / 0 failed / 0 ignored / 0 filtered verdi.",
"Implementation 31689 B / f00d03362818afaea8c3ec225b297e20d327a7c215bd7866012efc892ff11138; focused test 31977 B / b686a47b5b8dec98f2d9fcd37f8e90d6e5a87e5337343ab269288ef2b205f54f SHA-256'dır.",
"Proof 6763 B'dır.",
"Kaynakta unsafe, asm!, write_volatile, crate::uart, crate::arch, #[no_mangle] veya spin:: yoktur; modül hiçbir boot, IRQ, scheduler veya driver yolundan çağrılmaz.",
"S566 sırasında SD write/read-back/eject, UART open/capture, power transition, fiziksel koşu, güncelleme gösterimi veya yeni immutable raw üretimi yapılmadı; sözleşme yürütme yetkisi vermez.",
"RUNBOOK_EXECUTED_IN_S566=NO; supported-profile runtime observations=0, physical observations=0, Boot-to-UI physically observed=false ve R1 acceptance=false'dur.",
"S567 uygulama/recovery/güncelleme kabul matrisi host-only kapıdır; bu runbook'u yürütemez ve laboratuvar gösterimi ayrı kapı, fresh target revalidation ve açık operatör yetkisi ister.",
],
commands: [
"CARGO_INCREMENTAL=0 cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s566_r1_lab_update_demonstration_runbook_contract -- --test-threads=1",
],
terminalSessions: [
{
id: "s566-focused",
title: "S566 laboratuvar güncelleme gösterimi runbook sözleşmesi focused kabulü",
commandLines: [
"CARGO_INCREMENTAL=0 cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s566_r1_lab_update_demonstration_runbook_contract -- --test-threads=1",
],
outputLines: [
"test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s",
"S566 focused=1 group / 21 passed / 0 failed",
"hardware=none physical=0 runbook=NO",
],
exitCode: 0,
outputMode: "complete",
},
],
terminalSessionsNote:
"S566 kaynak/host sözleşme kabulü PASS'tir; hiçbir runbook adımı yürütülmemiştir ve güncelleme gösterimi iddiası yoktur. S540 ve S543 RED raw'ları ve kararları değişmez.",
limitations: [
"S566 yalnız sözleşmeyi yayımlar; laboratuvar güncelleme gösterimi yürütülmemiştir, update_demonstrated ve rollback_demonstrated false'dur ve RUNBOOK_EXECUTED_IN_S566=NO'dur.",
"S540 ve S543 fiziksel RED immutable kalır; hiçbir sözleşme veya ledger sonucu bunları yükseltemez.",
"Bu kapıda hiçbir donanım/panel/modem/board gözlemi yoktur; SD write, UART open, power transition ve yeni raw sayıları 0'dır.",
"Demo-boundary laboratuvar göstericisiyle sınırlıdır; saha veya ürün iddiası bu sözleşmeden türetilemez ve BOOT_TO_UI_READY gerçek UART'ta bu kapıda görülmemiştir.",
"Operatör-bildirimli adımların bağımsız tanığı yoktur; ledger modeli yalnız sentetik kanıtla focused testte sürülmüştür.",
"S567 kabul matrisi host-only kapıdır ve bu runbook'un yürütülmesine yetki vermez; gösterim ayrı kapı, fresh target revalidation ve açık operatör yetkisi ister.",
],
},snippet sha256: fd4b97c99775…file 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_s566_r1_lab_update_demonstration_runbook_contract -- --test-threads=1proof: docs/M8.1-RPi5-G8l-S566-R1-Lab-Update-Demonstration-Runbook-Contract-Proof.md
Registry schema v5 · generator
website/scripts/generate-code-gates.mjs · Tam SHA-256: 91d38c7b6222f0b4c117be786454853543da55a160e543d9b951057cc20dcc06