Skip to content

Check provenance attestation adversarially (F6-F9) - #154

Merged
macanderson merged 4 commits into
mainfrom
feat/attestation-conformance-b726a4bc
Aug 30, 2026
Merged

Check provenance attestation adversarially (F6-F9)#154
macanderson merged 4 commits into
mainfrom
feat/attestation-conformance-b726a4bc

Conversation

@macanderson

@macanderson macanderson commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Pull request

Summary

SPEC.md §6.5's F6–F9 shipped with their "Verified by" column pointing at
contextgraph_types::attest — the implementation's own unit tests. This adds an
attestation conformance check that probes those four guarantees on the wire,
plus five adversarial --misbehave modes in contextgraph-example-docs, one per
forgery the constructions exist to stop.

Closes #89

What changed

  • attestation check (contextgraph-conformance/src/lib.rs). Raw-stdio,
    like the §R1/§E1/§H4 probes and for the same reason: the attestations ride the
    envelope, and Host::query_provider hands back a ContextQueryResult with the
    envelope already discarded. It takes the attester keys the handshake published,
    recomputes each served frame's commitment from the frame in hand, and verifies
    the signature over it in the order §6.5.4 fixes — commitment first, so "the
    frame moved after signing" is never reported as "the key is wrong".
  • Five --misbehave modes in contextgraph-example-docs, each signing one
    thing and serving another.
  • Two optional envelope members (handshake_ack.attester_keys,
    frames.attestations) plus their $defs in
    schema/contextgraph-envelope.schema.json, SPEC.md §6.5.5 with a
    schema-validated example, and the maximal reference vectors populated.
  • SPEC.md §6.5.2 pins provider_id to the handshake-declared
    provider.name — the only identifier both ends of the wire observe. It was
    previously unstated, which would have made the check unimplementable from the
    spec alone.
  • F6–F9's "Verified by" column now names attestation.
  • contextgraph-conformance turns the attestation feature of
    contextgraph-types on. A suite that could not run the verifier would be
    asserting §6.5 rather than checking it. Side effect worth naming: nothing in CI
    built that feature before, so contextgraph-types/tests/attestation_vectors.rs
    — which is #![cfg(feature = "attestation")] — now actually runs in the
    workspace test job.

Evidence

Green path.github/scripts/conformance-green.sh, exit 0:

✓ attestation: recomputed and verified 2 detached attestation(s) over 2 served
  frame(s) against the handshake-published key(s) (§6.5)

All 14 checks passed.

The five modes. Each trips attestation and no other check, with the
verdict named in the evidence string, not merely "some failure":

mode checks tripped observed verdict
forge-signature attestation BadSignature (both frames)
lift-signature attestation CommitmentMismatch on frm_configuration; frm_getting_started verifies
truncate-chain attestation CommitmentMismatch on frm_getting_started
swap-content attestation CommitmentMismatch on frm_getting_started
malformed-attestation attestation MalformedCommitment on frm_getting_started; the other frame stays attested

lift-signature's full evidence, which shows the lift rather than asserting it —
the signed commitment sha256:36ce21… is exactly the commitment
frm_getting_started produces:

frame `frm_configuration` recomputes to sha256:48882c8d… but its attestation
signs sha256:36ce211d… — the frame, its `content_digest`, or its provenance
chain changed after signing (CommitmentMismatch)

The negative direction. Deleting enc_str(&mut preimage, &frame.id) from
frame_commitment — the frame-identity binding — makes lift-signature verify:

PASS :: recomputed and verified 2 detached attestation(s) ...
failed checks: []

and conformance-red.sh goes red naming it:

::error::mode 'lift-signature' passed every check — the suite does not catch it
::error::at least one misbehaviour mode went undetected

Reverted. Separately, corrupting one hex digit of an honest signature turns the
green path's attestation check red with BadSignature.

conformance-red.sh needed no edit: it derives the mode list and each mode's
expected check from the binary's own --help, so the doc comments' "(trips
attestation)" is what wires them. Confirmed — all 26 modes caught, the five new
ones by attestation alone.

