Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,13 @@

### Fixed

- `dispatch_intent` no longer stages a witnessed suffix import against the
kernel's default worldline (#892). It ignored the request's receiving
worldline and recorded `Staged` without the bundle and basis checks the
library performs. Until comparable-basis transport exists, import intents
are refused with `NOT_SUPPORTED` and nothing is admitted, staged or
attributed.

- A tick that decides a submission no rule matched now commits and recovers
under the WAL (#873). The WAL tick decision gains `NoMatchingRule` (code 4),
recovery maps it to `RecoveredSubmissionPosture::DecidedNoMatchingRule`, and
Expand Down
107 changes: 41 additions & 66 deletions crates/warp-wasm/src/warp_kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,16 @@ impl KernelPort for WarpKernel {
code: error_codes::INVALID_INTENT,
message: "invalid import suffix intent envelope".into(),
})?;
// Import must be judged at the request's receiving worldline and a
// comparable basis that transport establishes. Until that exists
// (flyingrobots/continuum#80), refuse instead of staging the
// import against this kernel's default worldline.
return Err(AbiError {
code: error_codes::NOT_SUPPORTED,
message: "witnessed suffix import is not supported until comparable-basis \
transport exists; nothing was admitted"
.into(),
});
}

let envelope = IngressEnvelope::local_intent(
Expand Down Expand Up @@ -1170,13 +1180,12 @@ impl TrustedKernelControlPort for WarpKernel {
mod tests {
use super::*;
use echo_wasm_abi::{
decode_cbor,
kernel_port::{
BuiltinObserverPlan as AbiBuiltinObserverPlan,
CausalSuffixBundle as AbiCausalSuffixBundle, ControlIntentV1,
GlobalTick as AbiGlobalTick, HeadEligibility as AbiHeadEligibility,
HeadId as AbiHeadId, ImportSuffixRequest as AbiImportSuffixRequest,
ImportSuffixResult as AbiImportSuffixResult, ObservationAt as AbiObservationAt,
ObservationAt as AbiObservationAt,
ObservationBasisPosture as AbiObservationBasisPosture,
ObservationCoordinate as AbiObservationCoordinate,
ObservationFrame as AbiObservationFrame, ObservationPayload as AbiObservationPayload,
Expand All @@ -1191,7 +1200,6 @@ mod tests {
SettlementOverlapRevalidation as AbiSettlementOverlapRevalidation,
SettlementParentRevalidation as AbiSettlementParentRevalidation,
SettlementRequest as AbiSettlementRequest,
WitnessedSuffixAdmissionOutcome as AbiWitnessedSuffixAdmissionOutcome,
WitnessedSuffixShell as AbiWitnessedSuffixShell, WorkState,
WorldlineId as AbiWorldlineId, WorldlineTick as AbiWorldlineTick,
WriterHeadKey as AbiWriterHeadKey,
Expand Down Expand Up @@ -1937,82 +1945,49 @@ mod tests {
}

#[test]
fn import_suffix_intent_enters_ingress_and_scheduler() {
fn import_suffix_dispatch_fails_closed_until_transport_exists() {
let mut kernel = WarpKernel::new().unwrap();
let request = sample_import_suffix_request(&kernel);
let intent = pack_import_suffix_intent_v1(&request).unwrap();
let head_before = kernel.current_head().unwrap();

let dispatch = kernel.dispatch_intent(&intent).unwrap();
assert!(dispatch.accepted);
assert_eq!(dispatch.intent_id.len(), 32);
let refusal = kernel.dispatch_intent(&intent).unwrap_err();
assert_eq!(refusal.code, error_codes::NOT_SUPPORTED);

let response = start_until_idle(&mut kernel, Some(1));
let head = kernel.current_head().unwrap();
// Nothing was admitted: no ingress to run, no tick, no staged result.
start_until_idle(&mut kernel, Some(1));
assert_eq!(
response.scheduler_status.last_run_completion,
Some(RunCompletion::Quiesced)
kernel.current_head().unwrap().worldline_tick,
head_before.worldline_tick
);
let event_id = NodeId(
IngressEnvelope::local_intent(
IngressTarget::DefaultWriter {
worldline_id: kernel.default_worldline,
},
make_intent_kind("echo.intent/eint-v1"),
intent.clone(),
)
.ingress_id(),
);
assert_eq!(head.worldline_tick, AbiWorldlineTick(1));

let event_id = NodeId(dispatch.intent_id.as_slice().try_into().unwrap());
let result_id = warp_core::import_suffix_result_node_id(&event_id);
let frontier = kernel
.runtime
.worldlines()
.get(&kernel.default_worldline)
.unwrap();
let frontier_state = frontier.state();
let root_warp = frontier_state.root().warp_id;
let store = frontier_state.store(&root_warp).unwrap();
let result_node = store.node(&result_id);
assert!(result_node.is_some());

let result_attachment = store
.node_attachment(&result_id)
.expect("import suffix result attachment should be recorded");
let warp_core::AttachmentValue::Atom(atom) = result_attachment else {
panic!("import suffix result must be a typed atom");
};
assert_eq!(
atom.type_id,
make_type_id(warp_core::IMPORT_SUFFIX_RESULT_ATTACHMENT_TYPE)
);

let result: AbiImportSuffixResult = decode_cbor(atom.bytes.as_ref()).unwrap();
assert_eq!(result.bundle_digest, request.bundle.bundle_digest);
assert_eq!(
result.admission.source_shell_digest,
request.bundle.source_suffix.witness_digest
);
assert_eq!(result.admission.target_basis, request.target_basis);
match result.admission.outcome {
AbiWitnessedSuffixAdmissionOutcome::Staged { staged_refs, .. } => {
assert_eq!(staged_refs, request.bundle.source_suffix.source_entries);
}
other => panic!("expected staged import result, got {other:?}"),
}

let entry = kernel
.provenance
.entry(kernel.default_worldline, WorldlineTick::ZERO)
let store = frontier
.state()
.store(&frontier.state().root().warp_id)
.unwrap();
let patch = entry.patch.expect("import tick should record a patch");
assert!(patch.ops.iter().any(|op| {
matches!(
op,
WarpOp::UpsertNode { node, .. } if node.local_id == result_id
)
}));
assert!(patch.ops.iter().any(|op| {
matches!(
op,
WarpOp::SetAttachment { key, .. }
if *key == AttachmentKey::node_alpha(NodeKey {
warp_id: root_warp,
local_id: result_id,
})
)
}));
assert!(store
.node(&warp_core::import_suffix_result_node_id(&event_id))
.is_none());
assert!(store.node(&event_id).is_none());

// A malformed import envelope is still reported as malformed.
let mut malformed = intent;
malformed.truncate(malformed.len() - 1);
assert!(kernel.dispatch_intent(&malformed).is_err());
}

#[test]
Expand Down
8 changes: 8 additions & 0 deletions docs/architecture/continuum-transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ transport adapter receives bytes
-> tick + receipt / witness
```

**Current status (#892).** This flow is not wired. Until comparable-basis
transport is specified ([continuum#80](https://github.com/flyingrobots/continuum/issues/80))
and the import is dispatched to its explicitly named receiving worldline,
`dispatch_intent` refuses import intents with `NOT_SUPPORTED` and admits,
stages and attributes nothing. It never substitutes the kernel's default
worldline. The library evaluator (`import_suffix`) is unaffected and is not
reachable from dispatch.

The runtime must:

1. Verify the source shell and bundle identities.
Expand Down
Loading