fix: preserve literal namespace components across evaluation paths - #827
Maksym (maksym-mishchenko) wants to merge 2 commits into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Maksym (@maksym-mishchenko) Can you add a test of integer/number package components e.g. "1", "1.0". IIRC, OPA has some strange semantics around those, in the package name context or as part of input. |
|
Can you back up your current branch and try a small prototype of the following: As Regorus evolved, there is bit of path related logic has become scattered, and this PR is a good opportunity to centralize it. We could introduce structural path types, roughly along these lines: #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(crate) enum StaticPathComponent {
/// `.foo` and `["foo"]` have the same structural identity.
String(Rc<str>),
Number(Number),
Bool(bool),
Null,
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(crate) struct StaticPath {
components: Box<[StaticPathComponent]>,
}
/// Components declared after `package`; excludes the implicit `data` root.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(crate) struct PackagePath(StaticPath);
/// Complete, statically known rule identity, rooted at `data`.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(crate) struct RulePath(StaticPath);
impl PackagePath {
fn from_ref(expr: &Expr) -> Result<Self>;
fn parse(text: &str) -> Result<Self>;
fn to_rule_path(&self, rule: &StaticPath) -> Result<RulePath>;
fn canonical(&self) -> Result<String>;
}
impl RulePath {
fn parse(text: &str) -> Result<Self>;
fn canonical(&self) -> Result<String>;
fn parent(&self) -> Option<Self>;
fn starts_with(&self, prefix: &Self) -> bool;
fn components(&self) -> &[StaticPathComponent];
}The above types would capture static paths; dynamic paths can be addressed later. Could you see how much of the minimum logic needed for this PR can be moved behind types like these? If the change remains reasonably contained, I would strongly prefer the typed approach. If it expands the scope too much, we can retain the current implementation for this PR and use the prototype as something to be revisited later. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
I loaded packages |
|
I put the package and rule-path parsing behind typed path objects in the prototype. Parsing, formatting, and prefix checks passed for string, number, boolean, and null components. Rule storage still uses string keys, so I’d leave that larger change out of this PR. |
Summary
I preserve literal string components in canonical package and rule paths, so
graph.defUniqueName["1.0.0"]remains distinct from nested namespaces. Canonical paths work across metadata, direct and compiled interpreter evaluation, and RVM without ambiguous flattened aliases.The regressions cover defaults and Undefined, escaped components, imports and functions, dynamic lookup, numeric-key precedence and mixed base/virtual data, long configured target paths, serialization, and reused execution in both modes. Public signatures and serialized program layout stay unchanged; related grammar and API documentation describe the canonical notation.
Validation
cargo xtask ci-debug --frozen, formatting and strict Clippy passed.Evidence limits
Native OPA parity remains unverified; pinned OPA v1.2.0 fixtures are not a native comparison. Shared FFI and C# runtime tests passed earlier in local acceptance but were not rerun after the last two isolated fixes. No latest-DLL or all-nine binding runtime validation is claimed. The unsupported no-default
rvm,arcwithoutstdcombination remains an unchanged baseline exception.