Key-less providers still pass (conformance-external.sh treats a skip as a
failure, so this had to be a pass, not a skip): ripgrep, treesitter,
mcp-bridge over the in-repo MCP fixture, and the Python SDK example provider all
report All 14 checks passed, with
attestation: provider publishes no attester key and serves no attestation.

Tests, all scoped per SCR-001: conformance_suite 23/23,
attestation_conformance 5/5 (new), reference_vectors 3/3, plus
examples_roundtrip, stdio_roundtrip, ingest_conformance, usage_report,
golden_fixtures, host_conformance_suite, composition_conformance_suite,
lifecycle_profile_examples, verify_wire, and a -p-scoped run for
contextgraph-host, -types, -refprov, -mcp-bridge, -mcp-server,
-ripgrep, -treesitter, -trace. python3 schema/validate-examples.py OK.
cargo fmt --all --check and cargo clippy --workspace --all-targets -D warnings
both clean.

Coordination with #90

#90 owns the envelope shape for attestations and had not landed, so this
constructs the minimum the check cannot run without: two optional members on
Envelope, their schema $defs, and the §6.5.5 example. It is deliberately the
shape #90's issue text describes ("a place in the frames envelope for per-frame
attestations"). Not built here, and left to #90: the result-set Merkle root
and inclusion proofs on the wire, and the examples/ transcript. If #90 lands
first, reconcile by keeping its member names and re-pointing
attestation_stdio_probe and attestations_for at them — nothing else in this
PR depends on the spelling.

The keys ride the handshake, not the answer, on purpose: a key republished
with every response could be swapped by the same forgery that swapped the
signature, and forge-signature would then verify.

Checklist

  • One logical change per PR (smaller lands faster)
  • Gate is green locally — fmt, clippy -D warnings, test (scoped per SCR-001; see Evidence)
  • A witness test is included, or a reason there isn't one is stated below
  • Docs updated in the same PR if behavior or flags changed (README.md, docs/, doc comments, --help text)
  • All commits signed off (git commit -s, DCO)
  • CHANGELOG.md updated under [Unreleased] if user-visible

Witness tests: contextgraph-conformance/tests/attestation_conformance.rs (5 new)
and 5 new mode tests in tests/conformance_suite.rs. All fail on main, where
neither the check nor the modes exist. an_attestation_lift_differs_only_in_the_frame_id
is the one that matters — it asserts the lift-signature fixture's precondition
rather than trusting it, because a mode that fails for an unrelated reason is a
test that will sit quietly through a real regression.

No test was deleted.

Registry submission (only if adding a row to docs/registry.md)

  • Not applicable — this PR does not add/change a conformance registry entry
  • The exact, reproducible contextgraph-inspect ... --json invocation used to produce the listed report is included below (no self-attested listings — a maintainer must be able to re-run it and get the same result)
  • Every check in the linked report is pass or skip, none fail

The row is not new; its report is regenerated because the suite gained a check.

cargo build -p contextgraph-conformance --bin contextgraph-example-docs
./target/debug/contextgraph-inspect stdio --json -- ./target/debug/contextgraph-example-docs

The regenerated report also repairs pre-existing drift the run surfaced: the
committed copy recorded v0.1.0 while the crate is at 2.0.0.

Protocol-stability impact (if a spec/wire change)

  • Not applicable — no wire or spec change
  • Additive (new optional field/check) — safe within contextgraph/1
  • Wire-breaking — requires contextgraph/2; explain below

Both new members are #[serde(default, skip_serializing_if = "Vec::is_empty")],
so a provider or host that knows nothing about them serializes exactly the bytes
it did before and drops them on receipt (§13 U1). Every existing reference vector
is byte-identical; only the two maximal vectors changed, and only because the
test's contract is that a maximal vector populates every optional field.

SPEC.md §6.5.2's provider_id sentence tightens an existing requirement rather
than adding one — the field was already in the normative preimage with no
statement of what it holds. Per GOVERNANCE.md the witness for both is a
conformance check, which is what this PR is.

License

By submitting this pull request, I agree to dual-license this contribution
under MIT OR Apache-2.0, as certified by my DCO sign-off.

Summary by Sourcery

Add adversarial wire-level provenance attestation verification for F6–F9, including optional envelope support and conformance coverage for honest, forged, and unverifiable attestations.

