Skip to content

test: add golden wire-contract fixtures and breaking-change CI guard - #332

Merged
t0k0sh1 merged 2 commits into
mainfrom
golden-wire-contract-fixtures
Jul 31, 2026
Merged

test: add golden wire-contract fixtures and breaking-change CI guard#332
t0k0sh1 merged 2 commits into
mainfrom
golden-wire-contract-fixtures

Conversation

@t0k0sh1

@t0k0sh1 t0k0sh1 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

  • Pins the current http_contract: 1 / mcp_contract: 1 wire shapes as machine-readable golden fixtures under tests/fixtures/wire/ (ADR 0005 §9), including retrieval: add optional cross-lane reranking and token-budgeted evidence assembly #216's evidence-assembly package (POST /contexts/{name}/evidence, assemble_evidence) — 20 fixtures across 13 HTTP/MCP operations, generated from a live server and verified/regenerated via tests/http_api/contract.rs (TAGURU_UPDATE_WIRE_FIXTURES=1 cargo test --test http_api contract).
  • Rust, Python (sdk/python/tests/unit/test_wire_contract.py), and TypeScript (sdk/typescript/tests/unit/wire-contract.test.ts) all read the same committed fixtures.
  • New sdk/spec/check_contract.py classifies fixture changes against a base ref per ADR 0005 §4's compatible/breaking table and fails unless a breaking change lands beside a matching HTTP_CONTRACT/MCP_CONTRACT bump in src/api.rs. Wired into a new contract-guard job in .github/workflows/ci.yml.
  • tests/fixtures/wire/README.md documents the update/classification procedure; CONTRIBUTING.md and CHANGELOG.md updated accordingly.

Closes #301

Test plan

  • cargo fmt --check / cargo clippy --all-targets --locked -- -D warnings / cargo test --locked (full suite, incl. the new 19 contract::* tests)
  • python sdk/spec/check_contract.py --check and --base origin/main
  • Manually verified the guard actually catches a breaking change and requires a contract-version bump (simulated removing fused_rank from the evidence response, confirmed detection, then reverted)
  • python -m pytest sdk/python/tests -q (153 passed)
  • npm test --workspace=taguru (148 passed), npm run typecheck, npm run lint, npm run check:surface --workspace=taguru
  • python sdk/spec/check_versions.py

https://claude.ai/code/session_011KBpNVCCcdTUtCuPdpXh2n

Summary by CodeRabbit

  • New Features

    • Added comprehensive HTTP and MCP wire-contract fixtures covering successful operations, errors, tool schemas, and edge cases.
    • Added automated validation to detect incompatible contract changes and require version updates when needed.
  • Documentation

    • Documented fixture structure, regeneration, validation, and contract-update requirements.
  • Tests

    • Added cross-language tests validating fixture coverage, response decoding, required fields, and enumerated values.

…301)

Pins the current http_contract: 1 / mcp_contract: 1 wire shapes as
machine-readable fixtures under tests/fixtures/wire/ (ADR 0005 §9),
including #216's evidence-assembly package. Rust generates and
verifies them against a live server (tests/http_api/contract.rs);
Python and TypeScript read the same files (sdk/python/tests/unit/
test_wire_contract.py, sdk/typescript/tests/unit/wire-contract.test.ts).
New sdk/spec/check_contract.py classifies fixture changes against a
base ref per ADR 0005 §4 and fails CI (new contract-guard job) unless
a breaking change lands beside a matching HTTP_CONTRACT/MCP_CONTRACT
bump.

Claude-Session: https://claude.ai/code/session_011KBpNVCCcdTUtCuPdpXh2n
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 20 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0d738ce0-235e-498c-98f8-e5cc9cf89aa3

📥 Commits

Reviewing files that changed from the base of the PR and between aefd0fc and 4ad884e.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • Cargo.toml
  • sdk/python/tests/unit/test_check_contract.py
  • sdk/spec/check_contract.py
  • sdk/typescript/tests/unit/wire-contract.test.ts
  • tests/fixtures/wire/shapes.json
  • tests/http_api/contract.rs
📝 Walkthrough

Walkthrough

This change adds shared HTTP and MCP wire-contract fixtures, Rust/Python/TypeScript validation, structural compatibility checks, contract-version enforcement, and a CI job for fixture consistency and breaking changes.

Changes

Wire-contract coverage and enforcement

