v0.1.0-pre.011

This commit is contained in:
2026-07-24 14:23:58 +02:00
parent 62bc0ffb44
commit 42e8a203ec
460 changed files with 12005 additions and 7020 deletions

View File

@@ -5,14 +5,14 @@
/// Stable identity of one decoded event materializer.
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct MaterializerIdentity {
pub struct MtApiMaterializerIdentity {
/// Stable lower snake case processor name.
pub name: std::string::String,
/// Semantic or deterministic implementation version.
pub version: std::string::String,
}
impl MaterializerIdentity {
impl MtApiMaterializerIdentity {
/// Builds a validated materializer identity.
pub fn new(
name: impl std::convert::Into<std::string::String>,
@@ -33,7 +33,7 @@ impl MaterializerIdentity {
/// Explicit policy applied to successful and failed source transactions.
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum MaterializationTransactionPolicy {
pub enum MtApiMaterializationTransactionPolicy {
/// Accept committed observations from successful transactions only.
SuccessfulCommittedOnly,
/// Accept successful observations and failed audit-only observations.
@@ -44,7 +44,7 @@ pub enum MaterializationTransactionPolicy {
/// Terminal materializer result status.
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum MaterializerOutcomeStatus {
pub enum MtApiMaterializerOutcomeStatus {
/// One or more new stable outputs were inserted.
Inserted,
/// One or more processor-owned outputs were deterministically replaced.
@@ -59,7 +59,7 @@ pub enum MaterializerOutcomeStatus {
/// Structured materializer diagnostic without generic error wrappers.
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct MaterializerDiagnostic {
pub struct MtApiMaterializerDiagnostic {
/// Stable machine-readable diagnostic code.
pub code: std::string::String,
/// Human-readable diagnostic message.
@@ -68,7 +68,7 @@ pub struct MaterializerDiagnostic {
pub retriable: bool,
}
impl MaterializerDiagnostic {
impl MtApiMaterializerDiagnostic {
/// Builds a validated materializer diagnostic.
pub fn new(
code: impl std::convert::Into<std::string::String>,
@@ -91,16 +91,16 @@ impl MaterializerDiagnostic {
/// Stable processor-owned business output derived from one decoded observation.
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct MaterializedOutput {
pub struct MtApiMaterializedOutput {
/// Stable processor-owned output key within one decoded observation.
pub output_key: std::string::String,
/// Business output family.
pub family: crate::MaterializedEventFamily,
pub family: crate::MdMaterializedEventFamily,
/// Typed business payload serialized as deterministic JSON.
pub payload_json: serde_json::Value,
}
impl MaterializedOutput {
impl MtApiMaterializedOutput {
/// Validates stable output identity.
pub fn validate(&self) -> kb_core::Result<()> {
if self.output_key.trim().is_empty() {
@@ -114,22 +114,22 @@ impl MaterializedOutput {
/// Complete explicit result produced by one materializer invocation.
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct MaterializerExecutionResult {
pub struct MtApiMaterializerExecutionResult {
/// Terminal materializer status.
pub status: MaterializerOutcomeStatus,
pub status: MtApiMaterializerOutcomeStatus,
/// Stable business outputs.
pub outputs: std::vec::Vec<MaterializedOutput>,
pub outputs: std::vec::Vec<MtApiMaterializedOutput>,
/// Structured diagnostics.
pub diagnostics: std::vec::Vec<MaterializerDiagnostic>,
pub diagnostics: std::vec::Vec<MtApiMaterializerDiagnostic>,
}
impl MaterializerExecutionResult {
impl MtApiMaterializerExecutionResult {
/// Builds a policy refusal result.
pub fn refused(code: &str, message: &str) -> Self {
return Self {
status: MaterializerOutcomeStatus::Refused,
status: MtApiMaterializerOutcomeStatus::Refused,
outputs: std::vec::Vec::new(),
diagnostics: std::vec![MaterializerDiagnostic {
diagnostics: std::vec![MtApiMaterializerDiagnostic {
code: code.to_string(),
message: message.to_string(),
retriable: false,
@@ -140,7 +140,7 @@ impl MaterializerExecutionResult {
/// Builds an ignored result.
pub fn ignored() -> Self {
return Self {
status: MaterializerOutcomeStatus::Ignored,
status: MtApiMaterializerOutcomeStatus::Ignored,
outputs: std::vec::Vec::new(),
diagnostics: std::vec::Vec::new(),
};
@@ -148,8 +148,8 @@ impl MaterializerExecutionResult {
/// Validates status and output consistency.
pub fn validate(&self) -> kb_core::Result<()> {
let output_status = self.status == MaterializerOutcomeStatus::Inserted
|| self.status == MaterializerOutcomeStatus::Replaced;
let output_status = self.status == MtApiMaterializerOutcomeStatus::Inserted
|| self.status == MtApiMaterializerOutcomeStatus::Replaced;
if output_status && self.outputs.is_empty() {
return std::result::Result::Err(kb_core::Error::invalid_state(
"inserted or replaced materializer status requires outputs",
@@ -160,7 +160,7 @@ impl MaterializerExecutionResult {
"ignored, refused or failed materializer status must not contain outputs",
));
}
if self.status == MaterializerOutcomeStatus::Failed && self.diagnostics.is_empty() {
if self.status == MtApiMaterializerOutcomeStatus::Failed && self.diagnostics.is_empty() {
return std::result::Result::Err(kb_core::Error::invalid_state(
"failed materializer status requires at least one diagnostic",
));
@@ -176,26 +176,32 @@ impl MaterializerExecutionResult {
}
/// Stable decoded observation materializer contract used by the common pipeline.
pub trait EventMaterializer: std::marker::Send + std::marker::Sync {
pub trait MtApiEventMaterializer: std::marker::Send + std::marker::Sync {
/// Returns the stable materializer identity.
fn identity(&self) -> MaterializerIdentity;
fn identity(&self) -> MtApiMaterializerIdentity;
/// Returns every decoded event family explicitly accepted by this materializer.
fn accepted_families(&self) -> &'static [crate::EventFamily];
fn accepted_families(&self) -> &'static [crate::MdEventFamily];
/// Returns whether this materializer accepts one exact decoded observation.
fn accepts_observation(&self, observation: &crate::DecodedObservation) -> bool {
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
let family = observation.event.event_family;
return self.accepted_families().iter().any(|accepted| return *accepted == family);
}
/// Returns the failed/successful transaction policy for one accepted family.
fn transaction_policy(&self, family: crate::EventFamily) -> MaterializationTransactionPolicy;
fn transaction_policy(
&self,
family: crate::MdEventFamily,
) -> MtApiMaterializationTransactionPolicy;
/// Materializes one validated decoded observation.
fn materialize(&self, observation: &crate::DecodedObservation) -> MaterializerExecutionResult;
fn materialize(
&self,
observation: &crate::DcApiDecodedObservation,
) -> MtApiMaterializerExecutionResult;
}
/// Returns true when a materializer explicitly accepts one decoded family.
pub fn materializer_accepts_family(
materializer: &dyn EventMaterializer,
family: crate::EventFamily,
pub fn materializer_api_accepts_family(
materializer: &dyn MtApiEventMaterializer,
family: crate::MdEventFamily,
) -> bool {
return materializer
.accepted_families()
@@ -204,48 +210,48 @@ pub fn materializer_accepts_family(
}
/// Returns true when a materializer accepts one exact decoded observation.
pub fn materializer_accepts_observation(
materializer: &dyn EventMaterializer,
observation: &crate::DecodedObservation,
pub fn materializer_api_accepts_observation(
materializer: &dyn MtApiEventMaterializer,
observation: &crate::DcApiDecodedObservation,
) -> bool {
return materializer.accepts_observation(observation);
}
/// Applies the mandatory source transaction policy before materialization.
pub fn validate_materialization_policy(
materializer: &dyn EventMaterializer,
observation: &crate::DecodedObservation,
) -> std::result::Result<(), MaterializerExecutionResult> {
pub fn materializer_api_validate_materialization_policy(
materializer: &dyn MtApiEventMaterializer,
observation: &crate::DcApiDecodedObservation,
) -> std::result::Result<(), MtApiMaterializerExecutionResult> {
let family = observation.event.event_family;
if !crate::materializer_accepts_observation(materializer, observation) {
return std::result::Result::Err(MaterializerExecutionResult::refused(
if !crate::materializer_api_accepts_observation(materializer, observation) {
return std::result::Result::Err(MtApiMaterializerExecutionResult::refused(
"unsupported_decoded_observation",
"materializer does not accept the decoded observation surface and entry",
));
}
let policy = materializer.transaction_policy(family);
if observation.transaction_failed || !observation.observation_committed {
if family == crate::EventFamily::Trade
|| family == crate::EventFamily::Liquidity
|| family == crate::EventFamily::Lifecycle
if family == crate::MdEventFamily::Trade
|| family == crate::MdEventFamily::Liquidity
|| family == crate::MdEventFamily::Lifecycle
{
return std::result::Result::Err(MaterializerExecutionResult::refused(
return std::result::Result::Err(MtApiMaterializerExecutionResult::refused(
"failed_transaction_mutation_refused",
"failed or uncommitted observations cannot create successful mutable business outputs",
));
}
if policy == MaterializationTransactionPolicy::SuccessfulCommittedOnly {
return std::result::Result::Err(MaterializerExecutionResult::refused(
if policy == MtApiMaterializationTransactionPolicy::SuccessfulCommittedOnly {
return std::result::Result::Err(MtApiMaterializerExecutionResult::refused(
"failed_transaction_policy_refused",
"materializer accepts committed observations from successful transactions only",
));
}
if policy == MaterializationTransactionPolicy::SuccessfulOrFailedAudit
&& family != crate::EventFamily::Audit
&& family != crate::EventFamily::ComplianceAudit
&& family != crate::EventFamily::Risk
if policy == MtApiMaterializationTransactionPolicy::SuccessfulOrFailedAudit
&& family != crate::MdEventFamily::Audit
&& family != crate::MdEventFamily::ComplianceAudit
&& family != crate::MdEventFamily::Risk
{
return std::result::Result::Err(MaterializerExecutionResult::refused(
return std::result::Result::Err(MtApiMaterializerExecutionResult::refused(
"failed_transaction_non_audit_refused",
"failed transaction materialization is limited to declared audit or risk families",
));
@@ -255,20 +261,20 @@ pub fn validate_materialization_policy(
}
/// Rejects successful mutable business outputs derived from failed or uncommitted observations.
pub fn validate_materialized_output_policy(
observation: &crate::DecodedObservation,
result: &MaterializerExecutionResult,
) -> std::result::Result<(), MaterializerExecutionResult> {
pub fn materializer_api_validate_materialized_output_policy(
observation: &crate::DcApiDecodedObservation,
result: &MtApiMaterializerExecutionResult,
) -> std::result::Result<(), MtApiMaterializerExecutionResult> {
if !observation.transaction_failed && observation.observation_committed {
return std::result::Result::Ok(());
}
let forbidden_output = result.outputs.iter().any(|output| {
return output.family != crate::MaterializedEventFamily::ComplianceAudit
&& output.family != crate::MaterializedEventFamily::TokenMetadataRisk
&& output.family != crate::MaterializedEventFamily::Risk;
return output.family != crate::MdMaterializedEventFamily::ComplianceAudit
&& output.family != crate::MdMaterializedEventFamily::TokenMetadataRisk
&& output.family != crate::MdMaterializedEventFamily::Risk;
});
if forbidden_output {
return std::result::Result::Err(MaterializerExecutionResult::refused(
return std::result::Result::Err(MtApiMaterializerExecutionResult::refused(
"failed_transaction_output_refused",
"failed or uncommitted observations may only produce audit or risk outputs",
));
@@ -280,48 +286,48 @@ pub fn validate_materialized_output_policy(
mod tests {
struct TradeMaterializer;
impl crate::EventMaterializer for TradeMaterializer {
fn identity(&self) -> crate::MaterializerIdentity {
return crate::MaterializerIdentity {
impl crate::MtApiEventMaterializer for TradeMaterializer {
fn identity(&self) -> crate::MtApiMaterializerIdentity {
return crate::MtApiMaterializerIdentity {
name: "trade_materializer".to_string(),
version: "1".to_string(),
};
}
fn accepted_families(&self) -> &'static [crate::EventFamily] {
return &[crate::EventFamily::Trade];
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
return &[crate::MdEventFamily::Trade];
}
fn transaction_policy(
&self,
_family: crate::EventFamily,
) -> crate::MaterializationTransactionPolicy {
return crate::MaterializationTransactionPolicy::SuccessfulCommittedOnly;
_family: crate::MdEventFamily,
) -> crate::MtApiMaterializationTransactionPolicy {
return crate::MtApiMaterializationTransactionPolicy::SuccessfulCommittedOnly;
}
fn materialize(
&self,
_observation: &crate::DecodedObservation,
) -> crate::MaterializerExecutionResult {
return crate::MaterializerExecutionResult::ignored();
_observation: &crate::DcApiDecodedObservation,
) -> crate::MtApiMaterializerExecutionResult {
return crate::MtApiMaterializerExecutionResult::ignored();
}
}
fn failed_trade_observation() -> crate::DecodedObservation {
return crate::DecodedObservation {
fn failed_trade_observation() -> crate::DcApiDecodedObservation {
return crate::DcApiDecodedObservation {
event_key: "trade".to_string(),
event: crate::DecodedProtocolEvent {
signature: crate::Signature("signature".to_string()),
slot: crate::Slot(42),
instruction_path: crate::InstructionPath("0".to_string()),
program_id: crate::ProgramId("program".to_string()),
protocol_code: crate::ProtocolCode("protocol".to_string()),
surface_code: crate::SurfaceCode("surface".to_string()),
event_code: crate::EventCode("trade".to_string()),
event_name: crate::EventName("trade".to_string()),
event_family: crate::EventFamily::Trade,
source_kind: crate::EventSourceKind::Instruction,
confidence: crate::DecoderConfidence::Exact,
event: crate::MdDecodedProtocolEvent {
signature: crate::MdSignature("signature".to_string()),
slot: crate::MdSlot(42),
instruction_path: crate::MdInstructionPath("0".to_string()),
program_id: crate::MdProgramId("program".to_string()),
protocol_code: crate::MdProtocolCode("protocol".to_string()),
surface_code: crate::MdSurfaceCode("surface".to_string()),
event_code: crate::MdEventCode("trade".to_string()),
event_name: crate::MdEventName("trade".to_string()),
event_family: crate::MdEventFamily::Trade,
source_kind: crate::MdEventSourceKind::Instruction,
confidence: crate::MdDecoderConfidence::Exact,
},
payload_json: serde_json::json!({}),
transaction_failed: true,
@@ -329,9 +335,9 @@ mod tests {
serde_json::json!({"InstructionError": [0, "Custom"]}),
),
observation_committed: false,
proof: crate::DecoderProof {
kind: crate::DecoderProofKind::ExactLayout,
confidence: crate::DecoderConfidence::Exact,
proof: crate::DcApiDecoderProof {
kind: crate::DcApiDecoderProofKind::ExactLayout,
confidence: crate::MdDecoderConfidence::Exact,
evidence: std::vec!["layout".to_string()],
},
};
@@ -339,47 +345,49 @@ mod tests {
#[test]
fn failed_trade_is_refused_before_materialization() {
let result =
crate::validate_materialization_policy(&TradeMaterializer, &failed_trade_observation());
let result = crate::materializer_api_validate_materialization_policy(
&TradeMaterializer,
&failed_trade_observation(),
);
assert!(result.is_err());
let refusal = match result {
std::result::Result::Ok(()) => panic!("failed trade unexpectedly accepted"),
std::result::Result::Err(value) => value,
};
assert_eq!(refusal.status, crate::MaterializerOutcomeStatus::Refused);
assert_eq!(refusal.status, crate::MtApiMaterializerOutcomeStatus::Refused);
assert_eq!(refusal.diagnostics[0].code, "failed_transaction_mutation_refused");
}
struct FailedAuditToTradeMaterializer;
impl crate::EventMaterializer for FailedAuditToTradeMaterializer {
fn identity(&self) -> crate::MaterializerIdentity {
return crate::MaterializerIdentity {
impl crate::MtApiEventMaterializer for FailedAuditToTradeMaterializer {
fn identity(&self) -> crate::MtApiMaterializerIdentity {
return crate::MtApiMaterializerIdentity {
name: "failed_audit_to_trade".to_string(),
version: "1".to_string(),
};
}
fn accepted_families(&self) -> &'static [crate::EventFamily] {
return &[crate::EventFamily::Audit];
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
return &[crate::MdEventFamily::Audit];
}
fn transaction_policy(
&self,
_family: crate::EventFamily,
) -> crate::MaterializationTransactionPolicy {
return crate::MaterializationTransactionPolicy::SuccessfulOrFailedAudit;
_family: crate::MdEventFamily,
) -> crate::MtApiMaterializationTransactionPolicy {
return crate::MtApiMaterializationTransactionPolicy::SuccessfulOrFailedAudit;
}
fn materialize(
&self,
_observation: &crate::DecodedObservation,
) -> crate::MaterializerExecutionResult {
return crate::MaterializerExecutionResult {
status: crate::MaterializerOutcomeStatus::Inserted,
outputs: std::vec![crate::MaterializedOutput {
_observation: &crate::DcApiDecodedObservation,
) -> crate::MtApiMaterializerExecutionResult {
return crate::MtApiMaterializerExecutionResult {
status: crate::MtApiMaterializerOutcomeStatus::Inserted,
outputs: std::vec![crate::MtApiMaterializedOutput {
output_key: "trade".to_string(),
family: crate::MaterializedEventFamily::Trade,
family: crate::MdMaterializedEventFamily::Trade,
payload_json: serde_json::json!({}),
}],
diagnostics: std::vec::Vec::new(),
@@ -387,9 +395,9 @@ mod tests {
}
}
fn failed_audit_observation() -> crate::DecodedObservation {
fn failed_audit_observation() -> crate::DcApiDecodedObservation {
let mut observation = failed_trade_observation();
observation.event.event_family = crate::EventFamily::Audit;
observation.event.event_family = crate::MdEventFamily::Audit;
return observation;
}
@@ -397,16 +405,20 @@ mod tests {
fn failed_audit_cannot_emit_successful_trade_output() {
let materializer = FailedAuditToTradeMaterializer;
let observation = failed_audit_observation();
let policy_result = crate::validate_materialization_policy(&materializer, &observation);
let policy_result =
crate::materializer_api_validate_materialization_policy(&materializer, &observation);
assert!(policy_result.is_ok());
let materialized = crate::EventMaterializer::materialize(&materializer, &observation);
let output_result = crate::validate_materialized_output_policy(&observation, &materialized);
let materialized = crate::MtApiEventMaterializer::materialize(&materializer, &observation);
let output_result = crate::materializer_api_validate_materialized_output_policy(
&observation,
&materialized,
);
assert!(output_result.is_err());
let refusal = match output_result {
std::result::Result::Ok(()) => panic!("failed audit unexpectedly emitted a trade"),
std::result::Result::Err(value) => value,
};
assert_eq!(refusal.status, crate::MaterializerOutcomeStatus::Refused);
assert_eq!(refusal.status, crate::MtApiMaterializerOutcomeStatus::Refused);
assert_eq!(refusal.diagnostics[0].code, "failed_transaction_output_refused");
}
}

View File

@@ -4,7 +4,7 @@
//! Materializer API contract used by business materializer crates.
/// Common contract implemented by all business materializer crates.
pub trait Materializer {
pub trait MtMaterializer {
/// Returns the stable materializer name.
fn materializer_name(&self) -> &'static str;
@@ -12,11 +12,11 @@ pub trait Materializer {
fn materializer_version(&self) -> &'static str;
/// Tests whether this materializer accepts a decoded event.
fn accepts_event(&self, event: &crate::DecodedProtocolEvent) -> bool;
fn accepts_event(&self, event: &crate::MdDecodedProtocolEvent) -> bool;
/// Materializes a decoded event into zero or more business events.
fn materialize_event(
&self,
event: &crate::DecodedProtocolEvent,
) -> kb_core::Result<std::vec::Vec<crate::MaterializedEvent>>;
event: &crate::MdDecodedProtocolEvent,
) -> kb_core::Result<std::vec::Vec<crate::MdMaterializedEvent>>;
}