broker-api-changelog-diffing-tool · v3.0.0 · 2026-09-03 · sha256 1c20f79774982ef6
broker-api-changelog-diffing-tool v3.0.0A
Immutable. This exact content is served forever at /api/v1/blob/1c20f79774982ef6.
--- name: broker-api-changelog-diffing-tool description: >- Use before upgrading a broker SDK or OpenAPI spec, to diff two schema snapshots for removed endpoints, newly required parameters, enum mutations and type changes so CI fails before the change reaches an order path. license: Apache-2.0 metadata: domain: algorithmic-trading subdomain: broker-integration tags: broker-integration, api-changelog, schema-diffing, openapi, breaking-changes, ci-cd brokers_frameworks: "OpenAPI 3.x; Swagger 2.0 (reference resolution only)" version: "3.0.0" author: algo-trading-skills-contributors --- ## When to Use Invoke this before upgrading a broker SDK version or pulling a new API specification (Binance, Coinbase, IBKR Client Portal and similar publish OpenAPI documents). Broker releases introduce silent breaking changes — a removed nested response field, a parameter that quietly became mandatory, a new order status the state machine has never seen. This skill diffs two schema snapshots and classifies what changed, so a CI job can fail the build before the change reaches an order path. The tool is a **gate**, and its failure modes are asymmetric: a false positive costs a developer a few minutes, a false negative ships a broken integration. Everything about its classification is biased accordingly. ## When NOT to Use - **As proof a release is safe.** It compares structure only. Rate limits, auth scope changes, altered matching-engine behaviour, changed rounding, new error codes returned in a 200 body — none are expressible in a schema, and none will appear in the report. A clean diff means "nothing structural broke", not "safe to deploy". - **On specifications it cannot fully resolve.** Only local (`#/...`) references are followed. External and remote `$ref`s are reported as `UNRESOLVED_REF` — that region was *not compared*, and treating the report as complete when one is present is a mistake. - **As a Swagger 2.0 differ.** `#/definitions/...` references resolve, but Swagger 2.0's body parameters and top-level `consumes`/`produces` are not modeled; the request-body logic assumes OpenAPI 3.x `requestBody.content`. Convert 2.0 documents to 3.x first. - **As a file loader.** It takes parsed Python dictionaries. Reading and parsing JSON or YAML is the caller's job. - **For composition keywords.** `oneOf`, `anyOf`, `allOf` and `discriminator` are not evaluated; schemas using them will diff only at the level the tool can see. ## Prerequisites - Baseline (older) and target (newer) API schemas, parsed into dictionaries. - Both documents complete, including the `components`/`definitions` sections the `$ref`s point at — a spec split across files must be bundled first, or references will come back unresolved. ## Workflow 1. **Load both documents and let the differ reject unusable input.** `diff_schemas` raises `SchemaDiffError` when a document is not a mapping or has no `paths`. This is deliberate: a failed download or a wrong path yields an empty document, and a differ that shrugs and reports zero changes turns the gate green at exactly the moment it matters. 2. **Diff endpoints.** Removed paths and removed methods are `CRITICAL_BREAKING`. Only real HTTP methods are treated as operations — a Path Item Object also legally carries `parameters`, `servers`, `summary`, `description` and `$ref`, and path-level `parameters` are diffed as shared across every operation. 3. **Resolve `$ref` before comparing anything.** Real broker specs describe payloads almost entirely through references, and a `$ref` schema carries no `type`, `properties` or `enum` of its own. Resolution follows `#/components/schemas/...` and `#/definitions/...` against the document each side came from, with cycle protection for self-referential models. 4. **Treat absence as a change.** A removed response status code, a removed request or response content type, and a removed `requestBody` are all breaking and all invisible to a differ that walks only the keys present on both sides. 5. **Check requirement transitions in both directions.** A request field or parameter moving *into* `required` breaks callers that omit it. A response field moving *out of* `required` breaks parsers that assume it is present. Both matter; they are not the same check. 6. **Classify enums by direction.** A request enum constrains what the client may send, so *removing* a value is breaking. A response enum constrains what the client must handle, so *adding* a value is breaking — a new order status silently breaks an exhaustive state machine. Newly imposing a request constraint, and dropping a response constraint, are breaking too. 7. **Gate the build.** `report.exit_code` is 0 when compatible and 1 otherwise; `report.format_report()` renders the findings severity-first. `is_compatible` is False if any change is `MEDIUM_BREAKING` or higher. > Full procedure: see `references/workflows.md`. > Severity matrix and classification rationale: see `references/standards.md`. > Printable pre-flight checklist: see `assets/checklist.md`. ## Common Pitfalls - **Comparing `$ref` schemas without resolving them.** Both sides look like empty objects, every check is skipped, and a release that deleted an entire response model reports clean. This is the single most likely way to get a false green. - **Ignoring an `UNRESOLVED_REF` finding.** It is informational in severity but it means a region of the schema was never compared. Bundle the spec and re-run. - **Only diffing keys present on both sides.** Removals are the breaking changes; a loop written as `if key in new: compare(...)` cannot see any of them. - **Treating enum changes as direction-agnostic.** Flagging every set difference raises false alarms on request widenings while missing the response additions that actually break consumers. - **Assuming a scalar `type`.** OpenAPI 3.1 allows `type: ["object", "null"]` where 3.0 used `nullable: true`. An equality test against the literal `"object"` silently skips property diffing, and comparing the two spellings reports a mutation that never happened. - **Treating every key under a path as an HTTP method.** `parameters` is a list and `summary` is a string; calling `.get()` on them raises on a perfectly valid document. - **Letting an empty or malformed document produce a clean report.** - **Unbounded recursion on self-referential models.** `Order.parent → Order` is ordinary, and resolving references without a cycle guard hangs the build. - **Reading a clean report as deployment approval.** Structure is not behaviour. ## Verification - Run the unit suite and confirm every test passes: `python -m unittest discover -s skills/broker-api-changelog-diffing-tool/scripts` - Build a fixture whose response model sits behind a `$ref`, delete a field from the referenced component, and confirm `REMOVED_RESPONSE_FIELD` is reported. A differ that passes every inline-schema test can still fail this one, which is the case that matters. - Confirm two empty documents raise `SchemaDiffError` rather than reporting compatible. - Confirm a self-referential model terminates. - Confirm direction-aware enum behaviour: adding a response enum value is breaking; adding a request enum value is not. - Confirm a Path Item Object carrying `parameters` and `summary` does not raise. - Mutate fixtures by deep-copying a baseline and changing exactly one thing, so a test for one change cannot accidentally introduce another. ## Related Skills - `broker-api-versioning-migration-playbook` - `broker-api-deprecation-notice-monitoring` - `sandbox-vs-production-endpoint-drift` - `broker-agnostic-adapter-interface`