Layer / File(s) Summary
Contract test harness
tests/http_api/contract.rs, tests/http_api/main.rs
Rust integration tests generate and compare normalized HTTP and MCP fixtures. They cover probes, search, evidence assembly, errors, MCP tools, enums, and required request fields.
Committed contract corpus
tests/fixtures/wire/http/*, tests/fixtures/wire/mcp/*, tests/fixtures/wire/shapes.json, tests/fixtures/wire/README.md
Added representative HTTP and MCP fixtures, shape metadata, enum declarations, required routes, and fixture workflow documentation.
Compatibility guard and CI wiring
sdk/spec/check_contract.py, .github/workflows/ci.yml, CHANGELOG.md, CONTRIBUTING.md
Added self-consistency checks, base-reference structural diffs, breaking-change classification, contract-version checks, CI execution, and project documentation.
Cross-SDK fixture validation
sdk/python/tests/unit/test_wire_contract.py, sdk/typescript/tests/unit/wire-contract.test.ts
Python and TypeScript tests validate the shared corpus, decode typed operations through SDK paths, and check enum values against shapes.json.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant ContractGuard
  participant GitBase
  participant SDKTests
  CI->>ContractGuard: validate current fixtures
  ContractGuard-->>CI: return consistency status
  CI->>ContractGuard: compare against base reference
  ContractGuard->>GitBase: load historical fixtures and shapes
  GitBase-->>ContractGuard: return base contract data
  ContractGuard-->>CI: return compatibility and version status
  CI->>SDKTests: run Python and TypeScript contract tests
  SDKTests-->>CI: return decoding and enum validation results
Loading

Possibly related PRs

  • t0k0sh1/taguru#326: Introduced the wire-contract inventory, compatibility rules, and versioning policy enforced here.
  • t0k0sh1/taguru#331: Introduced the HTTP /evidence endpoint and MCP assemble_evidence tool covered by these fixtures.
  • t0k0sh1/taguru#327: Introduced version and contract schemas covered by the version fixtures and validation.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the addition of golden wire-contract fixtures and the breaking-change CI guard.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch golden-wire-contract-fixtures

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

70-80: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Avoid interpolating ${{ }} expressions directly into run: shell blocks.

Both the base-ref detection step and the breaking-change guard step interpolate GitHub Actions expressions directly into shell scripts:

echo "ref=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_OUTPUT"
...
run: python3 sdk/spec/check_contract.py --base "${{ steps.base.outputs.ref }}"

zizmor flags Line 79 as a template-injection risk. github.event.pull_request.base.sha is a git SHA and steps.base.outputs.ref is derived from it or the literal HEAD^, so the immediate risk is low. Still, the standard mitigation is to pass these through env: and reference the environment variable inside the script, so no GitHub Actions expression is ever substituted into shell text before the shell parses it — this keeps the pattern safe even if a future edit changes what feeds base.sha-like values.

🔒 Proposed fix
       - name: Determine base ref
         id: base
+        env:
+          PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
         run: |
-          if [ -n "${{ github.event.pull_request.base.sha }}" ]; then
-            echo "ref=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_OUTPUT"
+          if [ -n "$PR_BASE_SHA" ]; then
+            echo "ref=$PR_BASE_SHA" >> "$GITHUB_OUTPUT"
           else
             echo "ref=HEAD^" >> "$GITHUB_OUTPUT"
           fi
       - name: Breaking-change guard
-        run: python3 sdk/spec/check_contract.py --base "${{ steps.base.outputs.ref }}"
+        env:
+          BASE_REF: ${{ steps.base.outputs.ref }}
+        run: python3 sdk/spec/check_contract.py --base "$BASE_REF"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 70 - 80, Update the “Determine base
ref” and “Breaking-change guard” steps to pass GitHub Actions expressions
through each step’s env configuration, then reference the resulting environment
variables inside the shell command or script. Remove direct ${{ }} interpolation
from the run blocks while preserving the existing base SHA/HEAD^ selection and
check_contract.py invocation.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/spec/check_contract.py`:
- Around line 54-70: The collect_by_path traversal must unwrap MCP pass-through
responses by parsing each content[].text string before continuing to nested
paths such as response.result, while preserving normal object and array
traversal. Apply the equivalent change to the TypeScript collector, and update
http_fixtures() in tests/http_api/contract.rs to include MCP fixtures if
required for shapes.json validation.
- Around line 231-249: Update classify_request so required-field promotion only
applies when the finding_path is a direct top-level request field, matching the
required entry by its exact path rather than only the final segment; preserve
existing behavior for genuine top-level additions. Add focused pytest coverage
for the nested request.filter.query collision, documented
classify/classify_request behavior, diff_shapes container-shape changes, and
field additions/removals.

In `@tests/fixtures/wire/shapes.json`:
- Around line 47-60: Add the missing response.result.omitted[].kind enum
declaration alongside the existing response.result.items[].kind entry, using the
identical allowed values: association, passage, and community.

In `@tests/http_api/contract.rs`:
- Around line 48-86: Add rust-version = "1.88" to the workspace package
configuration to declare the compiler minimum required by the let-chain syntax
in normalize_volatile; do not alter the normalization logic.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 70-80: Update the “Determine base ref” and “Breaking-change guard”
steps to pass GitHub Actions expressions through each step’s env configuration,
then reference the resulting environment variables inside the shell command or
script. Remove direct ${{ }} interpolation from the run blocks while preserving
the existing base SHA/HEAD^ selection and check_contract.py invocation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 54efed42-3919-40d6-b1bd-f83ca45d845c

📥 Commits

Reviewing files that changed from the base of the PR and between 7dbfd17 and aefd0fc.

📒 Files selected for processing (30)
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • CONTRIBUTING.md
  • sdk/python/tests/unit/test_wire_contract.py
  • sdk/spec/check_contract.py
  • sdk/typescript/tests/unit/wire-contract.test.ts
  • tests/fixtures/wire/README.md
  • tests/fixtures/wire/http/activate.json
  • tests/fixtures/wire/http/communities_search.json
  • tests/fixtures/wire/http/contexts_list.json
  • tests/fixtures/wire/http/error_forbidden.json
  • tests/fixtures/wire/http/error_malformed_request.json
  • tests/fixtures/wire/http/error_no_context.json
  • tests/fixtures/wire/http/error_over_limit.json
  • tests/fixtures/wire/http/evidence_budget_constrained.json
  • tests/fixtures/wire/http/evidence_communities_degrade_and_rerank_reason.json
  • tests/fixtures/wire/http/evidence_contradiction_group.json
  • tests/fixtures/wire/http/evidence_duplicate_passage.json
  • tests/fixtures/wire/http/evidence_mixed_lanes.json
  • tests/fixtures/wire/http/explore.json
  • tests/fixtures/wire/http/health.json
  • tests/fixtures/wire/http/recall.json
  • tests/fixtures/wire/http/sources_search.json
  • tests/fixtures/wire/http/version.json
  • tests/fixtures/wire/mcp/assemble_evidence_call.json
  • tests/fixtures/wire/mcp/assemble_evidence_tool_error.json
  • tests/fixtures/wire/mcp/assemble_evidence_tool_schema.json
  • tests/fixtures/wire/shapes.json
  • tests/http_api/contract.rs
  • tests/http_api/main.rs

Comment thread sdk/spec/check_contract.py
Comment thread sdk/spec/check_contract.py
Comment thread tests/fixtures/wire/shapes.json Outdated
Comment thread tests/http_api/contract.rs
- collect_by_path (Python, Rust, TypeScript): the enum self-consistency
  check silently found nothing inside MCP fixtures, since their shape
  lives a second time as JSON text under content[].text rather than a
  nested object — now unwraps that pass-through text before continuing
  the same path. tests/http_api/contract.rs also widens both shapes.json
  self-consistency tests to cover mcp/ fixtures, not just http/.
- check_contract.py's classify_request matched a required field by its
  last path segment alone, so a NEW nested field sharing a name with a
  required top-level one (request.filter.query vs. a required top-level
  query) was misclassified as a breaking change. Now matches the exact
  top-level path. Added sdk/python/tests/unit/test_check_contract.py to
  cover this and the module's other documented classification rules.
- shapes.json: declared response.result.omitted[].kind (same values as
  items[].kind) — omitted candidates carry it too.
- ci.yml: route the base-ref/PR-SHA values through env: instead of
  interpolating them directly into shell text (zizmor template-injection
  nitpick).
- Cargo.toml: declare rust-version — clippy's own incompatible_msrv
  lint puts the true floor at 1.89 (File::try_lock in src/storage.rs),
  not the 1.88 let-chains alone would suggest.

Claude-Session: https://claude.ai/code/session_011KBpNVCCcdTUtCuPdpXh2n
@t0k0sh1
t0k0sh1 merged commit b67017c into main Jul 31, 2026
9 checks passed
@t0k0sh1
t0k0sh1 deleted the golden-wire-contract-fixtures branch July 31, 2026 11: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.

api: add golden wire-contract fixtures and a breaking-change CI guard

1 participant