New Features:

  • Add wire-level provenance attestation conformance coverage for SPEC.md F6–F9.
  • Carry attester keys in handshake acknowledgements and detached frame attestations in frames envelopes.
  • Add five adversarial example-provider modes covering forged signatures, lifted signatures, truncated chains, swapped content, and malformed attestations.

Bug Fixes:

  • Pin frame commitments to the handshake-declared provider name so implementations can compute and verify them consistently.
  • Enable the attestation feature in conformance builds so attestation verification tests execute.

Enhancements:

  • Update the specification, schema, ADR, changelog, registry report, and provider documentation to describe the attestation wire format and conformance coverage.
  • Ensure unverifiable attestations leave frames served as unattested rather than causing them to be dropped.

Documentation:

  • Document optional attestation envelope members, provider identity binding, and adversarial verification evidence.

Tests:

  • Add wire-level attestation tests and adversarial conformance tests that assert the expected verdict and isolate failures to the attestation check.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @macanderson, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 15 hours and 32 minutes by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR moves provenance-attestation verification from implementation self-tests to an adversarial wire-level conformance check, adds five targeted forgery fixtures and tests, carries detached attestations through additive envelope fields, and updates the specification, schema, vectors, and documentation accordingly.

Sequence diagram for wire-level provenance attestation verification

sequenceDiagram
    participant Provider
    participant Connection as RawStdioConnection
    participant Probe as AttestationProbe
    participant Host

    Provider->>Connection: handshake_ack(attester_keys)
    Connection->>Probe: handshake provider.name and attester_keys
    Probe->>Provider: query(sample_query)
    Provider-->>Probe: frames + detached attestations
    Probe->>Probe: recompute frame commitment
    Probe->>Probe: verify_frame_attestation(provider.name, frame, attestation, key)
    alt attestation verifies
        Probe-->>Probe: mark frame attested
    else attestation fails
        Probe->>Host: query_provider(sample_query)
        Host-->>Probe: served frames
        Probe-->>Probe: retain frame as unattested per F9
    end
Loading

Flow diagram for adversarial attestation checks

flowchart TD
    Start[Provider serves frames and attestations] --> Keys{Handshake published attester keys?}
    Keys -- No keys and no attestations --> Pass[Pass: nothing to verify]
    Keys -- Yes --> Recompute[Recompute commitment from served frame]
    Recompute --> Compare{Commitment matches signed commitment?}
    Compare -- No --> Mismatch[CommitmentMismatch or MalformedCommitment]
    Compare -- Yes --> Signature[Verify signature with published key]
    Signature --> Valid{Signature valid?}
    Valid -- Yes --> Verified[Frame attested]
    Valid -- No --> Bad[BadSignature]
    Mismatch --> Retain[Keep frame served as unattested per F9]
    Bad --> Retain
    Verified --> Complete[Conformance result]
    Retain --> Complete
    Pass --> Complete
Loading

File-Level Changes

Change Details Files
Adds a wire-level attestation conformance check that validates detached signatures against handshake-published keys and enforces F6–F9 behavior.
  • Reads attester keys from the handshake and attestations directly from raw stdio envelopes.
  • Recomputes frame commitments using the specified provider identifier and checks commitments before signatures.
  • Reports malformed, unknown, mismatched, and bad-signature outcomes while verifying that unverifiable frames remain served.
  • Covers the check with honest-wire, detachment, verdict-ordering, and F9 regression tests.
contextgraph-conformance/src/lib.rs
contextgraph-conformance/Cargo.toml
contextgraph-conformance/tests/attestation_conformance.rs
contextgraph-conformance/tests/conformance_suite.rs
Introduces five adversarial reference-provider modes that isolate distinct provenance-attestation forgery scenarios.
  • Adds forge-signature, lift-signature, truncate-chain, swap-content, and malformed-attestation modes.
  • Keeps non-attestation conformance checks passing so failures remain attributable to attestation.
  • Adds fixture precondition assertions, including the frame-identity-only lift case and expected verdict strings.
contextgraph-conformance/src/bin/contextgraph-example-docs.rs
contextgraph-conformance/tests/conformance_suite.rs
contextgraph-conformance/tests/attestation_conformance.rs
Extends the protocol envelope with additive detached-attestation transport and propagates the new fields through host and provider implementations.
  • Adds optional handshake attester keys and per-frame detached attestations with empty-default serialization.
  • Stores handshake keys on raw stdio connections and exposes them to the conformance probe.
  • Updates HTTP, stdio, reference-provider, MCP bridge, ingest, and wire tests for the expanded envelope.
contextgraph-host/src/wire.rs
contextgraph-host/src/stdio.rs
contextgraph-host/src/http.rs
contextgraph-host/src/lib.rs
contextgraph-refprov/src/lib.rs
contextgraph-mcp-bridge/src/lib.rs
contextgraph-conformance/src/host_conformance.rs
contextgraph-conformance/tests/ingest_conformance.rs
Documents and validates the F6–F9 wire contract, provider identifier binding, schema additions, and updated reference vectors.
  • Pins provider_id to the handshake-declared provider name and documents the optional envelope members with an example.
  • Updates F6–F9 verification ownership, ADR guidance, changelog, provider documentation, and registry metadata.
  • Adds schema definitions and populates maximal/reference vectors with attestation fields.
SPEC.md
schema/contextgraph-envelope.schema.json
schema/reference-vectors.ndjson
contextgraph-conformance/tests/reference_vectors.rs
docs/adr/0010-provenance-attestation.md
CHANGELOG.md
docs/composition-walkthrough.md
docs/reference-providers.md
docs/registry.md
registry/contextgraph-example-docs.report.json

Assessment against linked issues

Issue Objective Addressed Explanation
#89 Add an adversarial wire-level attestation conformance check that recomputes frame commitments, verifies signatures against handshake-published keys, distinguishes the required F6–F9 verdicts, and preserves frames with unverifiable attestations as unattested.
#89 Extend contextgraph-example-docs with published attester keys, valid detached attestations, and the five required --misbehave modes—forge-signature, lift-signature, truncate-chain, swap-content, and malformed-attestation—with tests proving each mode triggers only attestation and reports the expected failure.
#89 Integrate the new check into the protocol and project validation surface, including optional envelope/schema support, SPEC F6–F9 verification references, CI red/green and external-provider behavior, registry/docs/ADR/CHANGELOG updates, and formatting/lint cleanliness.

Possibly linked issues


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

@macanderson
macanderson force-pushed the feat/attestation-conformance-b726a4bc branch from 2d958f5 to ad2bb23 Compare August 30, 2026 04:32
@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown

SCR-003 DoD check passed — every linked issue's definition of done is fully checked.

@macanderson

Copy link
Copy Markdown
Owner Author

DoD ticked on #89 — every item verified, most of them by this PR's own CI run (33292737181):

  • conformance (green and --misbehave red)All 14 checks passed. including ✓ attestation: recomputed and verified 2 detached attestation(s)…, then all 26 misbehave modes caught, the five new ones each by attestation and nothing else.
  • reference provider (ripgrep), (treesitter), mcp→cgp bridge, and the six SDK provider jobs — all green, so the key-less providers still pass a script that treats a skip as a failure.
  • clippy, rustfmt, test, msrv, schema validates the examples — green.

The one item CI cannot show is the negative direction, since it needs a deliberately broken tree. Deleting enc_str(&mut preimage, &frame.id) from frame_commitment locally made lift-signature verify and turned conformance-red.sh red with ::error::mode 'lift-signature' passed every check — the suite does not catch it; the transcript is in the PR description. Reverted before the commit; git diff shows contextgraph-types/src/attest.rs carries only the chunks_exactas_chunks change.

@macanderson
macanderson force-pushed the feat/attestation-conformance-b726a4bc branch 2 times, most recently from 54bda96 to 532e536 Compare August 30, 2026 05:11
@macanderson

Copy link
Copy Markdown
Owner Author

Rebased onto current main, and a note on the commit I restored

The session that wrote this PR was terminated by a rate limit before it finished. I have rebased the branch onto current main (now including #106, #109, #113, #114 and #131), resolved a CHANGELOG.md conflict, and added a ticked definition of done to issue #89.

One thing worth recording, because it is the kind of claim that deserves the check that contradicted it.

The branch carried a second commit fixing clippy::chunks_exact_to_as_chunks. I judged it redundant — #114 had landed the same as_chunks::<2>() change — and skipped it during the rebase. That was wrong. The commit touched two files:

Skipping the commit wholesale dropped the second half, and cargo clippy -p contextgraph-conformance -- -D warnings failed on decode_hex. 532e536 restores only that site, with the reasoning in the commit message.

The general lesson, for whoever hits this next: a commit is redundant per file, not per commit. git rebase --skip is all-or-nothing, so a commit that fixes one lint in several places needs the surviving hunks reapplied by hand.

Verified locally after the rebase

cargo test -p contextgraph-conformance
  attestation_conformance ... 5 passed; 0 failed
  conformance_suite ....... 23 passed; 0 failed
cargo fmt --check                                                   → clean
cargo clippy -p contextgraph-conformance --all-targets -- -D warnings → clean

The three checks that carry this PR's argument all pass by name: an_attestation_lift_differs_only_in_the_frame_id (the forgery the FrameId binding exists to stop), a_garbage_attestation_leaves_the_frame_served_but_unattested (F9 — an unverifiable attestation degrades a frame, it never disqualifies it), and an_attestation_is_detached_and_never_rides_inside_the_frame_it_signs (F6).

Sourcery

No review ran on this PR. The repository's Sourcery budget (250,000 diff characters per 7 days) is exhausted, so the check reports skipping. That is the budget, not a clean review — there is no ❌ to settle because nothing was produced.

SPEC.md §6.5's F6-F9 shipped with their "Verified by" column pointing at
`contextgraph_types::attest` — the implementation's own unit tests. Every
other guarantee in this protocol earns its credibility from a suite with an
adversarial mode behind it, and a guarantee whose only witness is the
implementation asserting about itself is the self-attestation §11.1 exists
to rule out.

The new `attestation` check reads the wire like the §R1, §E1 and §H4 probes
do: it takes the attester keys the handshake published, recomputes each
served frame's commitment from the frame in hand, and verifies the signature
over it in the order §6.5.4 fixes — commitment first, so "the frame moved
after signing" is never reported as "the key is wrong".

`contextgraph-example-docs` signs what it serves, and grows five
`--misbehave` modes, one per forgery the constructions exist to stop:

  forge-signature       wrong key                    -> BadSignature
  lift-signature        A's signature stapled to B   -> CommitmentMismatch
  truncate-chain        a hidden `derivation` link   -> CommitmentMismatch
  swap-content          other bytes, signed frame id -> CommitmentMismatch
  malformed-attestation garbage                      -> MalformedCommitment

`lift-signature` is the one a plausible implementation really does get
wrong — sign the bare chain head and every frame citing the same source
shares a valid signature. It serves two frames from one backing file so
their chain heads and `content_digest`s are equal and only the frame id
separates their commitments; `an_attestation_lift_differs_only_in_the_frame_id`
asserts that precondition instead of trusting it, because a mode that fails
for an unrelated reason proves nothing. Deleting the identity binding from
`frame_commitment` makes the mode pass and turns `conformance-red.sh` red,
which is the evidence that the check is worth having.

`malformed-attestation` also holds F9: the frame stays served, degraded to
unattested. The probe asks the reference host that question directly rather
than trusting its own bookkeeping, because a host that dropped such frames
would hand any peer a denial-of-service primitive.

Attestations reach the verifier through two optional envelope members
(§6.5.5): `handshake_ack.attester_keys` and `frames.attestations`, detached
per F6. Both are additive within contextgraph/1 — a peer that knows nothing
about them drops them. §6.5.2 now also pins `provider_id` to the
handshake-declared `provider.name`, the only identifier both ends observe.
Issue #90 owns the fuller wire treatment (result-set Merkle roots, inclusion
proofs); this is the minimum the check cannot run without.

A provider that publishes no key and serves no attestation passes: §6.5
makes the construction mandatory and the signing optional, and
`conformance-external.sh` treats a skip as a failure.

Closes #89
clippy 1.98's `chunks_exact_to_as_chunks` fires on `decode_hex`. The
even-length check above the call already rules out a remainder, so `.0`
discards nothing, and `&[u8; 2]` indexes without the bounds check a
`&[u8]` carries.

The sibling fix in `contextgraph-types::attest` landed with #114, so only
this site remained.

Refs #160
@macanderson

Copy link
Copy Markdown
Owner Author

Not merging this yet — it collides with #138 and #140 in a way that needs a decision, not a rebase

I rebased this branch onto current main (now carrying #138 for #90 and #140 for #88/#91) and resolved four textual conflicts. It then failed to compile, and the reason is a genuine design collision rather than anything wrong with the work here:

error[E0252]: the name `FrameAttestation` is defined multiple times
   --> contextgraph-host/src/lib.rs:109:28

There are now three types called FrameAttestation — in contextgraph-types/src/attest.rs (#138, canonical), contextgraph-host/src/trust.rs (#140), and contextgraph-host/src/wire.rs (this PR) — and two wire locations for the same data, because Envelope::Frames carries a result: ContextQueryResult that already has frame_attestations and result_attestation.

Separately, this PR adds attester_keys to Envelope::HandshakeAck, and ADR 0016 — merged an hour ago in #140 — decided against exactly that: keys come from the operator, ssh known_hosts-style, and the protocol specifies no PKI. #130 tracks the TOFU question as open. So that field is not a conflict to resolve; it is a protocol addition contradicting a just-merged decision.

Full analysis and the proposed resolution: #161.

Why I stopped rather than resolved it

I could have picked one of the three types and deleted the others, or dropped the envelope field, and got this green. Both are protocol-visible decisions about a wire format, made by hand at the end of a long session, in someone else's design. This repository holds the wire contract to a higher bar than that, and a wrong choice here is expensive to undo once it is on main and in the published schema.

What is actually finished here

The conformance work — this PR's whole point — is complete and was verified green before the collision surfaced:

attestation_conformance ... 5 passed; 0 failed
conformance_suite ....... 23 passed; 0 failed
cargo fmt --check / clippy -p contextgraph-conformance -D warnings → clean
python3 schema/validate-examples.py → OK

All five --misbehave modes assert their specific expected failure, not merely "not success": forge-signatureBadSignature; lift-signature, truncate-chain, swap-contentCommitmentMismatch; malformed-attestationMalformedCommitment and the frame still served, per F9. an_attestation_lift_differs_only_in_the_frame_id separately asserts the attestation is genuinely valid for frame A before it is lifted, so that mode cannot pass for an unrelated reason.

Issue #89's definition of done is written and ticked against that evidence.

Suggested path

Land #161's unification first — one FrameAttestation, one wire location, attester_keys decided under #130 — then rebase this branch, which should reduce to the conformance changes alone and go green immediately.

Two notes for whoever picks it up. The branch's second commit fixes clippy::chunks_exact_to_as_chunks in contextgraph-conformance::decode_hex; #114 landed the sibling fix in contextgraph-types::attest but not this site, so it is still needed. And use rg --hidden for reference sweeps — plain rg skips .github/**, which cost another agent three missed references today.

@macanderson

Copy link
Copy Markdown
Owner Author

CI is now red on this PR — 9 failing checks, all the same failure. Recording that so the count does not read as nine separate problems:

clippy · conformance (green and --misbehave red) · mcp→cgp bridge
msrv · reference provider (ripgrep) · sdk (go) · sdk (python) ×2 · sdk (typescript) ×2

Every one of those jobs compiles the workspace, and the workspace does not compile:

error[E0252]: the name `FrameAttestation` is defined multiple times
   --> contextgraph-host/src/lib.rs:109:28
error: unused import: `FrameAttestation`

Reproduced locally with cargo clippy -p contextgraph-conformance --all-targets -- -D warnings. It is the collision described in the comment above and filed as #161, not a regression in this branch's own work — the conformance suite was verified green before the rebase brought #138 and #140 together with it.

No action wanted on this PR until #161 lands. Rebasing again will not help; the two definitions have to be collapsed to one first.

@macanderson
macanderson merged commit 7e0a7da into main Aug 30, 2026
29 checks passed
@macanderson
macanderson deleted the feat/attestation-conformance-b726a4bc branch August 30, 2026 05:48
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.

Adversarial conformance check for provenance attestation (F6-F9)

1 participant