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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

### Fixed

- Outgoing-edge bucket iterators expose their exact remaining length without
inspecting edges, so bounded readers can precharge the entire source bucket
before filtering by type.

- The native pure interpreter evaluates bounded UTF-8 byte predicates with
complete aperture charging and typed Boolean values. Native provider judgments
independently validate matching helper/read guards and their bounded scan work.
Expand Down Expand Up @@ -137,6 +141,15 @@

### Added

- Outgoing-edge range claims retain source WARP, source node and edge type in
footprint union and scheduler reservation, including observed empty ranges.
Range-bearing operation footprint identities bind both range axes separately;
footprints without ranges keep their V1 identities. Range slots survive patch
identity, retained provenance and native Tick input/output metadata. Historical
host range readings replay a selected prefix and preserve edge relabeling,
movement and deletion. This does not implement the authored operation effect
bridge.

- Native Edict provider judgments accept the distinct bounded source-closure
artifact, preserve its identity and refuse mixed or relabelled source forms.
An explicit generation variant carries its owning schema binding; generic
Expand Down
4 changes: 4 additions & 0 deletions crates/echo-dry-tests/src/demo_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ fn base_scope_footprint(view: GraphView<'_>, scope: &NodeId) -> BaseScopeFootpri
fn compute_motion_footprint(view: GraphView<'_>, scope: &NodeId) -> Footprint {
let base = base_scope_footprint(view, scope);
Footprint {
r_read: warp_core::OutgoingEdgeRangeSet::default(),
r_write: warp_core::OutgoingEdgeRangeSet::default(),
n_read: base.n_read,
n_write: NodeSet::default(),
e_read: EdgeSet::default(),
Expand Down Expand Up @@ -285,6 +287,8 @@ fn compute_port_footprint(view: GraphView<'_>, scope: &NodeId) -> Footprint {
b_in.insert(base.warp_id, pack_port_key(scope, 0, true));
}
Footprint {
r_read: warp_core::OutgoingEdgeRangeSet::default(),
r_write: warp_core::OutgoingEdgeRangeSet::default(),
n_read: base.n_read,
n_write,
e_read: EdgeSet::default(),
Expand Down
2 changes: 2 additions & 0 deletions crates/echo-dry-tests/src/footprint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ impl FootprintBuilder {
/// Consumes the builder and returns the constructed [`Footprint`].
pub fn build(self) -> Footprint {
Footprint {
r_read: warp_core::OutgoingEdgeRangeSet::default(),
r_write: warp_core::OutgoingEdgeRangeSet::default(),
n_read: self.n_read,
n_write: self.n_write,
e_read: self.e_read,
Expand Down
5 changes: 4 additions & 1 deletion crates/warp-core/src/admission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//! without changing the single-tick law that all admission still happens under
//! `super_tick()`.

use crate::footprint::{AttachmentSet, EdgeSet, Footprint, NodeSet, PortSet};
use crate::footprint::{AttachmentSet, EdgeSet, Footprint, NodeSet, OutgoingEdgeRangeSet, PortSet};
use crate::ident::Hash;

/// Engine-defined policy identity for one admission act.
Expand All @@ -42,6 +42,8 @@ pub struct AffectedRegion {
pub edges: EdgeSet,
/// Attachments locally affected by the claim.
pub attachments: AttachmentSet,
/// Outgoing-edge ranges affected by the claim, including empty ranges.
pub outgoing_edge_ranges: OutgoingEdgeRangeSet,
}

impl AffectedRegion {
Expand All @@ -52,6 +54,7 @@ impl AffectedRegion {
nodes: footprint.n_write.clone(),
edges: footprint.e_write.clone(),
attachments: footprint.a_write.clone(),
outgoing_edge_ranges: footprint.r_write.clone(),
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/warp-core/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ fn import_suffix_intent_footprint(view: crate::GraphView<'_>, scope: &NodeId) ->
}));

Footprint {
r_read: crate::footprint::OutgoingEdgeRangeSet::default(),
r_write: crate::footprint::OutgoingEdgeRangeSet::default(),
n_read,
n_write,
e_read: EdgeSet::default(),
Expand Down
2 changes: 2 additions & 0 deletions crates/warp-core/src/contract_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ pub fn runtime_ingress_eint_read_footprint(view: GraphView<'_>, scope: &NodeId)
local_id: *scope,
}));
Footprint {
r_read: crate::footprint::OutgoingEdgeRangeSet::default(),
r_write: crate::footprint::OutgoingEdgeRangeSet::default(),
n_read,
n_write: NodeSet::default(),
e_read: EdgeSet::default(),
Expand Down
64 changes: 63 additions & 1 deletion crates/warp-core/src/echo_operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const CREATE_APPLICATION_BASIS_DOMAIN: &[u8] =
const CREATE_RESULT_ABSENCE_PROPOSITION_DOMAIN: &[u8] =
b"echo:operation-result-anchored-node-alpha-absence-proposition:v1\0";
const FOOTPRINT_DIGEST_DOMAIN: &[u8] = b"echo:operation-footprint:v1\0";
const RANGE_FOOTPRINT_DIGEST_DOMAIN: &[u8] = b"echo:operation-footprint:v2\0";
const RECEIPT_DIGEST_DOMAIN: &[u8] = b"echo:operation-receipt:v1\0";
const COMPOSITION_DIGEST_DOMAIN: &[u8] = b"echo:operation-singleton-composition:v1\0";
const PLAN_DIGEST_DOMAIN: &[u8] = b"echo:operation-plan:v1\0";
Expand Down Expand Up @@ -7509,7 +7510,12 @@ fn record_node_read(footprint: &mut Footprint, node: NodeKey) {

fn footprint_digest(footprint: &Footprint) -> Hash {
let mut hasher = Hasher::new();
hasher.update(FOOTPRINT_DIGEST_DOMAIN);
let has_ranges = !footprint.r_read.is_empty() || !footprint.r_write.is_empty();
hasher.update(if has_ranges {
RANGE_FOOTPRINT_DIGEST_DOMAIN
} else {
FOOTPRINT_DIGEST_DOMAIN
});
hash_node_set(
&mut hasher,
b"nr",
Expand Down Expand Up @@ -7559,6 +7565,17 @@ fn footprint_digest(footprint: &Footprint) -> Hash {
footprint.b_out.iter(),
);
hasher.update(&footprint.factor_mask.to_le_bytes());
if has_ranges {
for (label, ranges) in [(b"rr", &footprint.r_read), (b"rw", &footprint.r_write)] {
hasher.update(label);
hasher.update(&(ranges.len() as u64).to_le_bytes());
for range in ranges.iter() {
hasher.update(range.source.warp_id.as_bytes());
hasher.update(range.source.local_id.as_bytes());
hasher.update(range.edge_type.as_bytes());
}
}
}
hasher.finalize().into()
}

Expand Down Expand Up @@ -8689,6 +8706,17 @@ mod tests {
debug_assert_action_member_alignment_v1(2, 1);
}

#[test]
fn footprint_without_ranges_retains_its_v1_identity() {
assert_eq!(
footprint_digest(&Footprint::default()),
[
133, 20, 8, 211, 91, 122, 210, 37, 17, 71, 156, 145, 21, 30, 109, 175, 39, 57, 176,
34, 41, 209, 18, 169, 48, 224, 15, 83, 138, 167, 145, 2
]
);
}

#[test]
fn footprint_digest_is_prefix_free_across_adjacent_sets() {
let mut read_node_bytes = [0; 64];
Expand Down Expand Up @@ -8749,6 +8777,40 @@ mod tests {
let mut footprint = Footprint::default();
footprint.b_out.insert(node.warp_id, 9);
footprints.push(footprint);
let range = crate::footprint::OutgoingEdgeRange {
source: node,
edge_type: crate::TypeId(digest(10)),
};
let mut footprint = Footprint::default();
footprint.r_read.insert(range);
footprints.push(footprint);
let mut footprint = Footprint::default();
footprint.r_write.insert(range);
footprints.push(footprint);
for changed in [
crate::footprint::OutgoingEdgeRange {
source: NodeKey {
warp_id: crate::WarpId(digest(11)),
..node
},
..range
},
crate::footprint::OutgoingEdgeRange {
source: NodeKey {
local_id: crate::NodeId(digest(11)),
..node
},
..range
},
crate::footprint::OutgoingEdgeRange {
edge_type: crate::TypeId(digest(11)),
..range
},
] {
let mut footprint = Footprint::default();
footprint.r_read.insert(changed);
footprints.push(footprint);
}
footprints.push(Footprint {
factor_mask: 1,
..Footprint::default()
Expand Down
23 changes: 23 additions & 0 deletions crates/warp-core/src/engine_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ use crate::tx::TxId;
use crate::warp_state::{WarpInstance, WarpState};
use crate::worldline_state::WorldlineState;
use crate::ContractInverseHandler;

#[cfg(test)]
#[path = "engine_impl/range_tests.rs"]
mod range_tests;
use std::sync::Arc;

const RUNTIME_INGRESS_EVENT_TYPE: &str = "runtime/ingress/event";
Expand Down Expand Up @@ -3230,6 +3234,12 @@ pub(crate) fn footprints_conflict(
{
return true;
}
if a.r_write.intersects(&b.r_write)
|| a.r_write.intersects(&b.r_read)
|| b.r_write.intersects(&a.r_read)
{
return true;
}
if a.a_write.intersects(&b.a_write)
|| a.a_write.intersects(&b.a_read)
|| b.a_write.intersects(&a.a_read)
Expand Down Expand Up @@ -3349,6 +3359,13 @@ fn extend_slots_from_footprint(
in_slots.insert(SlotId::Edge(*key));
out_slots.insert(SlotId::Edge(*key));
}
for key in fp.r_read.iter() {
in_slots.insert(SlotId::OutgoingEdges(*key));
}
for key in fp.r_write.iter() {
in_slots.insert(SlotId::OutgoingEdges(*key));
out_slots.insert(SlotId::OutgoingEdges(*key));
}

// Attachments (already warp-scoped via AttachmentKey)
for key in fp.a_read.iter() {
Expand Down Expand Up @@ -3526,6 +3543,8 @@ mod tests {
a_write.insert(key);
}
crate::Footprint {
r_read: crate::footprint::OutgoingEdgeRangeSet::default(),
r_write: crate::footprint::OutgoingEdgeRangeSet::default(),
n_read: crate::NodeSet::default(),
n_write: crate::NodeSet::default(),
e_read: crate::EdgeSet::default(),
Expand Down Expand Up @@ -3566,6 +3585,8 @@ mod tests {
a_write.insert(key);
}
crate::Footprint {
r_read: crate::footprint::OutgoingEdgeRangeSet::default(),
r_write: crate::footprint::OutgoingEdgeRangeSet::default(),
n_read: crate::NodeSet::default(),
n_write: crate::NodeSet::default(),
e_read: crate::EdgeSet::default(),
Expand Down Expand Up @@ -3660,6 +3681,8 @@ mod tests {
local_id: *scope,
}));
crate::Footprint {
r_read: crate::footprint::OutgoingEdgeRangeSet::default(),
r_write: crate::footprint::OutgoingEdgeRangeSet::default(),
n_read,
n_write: crate::NodeSet::default(),
e_read: crate::EdgeSet::default(),
Expand Down
Loading
Loading