Skip to content

Commit 7aa69b1

Browse files
authored
Merge pull request #325 from flyingrobots/cycle/0012-witnessed-suffix-posture-canonicalization-red
Canonical witnessed suffix posture constructors
2 parents cb4586b + ce38fd0 commit 7aa69b1

5 files changed

Lines changed: 445 additions & 160 deletions

File tree

crates/warp-core/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ pub use warp_state::{WarpInstance, WarpState};
252252
pub use witnessed_suffix::{
253253
evaluate_witnessed_suffix_admission, WitnessedSuffixAdmissionContext,
254254
WitnessedSuffixAdmissionOutcome, WitnessedSuffixAdmissionRequest,
255-
WitnessedSuffixAdmissionResponse, WitnessedSuffixLocalAdmissionPosture, WitnessedSuffixShell,
255+
WitnessedSuffixAdmissionResponse, WitnessedSuffixLocalAdmissionPosture,
256+
WitnessedSuffixLocalAdmissionPostureError, WitnessedSuffixShell,
256257
};
257258
pub use worldline::{
258259
ApplyError, AtomWrite, AtomWriteSet, HashTriplet, OutputFrameSet, WorldlineId,

crates/warp-core/src/witnessed_suffix.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
99
use blake3::Hasher;
1010
use echo_wasm_abi::{encode_cbor, kernel_port as abi};
11+
use thiserror::Error;
1112

1213
use crate::attachment::{AttachmentOwner, AttachmentPlane};
1314
use crate::clock::WorldlineTick;
@@ -139,22 +140,48 @@ pub trait WitnessedSuffixAdmissionContext {
139140
) -> WitnessedSuffixLocalAdmissionPosture;
140141
}
141142

143+
/// Error returned when constructing a canonical local admission posture fails.
144+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Error)]
145+
pub enum WitnessedSuffixLocalAdmissionPostureError {
146+
/// A provenance coordinate appeared more than once in a posture vector.
147+
#[error("duplicate witnessed suffix local admission provenance ref: {provenance_ref:?}")]
148+
DuplicateProvenanceRef {
149+
/// Duplicate provenance coordinate.
150+
provenance_ref: ProvenanceRef,
151+
},
152+
}
153+
142154
/// Local posture reported by the read-only admission context.
155+
///
156+
/// Prefer [`Self::admissible`], [`Self::staged`], or [`Self::plural`] for
157+
/// ordinary construction so ref vectors are sorted canonically and duplicate
158+
/// provenance refs are rejected before reaching an ABI-visible response. Direct
159+
/// enum construction remains available for raw-shape tests and defensive
160+
/// evaluator inputs.
143161
#[derive(Clone, Debug, PartialEq, Eq)]
144162
pub enum WitnessedSuffixLocalAdmissionPosture {
145163
/// Local evidence says the suffix is admissible.
146164
Admissible {
147165
/// Target-local provenance coordinates produced or expected by admission.
166+
///
167+
/// Use [`WitnessedSuffixLocalAdmissionPosture::admissible`] for normal
168+
/// construction.
148169
admitted_refs: Vec<ProvenanceRef>,
149170
},
150171
/// Local evidence says the suffix should be retained for later judgment.
151172
Staged {
152173
/// Source or target coordinates retained while staged.
174+
///
175+
/// Use [`WitnessedSuffixLocalAdmissionPosture::staged`] for normal
176+
/// construction.
153177
staged_refs: Vec<ProvenanceRef>,
154178
},
155179
/// Local evidence preserves lawful plurality.
156180
Plural {
157181
/// Candidate coordinates that remain lawful plural outcomes.
182+
///
183+
/// Use [`WitnessedSuffixLocalAdmissionPosture::plural`] for normal
184+
/// construction.
158185
candidate_refs: Vec<ProvenanceRef>,
159186
},
160187
/// Local evidence reports deterministic adverse admission law.
@@ -170,6 +197,51 @@ pub enum WitnessedSuffixLocalAdmissionPosture {
170197
},
171198
}
172199

200+
impl WitnessedSuffixLocalAdmissionPosture {
201+
/// Builds an admissible posture with canonical admitted refs.
202+
pub fn admissible(
203+
admitted_refs: Vec<ProvenanceRef>,
204+
) -> Result<Self, WitnessedSuffixLocalAdmissionPostureError> {
205+
Ok(Self::Admissible {
206+
admitted_refs: canonical_unique_provenance_refs(admitted_refs)?,
207+
})
208+
}
209+
210+
/// Builds a staged posture with canonical staged refs.
211+
pub fn staged(
212+
staged_refs: Vec<ProvenanceRef>,
213+
) -> Result<Self, WitnessedSuffixLocalAdmissionPostureError> {
214+
Ok(Self::Staged {
215+
staged_refs: canonical_unique_provenance_refs(staged_refs)?,
216+
})
217+
}
218+
219+
/// Builds a plural posture with canonical candidate refs.
220+
pub fn plural(
221+
candidate_refs: Vec<ProvenanceRef>,
222+
) -> Result<Self, WitnessedSuffixLocalAdmissionPostureError> {
223+
Ok(Self::Plural {
224+
candidate_refs: canonical_unique_provenance_refs(candidate_refs)?,
225+
})
226+
}
227+
228+
/// Builds a conflict posture from named conflict evidence.
229+
#[must_use]
230+
pub fn conflict(
231+
reason: ConflictReason,
232+
source_ref: ProvenanceRef,
233+
evidence_digest: Hash,
234+
overlap_revalidation: Option<StrandOverlapRevalidation>,
235+
) -> Self {
236+
Self::Conflict {
237+
reason,
238+
source_ref,
239+
evidence_digest,
240+
overlap_revalidation,
241+
}
242+
}
243+
}
244+
173245
/// Evaluates one witnessed suffix admission request against local evidence.
174246
///
175247
/// Performs deterministic local validation before returning the classified
@@ -374,6 +446,24 @@ fn canonical_provenance_refs(mut refs: Vec<ProvenanceRef>) -> Vec<ProvenanceRef>
374446
refs
375447
}
376448

449+
fn canonical_unique_provenance_refs(
450+
mut refs: Vec<ProvenanceRef>,
451+
) -> Result<Vec<ProvenanceRef>, WitnessedSuffixLocalAdmissionPostureError> {
452+
refs.sort_unstable();
453+
454+
for window in refs.windows(2) {
455+
if window[0] == window[1] {
456+
return Err(
457+
WitnessedSuffixLocalAdmissionPostureError::DuplicateProvenanceRef {
458+
provenance_ref: window[0],
459+
},
460+
);
461+
}
462+
}
463+
464+
Ok(refs)
465+
}
466+
377467
fn obstructed_response(
378468
request: &WitnessedSuffixAdmissionRequest,
379469
source_shell_digest: Hash,

0 commit comments

Comments
 (0)