Skip to content

[4/n] add stricter typing in JsonPathStack#15

Merged
sunshowers merged 11 commits into
mainfrom
sunshowers/spr/2n-add-stricter-typing-in-jsonpathstack
May 12, 2026
Merged

[4/n] add stricter typing in JsonPathStack#15
sunshowers merged 11 commits into
mainfrom
sunshowers/spr/2n-add-stricter-typing-in-jsonpathstack

Conversation

@sunshowers
Copy link
Copy Markdown
Contributor

A JsonPathStack always has an endpoint at the bottom and a series of schemas above that. We're going to rely on this in upcoming work -- express this constraint in the type system.

Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1

[skip ci]
@sunshowers sunshowers changed the title [2/n] add stricter typing in JsonPathStack [3/n] add stricter typing in JsonPathStack Feb 6, 2026
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1

[skip ci]
Created using spr 1.3.6-beta.1
Copy link
Copy Markdown
Collaborator

@ahl ahl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't look very carefully; please let me know if something needs particular scrutiny

Comment thread src/lib.rs
Comment thread src/path.rs Outdated
@sunshowers sunshowers changed the base branch from sunshowers/spr/main.2n-add-stricter-typing-in-jsonpathstack to main May 5, 2026 01:05
sunshowers added a commit that referenced this pull request May 5, 2026
Detect cycles by checking for path segments (with a trailing `/`) rather than just using a raw string prefix. We hit this in Omicron where `AuditLogEntry` was incorrectly detected as a prefix of `AuditLogEntryActor`, hiding incompatible changes.

This is a minimal fix that (I believe) is correct given the current structure. I'm reworking this in #15 to have stronger types so we can think about this in a more principled manner.
sunshowers added 2 commits May 8, 2026 15:42
Created using spr 1.3.6-beta.1

[skip ci]
@sunshowers sunshowers changed the base branch from main to sunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstack May 8, 2026 22:42
@sunshowers sunshowers changed the title [3/n] add stricter typing in JsonPathStack [4/n] add stricter typing in JsonPathStack May 8, 2026
@sunshowers sunshowers changed the base branch from sunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstack to main May 8, 2026 22:44
@sunshowers sunshowers changed the base branch from main to sunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstack May 8, 2026 22:44
sunshowers added 2 commits May 8, 2026 16:41
Created using spr 1.3.6-beta.1

[skip ci]
Created using spr 1.3.6-beta.1
Comment thread src/compare.rs
Comment on lines +69 to +81
/// Lifecycle of a schema comparison, keyed by `VisitedKey` in
/// [`Compare::visit_state`].
#[derive(Clone, Debug)]
pub(crate) enum VisitState {
/// Comparison is in progress somewhere up the call stack. Re-entering a
/// key in this state means the schema graph has a cycle.
Visiting,
/// Comparison has completed.
Completed {
/// Whether the two schemas were determined to be equal.
equal: bool,
},
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this PR I replaced the existing cycle detection check, which relied on looking at the stack of schemas, with a more explicit DFS postorder check.

This is equivalent to the old code:

        if old_schema.context().stack().contains_cycle()
            && new_schema.context().stack().contains_cycle()
        {
            return Ok(true);
        }

Why? Basically because having a prefix in the stack is equivalent to being in the visiting state while performing the DFS. The tests added in #23 don't have any output differences, which is a reasonable sign that there aren't any behavior changes here.

I like how explicit the postorder check is, and it also fits quite nicely into visit_state.

Comment thread src/schema.rs
Comment on lines +205 to +217
// Returning `true` on `Visiting` is sound only because the compare
// methods call `schema_push_change` eagerly on detecting a change
// rather than making decisions based on the value returned from this
// function. If that weren't the case -- for example, if there were
// code which did something like:
//
// let inner_eq = self.compare_schema(...)?;
// if !inner_eq {
// self.schema_push_change(...);
// }
//
// Then, relying on `true` here would result in a false negative.
// This invariant must be upheld by all compare methods.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note this block -- the old code also returned true, which is correct, but I wanted to reason about this more clearly.

sunshowers added a commit that referenced this pull request May 12, 2026
Rename `tests/cases/cycle-shared-prefix` to `tests/cases/cycle-detection` to reflect the broader scope, and extend the fixture with a few different kinds of cycles:

- mutual recursion through `$ref`
- three-way cycle
- mutual recursion through `allOf` wrappers
- asymmetric tests where the old and new schemas have different shapes

Also add tests to verify outputs. (We're going to rework cycle detection a bit in #15 and want to ensure that PR doesn't introduce any behavior changes.)
@sunshowers sunshowers changed the base branch from sunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstack to main May 12, 2026 17:06
Created using spr 1.3.6-beta.1
@sunshowers sunshowers merged commit 8974df2 into main May 12, 2026
8 checks passed
@sunshowers sunshowers deleted the sunshowers/spr/2n-add-stricter-typing-in-jsonpathstack branch May 12, 2026 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants