fix(sdk): serve verifiable file provenance from the three example providers - #71
Merged
Merged
Conversation
…viders The Python, TypeScript, and Go example-docs fixtures cited file:///docs/… paths that exist on no machine, with placeholder digests (sha256:1111…). provenance-fixture-consistency re-reads the bytes every file provenance names; with nothing locally readable it skips, and conformance-external.sh requires every check green, none skipped — so the three 'sdk is a conformant implementation' CI jobs went red on main. Each example now ships the same two fixture files the Rust reference provider uses, resolves absolute file:// URIs from its own location, and computes the real sha256 over the on-disk bytes at startup — the digest a host re-derives when it re-reads the file (§6.2, §F5). Verified locally: all 13 checks pass for all three providers via .github/scripts/conformance-external.sh.
Reviewer's GuideThis PR makes the Python, TypeScript, and Go SDK example-docs providers serve real, verifiable file provenance by shipping shared fixture markdown files, resolving them to absolute file:// URIs, and computing true sha256 digests from on-disk bytes, aligning the examples with the Rust reference and unbreaking conformance CI. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In all three SDKs, the fixture digest functions silently fall back to hashing empty bytes when the backing file is missing; consider failing fast (e.g., explicit error or process exit) so broken fixtures don't produce misleading but valid digests.
- The Python
_fixture_uriusesos.path.join, which will introduce backslashes on Windows; if cross-platform usage is expected, normalize to POSIX-style paths (e.g.,pathlib.Path(...).as_posix()) before building thefile://URI. - In the TypeScript example, the FIXTURE_DIR resolution has a fallback to a non-existent
fixturesfolder underdist/exampleswhen neither candidate exists; consider throwing an error if no candidate directory is found instead of silently using a likely-missing path.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In all three SDKs, the fixture digest functions silently fall back to hashing empty bytes when the backing file is missing; consider failing fast (e.g., explicit error or process exit) so broken fixtures don't produce misleading but valid digests.
- The Python `_fixture_uri` uses `os.path.join`, which will introduce backslashes on Windows; if cross-platform usage is expected, normalize to POSIX-style paths (e.g., `pathlib.Path(...).as_posix()`) before building the `file://` URI.
- In the TypeScript example, the FIXTURE_DIR resolution has a fallback to a non-existent `fixtures` folder under `dist/examples` when neither candidate exists; consider throwing an error if no candidate directory is found instead of silently using a likely-missing path.
## Individual Comments
### Comment 1
<location path="sdk/python/examples/example_docs.py" line_range="38-43" />
<code_context>
+FIXTURE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures")
+
+
+def _fixture_uri(file: str) -> str:
+ """The absolute ``file://`` URI a host re-reads to verify a frame's
+ provenance digest (``provenance-fixture-consistency``). Absolute and
+ cwd-independent, so verification never depends on the host's working
+ directory."""
+ return "file://" + os.path.join(FIXTURE_DIR, file)
+
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Normalize fixture URIs to valid `file://` URLs across platforms.
On POSIX this yields valid `file:///...` URLs, but on Windows `os.path.join` produces backslashes and `file://C:\...`, which is not a valid file URI and may fail when round-tripped or consumed by RFC-compliant clients. Consider using `pathlib.Path(FIXTURE_DIR, file).absolute().as_uri()` (or normalizing separators and enforcing a `file:///` prefix) so provenance URIs are portable and aligned with the TS/Go implementations.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- CHANGELOG: contextgraph-types/host/conformance 0.1.0 and contextgraph-sdk 0.1.0 are live, each verified against the real registry (external scratch crate compiles; installed PyPI package passes all 13 conformance checks). - sdk/PUBLISHING.md: flip the PyPI row to published; note the post-publish smoke copy needs the example's fixtures/ directory now that provenance digests are computed from real files. - README: drop the 'badges read not-found until published' callout. - sdk/python/README: drop the 'not yet published' install caveat.
macanderson
added a commit
that referenced
this pull request
Aug 1, 2026
…og, and backfill the gaps (#73) CHANGELOG.md relied on every PR remembering to write its own [Unreleased] entry. An audit of the 22 merges since v0.1.0 whose numbers never appear in the file found 9 user-visible changes with no entry at all — including the OCP -> CGP rename itself, the repo's biggest breaking change. The Unreleased section had also accumulated duplicate category headings (two '### Added', two '### Changed', two '### Fixed') from PRs appending their own blocks. Go-forward: .github/workflows/changelog.yml watches pushes to main. When a merge lands without touching CHANGELOG.md, it drafts the missing entries from the merge's actual diff (.github/scripts/changelog-ai.sh, Vercel AI Gateway, degrade-open: no key or a failed call is a log line, never a red check) and proposes them as a bot/changelog PR — a draft for human review, never a direct push. The gap is measured from the last commit that touched CHANGELOG.md, so merging the bot PR resets it, and each run regenerates the whole current gap, so a superseded bot PR loses nothing. Backfill: entries for the rename (#1), frame identity/composition/usage reports (#32), golden wire fixtures (#35), ADR 0007 (#61, #27), composition conformance + the canary scheduled-run gate (#70) — written from each PR's diff, in the file's existing voice. Three further audit hits (#68, #69, #71) turned out to be already covered by newer entries and were left alone. Duplicate category headings merged: one heading per category, Keep-a-Changelog order.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Main's CI is red on the three sdk … is a conformant implementation jobs (python, typescript, go). The new
provenance-fixture-consistencycheck re-reads the bytes everyfileprovenance names; the SDK examples citedfile:///docs/…paths that exist on no machine with placeholder digests (sha256:1111…), so the check had nothing locally readable to verify and skipped — andconformance-external.shrequires every check green, none skipped.How
Mirror the Rust reference provider's approach in each SDK example:
getting-started.md,configuration.md) under each example'sfixtures/directory.file://URIs from the example's own location (__file__/import.meta.url/runtime.Caller(0)), cwd-independent.content_digestand the provenance digest — the digest a host re-derives when it re-reads the file (§6.2, §F5), so it can never drift from the bytes the URI names.Ranges (
L1-40/L1-25) clamp to EOF in the host's verifier, addressing the whole file — matching the whole-file digest, exactly as the Rust example does.Verification
Ran
.github/scripts/conformance-external.shlocally against all three fixed examples — all 13 checks pass for each, includingprovenance-fixture-consistency("re-read and re-hashed 2 file-provenance digest(s) against the bytes on disk — all match").Summary by Sourcery
Make the SDK example providers serve real, verifiable file-backed documentation so conformance provenance checks pass across languages.
New Features:
Bug Fixes:
Documentation: