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
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ for reference without a full itemized history.

## [Unreleased]

## [0.14.0] - pending tag

Additive, non-breaking release. No public API was removed or changed
incompatibly since `v0.13.0`.

Added:
- `sysml_model`: `ElementId` now documents and recognizes `blake3:` as a
sanctioned content-hash scheme alongside `sha256:` and `git:`. The
newtype itself is unchanged — still `pub struct ElementId(pub String)`,
opaque; this is purely additive.
- `ElementId::HASH_SCHEMES` — the `&'static [&'static str]` of
recognized content-hash / VCS scheme prefixes (`"sha256:"`,
`"blake3:"`, `"git:"`).
- `ElementId::content_hash_scheme()` — the scheme prefix this id
carries if it is content-addressed, else `None`.
- `ElementId::is_content_addressed()` — whether this id is a content /
VCS hash rather than a human-meaningful name.
- The `ElementId` doc comment now lists `blake3:…` among the sanctioned
content / VCS hash forms; the **never numeric** rule is unchanged.

## [0.13.0] - pending tag

Additive, non-breaking release. No public API was removed or changed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ufo-types"
version = "0.13.0"
version = "0.14.0"
edition = "2024"
rust-version = "1.85"
authors = ["Brian Horakh <brian@promptexecution.com>"]
Expand Down
39 changes: 38 additions & 1 deletion src/sysml_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use serde::{Deserialize, Serialize};
///
/// MAY be a human-meaningful name (`"bus-3"`, `"agent.foo"`), a KerML
/// qualified name (`Pkg::Sub::Item`), or a content / VCS hash
/// (`sha256:…`, `git:<blob-sha>`) where an element needs a stable derived
/// (`sha256:…`, `blake3:…`, `git:<blob-sha>`) where an element needs a stable derived
/// identity. It is **never** a numeric id — a random integer breaks the
/// byte-identical, git-diffable artifact model; a derived one is just a less
/// legible string (kr0ki `DESIGN-NOTE-typed-model-layer.md` §2.4).
Expand All @@ -55,6 +55,23 @@ impl ElementId {
pub fn as_str(&self) -> &str {
&self.0
}

/// The recognized content-hash / VCS scheme prefixes an `ElementId` may carry.
pub const HASH_SCHEMES: &'static [&'static str] = &["sha256:", "blake3:", "git:"];

/// If this id is content-addressed, the scheme prefix it uses
/// (`"sha256:"`, `"blake3:"`, `"git:"`), else `None`.
pub fn content_hash_scheme(&self) -> Option<&'static str> {
Self::HASH_SCHEMES
.iter()
.copied()
.find(|p| self.0.starts_with(p))
}

/// Whether this id is a content / VCS hash rather than a name.
pub fn is_content_addressed(&self) -> bool {
self.content_hash_scheme().is_some()
}
}

impl std::fmt::Display for ElementId {
Expand Down Expand Up @@ -521,6 +538,26 @@ mod tests {
assert_eq!(serde_json::from_str::<ElementId>(&json).unwrap(), id);
}

#[test]
fn element_id_content_hash_scheme_detection() {
assert_eq!(eid("blake3:abc123").content_hash_scheme(), Some("blake3:"));
assert!(eid("blake3:abc123").is_content_addressed());

assert_eq!(
eid("sha256:deadbeef").content_hash_scheme(),
Some("sha256:")
);
assert!(eid("sha256:deadbeef").is_content_addressed());

assert_eq!(eid("git:deadbeef").content_hash_scheme(), Some("git:"));
assert!(eid("git:deadbeef").is_content_addressed());

assert_eq!(eid("bus-3").content_hash_scheme(), None);
assert!(!eid("bus-3").is_content_addressed());

assert_eq!(ElementId::HASH_SCHEMES.len(), 3);
}

#[test]
fn element_kind_all_is_complete_and_ordered() {
// Exhaustive match: a new variant fails to compile until it is also
Expand Down
Loading