Skip to content

Worktree spec schema conformance - #76

Open
macanderson wants to merge 4 commits into
mainfrom
worktree-spec-schema-conformance
Open

Worktree spec schema conformance#76
macanderson wants to merge 4 commits into
mainfrom
worktree-spec-schema-conformance

Conversation

@macanderson

@macanderson macanderson commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Spec Conformance Tooling

Extends schema validation and conformance around worktree spec examples, enforces previously un-checked protocol rules, and adds regression guards to keep the JSON Schema, Rust types, and SPEC examples in sync.

Flow diagram for extended schema/validate-examples.py checks

flowchart TD
    ROOT["Run validate-examples.py"] --> EXAMPLES["Validate examples/ messages against schema"]
    EXAMPLES --> VECTORS["Validate reference-vectors.ndjson against schema"]
    VECTORS --> SPEC["Validate SPEC.md fenced jsonc examples"]
    SPEC --> IDCHECK["Fetch schema $id URL and compare bytes to local schema"]
    IDCHECK --> RESULT["Exit 0 if all checks pass, else 1"]
Loading

File-Level Changes

Change Details Files
Extend schema example validator to cover SPEC.md jsonc blocks and enforce schema $id byte-identical dereference.
  • Updated validator docstring to describe validation of examples/, reference vectors, SPEC.md fenced examples, and schema $id resolution.
  • Added regex-based placeholder replacement and comment-stripping logic to normalize jsonc SPEC examples into valid JSON before validation.
  • Parsed SPEC.md for ```jsonc fenced blocks, decoded each JSON value, and validated envelopes against the root schema and bare payloads against ContextFrame $defs.
  • Reported clear failure messages for missing fences, parse errors, and validation failures, ensuring SPEC examples stay schema-conformant.
schema/validate-examples.py
Enforce frame-validity rules for relation.target_uri and frame.content_digest and add targeted conformance tests.
  • Imported Relation type into golden fixtures tests and added tests that ensure frame-validity rejects relations with empty/whitespace target_uri (SPEC §G2) and malformed content_digest values (SPEC §D1).
  • Extended Relation with has_target_uri helper mirroring schema minLength constraint, and ContextFrame with has_usable_content_digest helper matching protocol digest form requirements, plus unit tests.
  • Updated check_frames to call these helpers, reject non-usable content_digest and empty target_uri, and include explicit §D1/§G2 messages while updating the success evidence string to mention "labelled and targeted relations".
contextgraph-conformance/tests/golden_fixtures.rs
contextgraph-types/src/frame.rs
contextgraph-conformance/src/lib.rs
Add regression guard tying ContextQuery serialization to schema required keys and fix docs/spec discrepancies around ids and capabilities.
  • Generalized helper to read required keys for any $defs entry, then added a test ensuring an unfiltered, unanchored ContextQuery still satisfies all schema-required keys, guarding against schema/serializer drift.
  • Updated changelog with detailed notes about SPEC §9 verify example schema failures, the ContextQuery required regression guard, and enforcement of §G2/§D1 plus corrected host wire docs.
  • Clarified wire-layer documentation to state correlation is negotiated via Capabilities::correlation and hosts must not send ids to providers that did not declare correlation, and that verify/verified correlate by full frame identity without ids.
  • Fixed SPEC verify/verified examples by removing illegal id fields so they match the schema and reference envelope types.
contextgraph-conformance/tests/ingest_conformance.rs
CHANGELOG.md
contextgraph-host/src/wire.rs
SPEC.md

Possibly linked issues

  • #P0: PR implements systemic schema/serializer conformance checks (SPEC.md and reference vectors) and guards ContextQuery required keys, directly addressing the issue.

Three defects, all the same shape: a normative claim nothing checked.

1. SPEC.md §9's `verify` example was invalid against the schema SPEC.md
   ships. Both envelopes carried `"id": "v1"`, but §3.2 grants an `id` only
   to `query`/`frames`/`error`, `Envelope::Verify`/`Verified` have no such
   field, and the schema is `additionalProperties: false`. Removed — verify
   correlates by full frame identity, not by envelope id.

   Root cause: validate-examples.py checked `examples/` but never SPEC.md,
   so the one example surface with no machine check was the one that
   drifted. It now validates every fenced jsonc block in SPEC.md (comments
   and documented placeholders normalized; structure checked), so CI's
   existing `schema` job catches this class. Verified by re-introducing the
   `id`: the harness fails both envelopes and exits non-zero.

2. An ordinary ContextQuery was un-representable in conformant JSON.
   `kinds` and `anchors` were `required` while both are
   skip_serializing_if = "Vec::is_empty", so an unfiltered, unanchored
   query failed validation — the bug PR #44 fixed for ContextFrame, one
   type over. A test now asserts an ordinary query satisfies the schema's
   own `required` array (reads the schema, so it cannot drift), and a
   cross-audit of all 16 shared types confirms no other type demands a
   field its serializer elides.

3. §G2 claimed "Verified by frame-validity" while `target_uri` appeared
   nowhere in the conformance or validation code — the self-attestation
   §11.1 exists to reject. Implemented rather than downgraded: check_frames
   now rejects an edge with an empty target_uri.

   Auditing the other ten rules citing frame-validity found §D1 unenforced
   too: the frame's own content_digest was never format-checked, and the
   evidence string claimed "well-formed digests" while accepting
   `sha256:abc` — the very placeholder validate.rs exists to reject. Also
   fixed; the remaining nine were confirmed enforced.

Both new checks are mutation-tested: disabling either makes its test fail.

Also corrects contextgraph-host::wire, which said correlation is
"negotiated by observation, not by a capability flag" — contradicting
§3.2 and the shipped Capabilities::correlation, and inverting a MUST NOT.

cargo test --workspace: 243 passed, 0 failed. fmt, clippy -D warnings,
validate-examples.py, and conformance-{green,red}/host all pass.
Signed-off-by: Mac Anderson <mac@oxagen.sh>
Resolving the conflict with #63 kept this branch's version of
`schema/validate-examples.py` wholesale, silently discarding both checks
#63 had added to it on main:

  * the reference-SERIALIZED vector validation (issue #54) — the half that
    catches schema/serializer disagreement, which curated examples cannot;
  * the `$id` + served-copy check, asserting `$id` names the live domain
    and `site/public/schema/` is byte-identical to the source.

Neither loss was visible in CI: both are additive validations, so deleting
them removes coverage without failing anything. The PR was green with the
checks gone.

The second loss was not merely theoretical. This branch had edited the
ContextQuery `$comment`, so the served copy under `site/public/schema/`
had already drifted from the source — the exact "stale schema that still
resolves" failure #63's comment warns about. The merge introduced the
drift and deleted the detector in one move. Restoring the check fails
immediately on it, which is how the drift was found.

Also drops this branch's ContextQuery `required` edit in favour of main's.
#63 fixed that bug independently and identically; its `$comment` is the
better of the two (it names the conformance suite's own sample_query and
records that absence and  mean the same thing). `schema/` is now
byte-identical to main, and the CHANGELOG entry is reworded to claim only
what this branch still contributes: the regression test and the
cross-audit, not the schema change.

Section numbering reconciled: 1-2 examples/, 3 reference vectors,
4 SPEC.md, 5 schema identity.

validate-examples.py: 39 checks pass (24 before the merge, 0 dropped).
cargo test --workspace: 292 passed, 0 failed. fmt, clippy -D warnings, and
conformance-{green,red}/host all pass.
sourcery-ai[bot]

This comment was marked as low quality.

@sourcery-ai

sourcery-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Reviewer's Guide

Extends schema validation and conformance around worktree spec examples, enforces previously un-checked protocol rules, and adds regression guards to keep the JSON Schema, Rust types, and SPEC examples in sync.

Flow diagram for extended schema/validate-examples.py checks

flowchart TD
    ROOT["Run validate-examples.py"] --> EXAMPLES["Validate examples/ messages against schema"]
    EXAMPLES --> VECTORS["Validate reference-vectors.ndjson against schema"]
    VECTORS --> SPEC["Validate SPEC.md fenced jsonc examples"]
    SPEC --> IDCHECK["Fetch schema $id URL and compare bytes to local schema"]
    IDCHECK --> RESULT["Exit 0 if all checks pass, else 1"]
Loading

File-Level Changes

Change Details Files
Extend schema example validator to cover SPEC.md jsonc blocks and enforce schema $id byte-identical dereference.
  • Updated validator docstring to describe validation of examples/, reference vectors, SPEC.md fenced examples, and schema $id resolution.
  • Added regex-based placeholder replacement and comment-stripping logic to normalize jsonc SPEC examples into valid JSON before validation.
  • Parsed SPEC.md for ```jsonc fenced blocks, decoded each JSON value, and validated envelopes against the root schema and bare payloads against ContextFrame $defs.
  • Reported clear failure messages for missing fences, parse errors, and validation failures, ensuring SPEC examples stay schema-conformant.
