Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5c8303a
feat(physical): add rack and bay planning
polaz Oct 31, 2026
aed49f2
feat(physical): unify transition steps
polaz Oct 31, 2026
70453b5
refactor(physical): unify placement storage
polaz Oct 31, 2026
5c2d846
fix(physical): satisfy strict code checks
polaz Oct 31, 2026
cb33750
fix(physical): protect reservation lifecycles
polaz Oct 31, 2026
c0e5ee5
fix(physical): keep one type authority
polaz Oct 31, 2026
ed20c21
fix(physical): avoid duplicate slot updates
polaz Oct 31, 2026
13b43fa
feat(physical): share preview admission
polaz Oct 31, 2026
6372218
feat(plans): gate steps with shared requirements
polaz Oct 31, 2026
a44d799
feat(cables): define named physical ends
polaz Oct 31, 2026
65412b3
feat(cables): record wiring through shared plans
polaz Oct 31, 2026
bb308bc
build: select the stable Rust channel
polaz Oct 31, 2026
4c361f2
feat(physical): add scoped availability
polaz Oct 31, 2026
c32240e
feat(physical): enforce service clearances
polaz Oct 31, 2026
f78e32d
fix(physical): require occupancy evidence
polaz Oct 31, 2026
3bd9b93
feat(physical): assess recorded power paths
polaz Nov 1, 2026
ec2105d
fix(ui): project accurate rack elevations
polaz Nov 1, 2026
4269c7c
feat(physical): declare rack rail numbering
polaz Nov 1, 2026
889c64e
fix(physical): fence future removal credits
polaz Nov 1, 2026
e4748bb
feat(physical): couple replacement and pose
polaz Nov 1, 2026
27d383e
feat(physical): track plan material demand
polaz Nov 1, 2026
a510d6c
feat(physical): place future material units
polaz Nov 1, 2026
236e4ee
feat(physical): review replacement mappings
polaz Nov 1, 2026
60159d1
fix(physical): page binding postconditions
polaz Nov 1, 2026
ad7764d
fix(physical): include future availability loads
polaz Nov 1, 2026
554f27f
fix(physical): account for received unit loads
polaz Nov 1, 2026
3dc5c53
fix(physical): reconcile removed review decisions
polaz Nov 1, 2026
e08e439
fix(ui): draft space for incomplete materials
polaz Nov 1, 2026
9489a09
fix(ui): refresh physical context without drafts
polaz Nov 1, 2026
9758a18
fix(physical): enforce component slot budgets
polaz Nov 1, 2026
98bf182
docs(storage): report the current format version
polaz Nov 1, 2026
1a6b62d
fix(physical): page installed part projections
polaz Nov 1, 2026
a93b6c4
fix(physical): redact denied binding revisions
polaz Nov 1, 2026
6c94033
fix(physical): recheck received unit admission
polaz Nov 1, 2026
3031c26
fix(ui): reset shifted endpoint review context
polaz Nov 1, 2026
a6d09be
fix(ui): retain the full physical integer range
polaz Nov 1, 2026
7ac64d4
fix(ui): preserve revoked availability profiles
polaz Nov 1, 2026
389f65a
fix(ui): retain committed offer acknowledgments
polaz Nov 1, 2026
ca364be
fix(ui): check recipient bytes before submission
polaz Nov 1, 2026
86d2a8e
fix(ui): bind plan actions to saved step context
polaz Nov 1, 2026
ae61baa
fix(physical): recheck mating at cable completion
polaz Nov 1, 2026
b1980e6
fix(contracts): group physical page limits
polaz Nov 1, 2026
5b96762
fix(ui): preserve fresh plan acknowledgments
polaz Nov 1, 2026
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ including bounded quantities, model alternatives and supported exclusions,
then be refined without changing their identity.
The workspace can [check recorded requirements](docs/inventory.md#recorded-requirements)
against permitted current facts, preserving missing, stale and conflicting evidence.
It includes [physical planning](docs/inventory.md#physical-plans-and-cable-ends) with exact
rack elevations, cable ends, material requirements, reservations and reviewed
component replacement. Manual results remain separate from verified service health.

## License

Expand Down
28 changes: 28 additions & 0 deletions crates/omloom-contracts/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ fn main() -> Result<(), Box<dyn Error>> {
.boxed(".omloom.workspace.v1.Reply.result.detail")
.boxed(".omloom.workspace.v1.Reply.result.vm_placement_review")
.boxed(".omloom.workspace.v1.HostImport.report")
// Keep the request stack bound; allocate this volume only for an explicit coverage assertion.
.boxed(".omloom.workspace.v1.PhysicalDefinition.occupancy_coverage")
.boxed(".omloom.workspace.v1.PhysicalDefinition.rack_grid")
.boxed(".omloom.workspace.v1.PhysicalDefinition.clearance")
.boxed(".omloom.workspace.v1.PhysicalMaterial.physical")
.boxed(".omloom.workspace.v1.PhysicalReplacement.feedback")
.file_descriptor_set_path(&descriptor)
.compile_protos(&[workspace], &["../../proto"])?;
let set = FileDescriptorSet::decode(fs::read(descriptor)?.as_slice())?;
Expand Down Expand Up @@ -67,8 +73,30 @@ fn main() -> Result<(), Box<dyn Error>> {
16
} else if (message.name() == "EvaluateRequirements" && field.name() == "nodes")
|| (message.name() == "RequirementGroup" && field.name() == "members")
|| (message.name() == "PhysicalPlan" && field.name() == "steps")
|| (message.name() == "PhysicalView" && field.name() == "definitions")
|| (message.name() == "PhysicalCompletion"
&& matches!(field.name(), "completed_steps" | "not_performed_steps"))
|| (message.name() == "PhysicalPlan" && field.name() == "materials")
|| (message.name() == "PhysicalMaterial" && field.name() == "allocations")
|| (message.name() == "PhysicalReplacement" && field.name() == "endpoints")
|| (message.name() == "PhysicalEndpointMappings" && field.name() == "pairs")
|| (message.name() == "PhysicalCableEnd" && field.name() == "channels")
|| (message.name() == "PhysicalChannelSet" && field.name() == "channels")
|| (message.name() == "PhysicalDefinition" && field.name() == "channels")
{
64
} else if message.name() == "PhysicalMaterial" && field.name() == "specifications" {
12
} else if message.name() == "PhysicalView"
&& matches!(
field.name(),
"occupancy" | "plans" | "positions" | "replacement_quality"
)
{
25
} else if message.name() == "PhysicalView" && field.name() == "items" {
256
} else {
0
}
Expand Down
53 changes: 31 additions & 22 deletions crates/omloom-contracts/src/equipment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,29 +221,13 @@ fn identity(value: &Option<EquipmentReference>) -> (&str, &str, &str) {
None => ("", "", ""),
}
}
/// One bounded semantic encoding for retries, changed-only storage and CSV.
/// Candidate/exclusion order is irrelevant; source and interpretation basis are not.
pub fn encode(value: &EquipmentClaim) -> Result<Vec<u8>, Error> {
/// Normalize an owned bounded claim for changed-only storage and returned plans.
pub fn canonicalize(value: &mut EquipmentClaim) -> Result<(), Error> {
validate(value)?;
let canonical = match &value.assertion {
Some(equipment_claim::Assertion::Quantity(q)) => {
q.scale == 0
|| q.lower.is_some_and(|n| n % 10 != 0)
|| q.upper.is_some_and(|n| n % 10 != 0)
}
Some(equipment_claim::Assertion::Alternatives(v)) => {
v.candidates.is_sorted_by(|a, b| {
(&a.value, identity(&a.reference)) <= (&b.value, identity(&b.reference))
}) && v.excluded.is_sorted_by(|a, b| {
(&a.value, identity(&a.reference)) <= (&b.value, identity(&b.reference))
})
}
_ => true,
};
if canonical {
return Ok(value.encode_to_vec());
}
let mut value = value.clone();
canonicalize_validated(value);
Ok(())
}
fn canonicalize_validated(value: &mut EquipmentClaim) {
if let Some(equipment_claim::Assertion::Quantity(q)) = &mut value.assertion {
while q.scale > 0
&& q.lower.is_none_or(|n| n % 10 == 0)
Expand All @@ -266,6 +250,31 @@ pub fn encode(value: &EquipmentClaim) -> Result<Vec<u8>, Error> {
(&a.value, identity(&a.reference)).cmp(&(&b.value, identity(&b.reference)))
});
}
}
/// One bounded semantic encoding for retries, changed-only storage and CSV.
/// Candidate/exclusion order is irrelevant; source and interpretation basis are not.
pub fn encode(value: &EquipmentClaim) -> Result<Vec<u8>, Error> {
validate(value)?;
let canonical = match &value.assertion {
Some(equipment_claim::Assertion::Quantity(q)) => {
q.scale == 0
|| q.lower.is_some_and(|n| n % 10 != 0)
|| q.upper.is_some_and(|n| n % 10 != 0)
}
Some(equipment_claim::Assertion::Alternatives(v)) => {
v.candidates.is_sorted_by(|a, b| {
(&a.value, identity(&a.reference)) <= (&b.value, identity(&b.reference))
}) && v.excluded.is_sorted_by(|a, b| {
(&a.value, identity(&a.reference)) <= (&b.value, identity(&b.reference))
})
}
_ => true,
};
if canonical {
return Ok(value.encode_to_vec());
}
let mut value = value.clone();
canonicalize_validated(&mut value);
Ok(value.encode_to_vec())
}

Expand Down
24 changes: 24 additions & 0 deletions crates/omloom-contracts/src/equipment/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
use super::*;

// Owned plans and the persisted encoding must share normalization, including retry order and fixed-point spelling.
#[test]
fn owned_claim_canonicalization_matches_encoding_and_is_idempotent() {
let mut value = possible();
let encoded = encode(&value).expect("valid claim");
canonicalize(&mut value).expect("valid owned claim");
assert_eq!(value.encode_to_vec(), encoded);
let previous = value.clone();
canonicalize(&mut value).expect("already canonical claim");
assert_eq!(value, previous);
let mut quantity = EquipmentClaim {
basis: "Recorded physical measurement".into(),
assertion: Some(equipment_claim::Assertion::Quantity(QuantityRange {
lower: Some(1200),
upper: None,
scale: 2,
unit: "mm".into(),
})),
};
let encoded = encode(&quantity).expect("valid measurement");
canonicalize(&mut quantity).expect("owned measurement");
assert_eq!(quantity.encode_to_vec(), encoded);
}
fn possible() -> EquipmentClaim {
EquipmentClaim {
basis: "Front label and visible bays".into(),
Expand Down
1 change: 1 addition & 0 deletions crates/omloom-contracts/src/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ id!(SourceId);
id!(AuthorityId);
id!(RelationId);
id!(OperationId);
id!(PlanId);
id!(ScanId);
id!(TrustId);
id!(CredentialBindingId);
Expand Down
48 changes: 48 additions & 0 deletions crates/omloom-contracts/tests/workspace.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
use omloom_contracts::{Error, Limits, MemoryBudget, decode_workspace, workspace as api};
use prost::Message;

// Physical wire containers enforce repeated bounds before prost allocates their vectors.
#[test]
fn physical_channels_and_endpoint_maps_are_bounded_before_decode() {
let budget = MemoryBudget::new(16 * 1_048_576);
let channels = api::Request {
working: None,
command: Some(api::request::Command::Physical(api::Physical {
action: Some(api::physical::Action::Define(api::PhysicalDefinitionEdit {
definition: Some(api::PhysicalDefinition {
channels: vec![1; 65],
..Default::default()
}),
})),
})),
}
.encode_to_vec();
assert!(matches!(
decode_workspace(&channels, Limits::default(), &budget),
Err(Error::Limit)
));
assert_eq!(budget.used(), 0);
let mappings = api::Request {
working: None,
command: Some(api::request::Command::Physical(api::Physical {
action: Some(api::physical::Action::Save(api::PhysicalSave {
plan: Some(api::PhysicalPlan {
steps: vec![api::PhysicalStep {
action: Some(api::physical_step::Action::Replacement(
api::PhysicalReplacement {
endpoints: vec![Default::default(); 65],
..Default::default()
},
)),
..Default::default()
}],
..Default::default()
}),
})),
})),
}
.encode_to_vec();
assert!(matches!(
decode_workspace(&mappings, Limits::default(), &budget),
Err(Error::Limit)
));
assert_eq!(budget.used(), 0);
}

// Omitted wire input cannot implicitly request an exclusive allocation.
#[test]
fn network_sharing_requires_an_explicit_mechanism() {
Expand Down
29 changes: 28 additions & 1 deletion crates/omloom-store/src/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,23 @@ use std::{
type Properties = BTreeMap<String, Value>;
type Result<T> = std::result::Result<T, Error>;
const ROOT: &str = "installation";
const SCHEMA_VERSION: u64 = 14;
const SCHEMA_VERSION: u64 = 22;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
const PHYSICAL_TEXT: &[&str] = &["basis", "mounting", "item", "enclosure", "old_item"];
const PHYSICAL_NUMBERS: &[&str] = &[
"material_count",
"expected",
"x_start",
"x_length",
"y_start",
"y_length",
"z_start",
"z_length",
"max_mass_g",
"demand_mw",
"capacity_mw",
"cooling_mw",
"cooling_capacity_mw",
];
const MAX_CHILDREN: usize = 2048;
mod deltas;
mod inventory;
Expand Down Expand Up @@ -374,6 +390,12 @@ impl Store {
}
let mut schema = LabelSchema::new_node_id("OmRow");
schema.add_property(PropertyDef::new("key", PropertyType::String).not_null());
for name in PHYSICAL_TEXT {
schema.add_property(PropertyDef::new(*name, PropertyType::String));
}
for name in PHYSICAL_NUMBERS {
schema.add_property(PropertyDef::new(*name, PropertyType::Int));
}
for name in ["candidate", "cursor", "snapshot"] {
schema.add_property(PropertyDef::new(name, PropertyType::String));
}
Expand Down Expand Up @@ -546,6 +568,11 @@ impl Store {
.keys()
.filter(|key| !current.properties.contains_key(*key))
.any(|key| {
if PHYSICAL_TEXT.contains(&key.as_str())
|| PHYSICAL_NUMBERS.contains(&key.as_str())
{
return false;
}
if [
"issuer",
"subject",
Expand Down
Loading
Loading