schema/validate-examples.py
Enforce frame-validity rules for relation.target_uri and frame.content_digest and add targeted conformance tests.
  • Imported Relation type into golden fixtures tests and added tests that ensure frame-validity rejects relations with empty/whitespace target_uri (SPEC §G2) and malformed content_digest values (SPEC §D1).
  • Extended Relation with has_target_uri helper mirroring schema minLength constraint, and ContextFrame with has_usable_content_digest helper matching protocol digest form requirements, plus unit tests.
  • Updated check_frames to call these helpers, reject non-usable content_digest and empty target_uri, and include explicit §D1/§G2 messages while updating the success evidence string to mention "labelled and targeted relations".
contextgraph-conformance/tests/golden_fixtures.rs
contextgraph-types/src/frame.rs
contextgraph-conformance/src/lib.rs
Add regression guard tying ContextQuery serialization to schema required keys and fix docs/spec discrepancies around ids and capabilities.
  • Generalized helper to read required keys for any $defs entry, then added a test ensuring an unfiltered, unanchored ContextQuery still satisfies all schema-required keys, guarding against schema/serializer drift.
  • Updated changelog with detailed notes about SPEC §9 verify example schema failures, the ContextQuery required regression guard, and enforcement of §G2/§D1 plus corrected host wire docs.
  • Clarified wire-layer documentation to state correlation is negotiated via Capabilities::correlation and hosts must not send ids to providers that did not declare correlation, and that verify/verified correlate by full frame identity without ids.
  • Fixed SPEC verify/verified examples by removing illegal id fields so they match the schema and reference envelope types.
contextgraph-conformance/tests/ingest_conformance.rs
CHANGELOG.md
contextgraph-host/src/wire.rs
SPEC.md

Possibly linked issues

  • #P0: PR implements systemic schema/serializer conformance checks (SPEC.md and reference vectors) and guards ContextQuery required keys, directly addressing the issue.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Signed-off-by: Mac Anderson <mac@oxagen.sh>
@macanderson macanderson self-assigned this Aug 10, 2026
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.

1 participant