Skip to content

ci: automated public-API spec conformance validation#988

Merged
RaHehl merged 5 commits into
uilibs:mainfrom
bluetoothbot:koan/implement-987
Jun 19, 2026
Merged

ci: automated public-API spec conformance validation#988
RaHehl merged 5 commits into
uilibs:mainfrom
bluetoothbot:koan/implement-987

Conversation

@bluetoothbot

@bluetoothbot bluetoothbot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds automated drift detection between the hand-maintained public-API client and Ubiquiti's Integration OpenAPI spec, running at most once per Protect release. The spec itself is never committed (Ubiquiti IP) — only a bare openapi/.validated-version marker is tracked.

Closes #987

Changes

  • scripts/validate_spec.py — four conformance checks (endpoint coverage table, model fields both directions, required fields, enum values), reusing the resolution helpers shared with tests/test_public_schema_conformance.py and each model's _get_unifi_remaps() as the remap source of truth. Prints a markdown summary; exits non-zero on any error.
  • .github/workflows/spec-validation.yml — daily cron + workflow_dispatch (optional version, dry_run). Queries the firmware-latest API first and short-circuits while the marker is current or a drift issue is already open, so the ~74 MB deb is fetched only when a release actually drifts. Opens a marker-bump PR on green or one drift issue on red (closing superseded ones).
  • openapi/.validated-version (7.1.77) — the only committed artifact; .gitignore keeps openapi/integration.json ignored while un-ignoring the marker.
  • scripts/fetch_openapi.py--print-version flag (resolve version, no download) for the workflow's cheap steady-state check.
  • tests/test_validate_spec.py — network-free unit tests over in-memory mock specs covering every check branch (new endpoint, removed field, missing-required, new enum, all-green).
  • tests/test_public_schema_conformance.py — extended to run the same checks when a spec is present; still skips when absent (CI default).
  • AGENTS.md — documents the validation script, marker, and workflow.

Design note

The plan specified required-vs-optional mismatches as errors, but this library deliberately models every public-API field optional (older firmware and partial/reference responses omit them — documented convention). A hard error would make validation perpetually red and unreachable for the green marker-bump path, so check_required emits warnings instead. Rationale documented inline.

Test plan

  • poetry run pytest tests/test_validate_spec.py — 23 pass, no network.
  • poetry run pytest tests/test_public_schema_conformance.py — skips cleanly with no spec; runs the full checks when a spec is present.
  • ruff check / ruff format --check clean on all changed files.
  • git check-ignore openapi/integration.json still reports it ignored; openapi/.validated-version is trackable.

Quality Report

Changes: 9 files changed, 1067 insertions(+), 51 deletions(-)

Code scan: 3 issue(s) found

  • scripts/fetch_openapi.py:125 — debug print statement
  • scripts/validate_spec.py:445 — debug print statement
  • scripts/validate_spec.py:454 — debug print statement

Tests: failed (FAILED)

Branch hygiene: 1 issue(s)

  • Non-conventional commit: drop required-vs-optional check (guaranteed noise by design)

Generated by Kōan

Summary by CodeRabbit

  • Chores

    • Added automated scheduled/manual public spec conformance validation for the API client.
    • Introduced version tracking and short-circuiting to reduce redundant checks.
    • Generates a conformance report and opens drift issues or updates a validated-version marker via PRs.
    • Updated ignore rules for fetched spec artifacts and the validated version marker.
  • New Features

    • Added a validation CLI and integrity checks for endpoint, model-field, and enum conformance.
  • Documentation

    • Documented how conformance validation works, what it checks, and how to run it locally.
  • Tests

    • Added test coverage for conformance reporting, completeness gaps, and expected CLI behaviors.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8aa42605-2158-4cc8-bd7b-fbaada1b1945

📥 Commits

Reviewing files that changed from the base of the PR and between 5cdec8b and f4b212b.

📒 Files selected for processing (1)
  • .github/workflows/spec-validation.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/spec-validation.yml

📝 Walkthrough

Walkthrough

This PR introduces an automated spec conformance validation system that detects API drift between the library's public-API client and Ubiquiti's Integration OpenAPI specification. The system runs once per Protect release, reports endpoint/field/enum mismatches via CI, and maintains a version marker file tracking the last validated release.

Changes

Spec Conformance Validation

Layer / File(s) Summary
Spec validation framework and checks
scripts/validate_spec.py
Core validation logic derives client endpoint coverage from decorator registries, recorded example calls, and websocket paths. Implements conformance checks for endpoint coverage (warns on uncovered spec endpoints), model field drift (errors on removed fields, warns on added ones), enum value gaps, and completeness of public-API methods. Returns structured errors/warnings and formats a markdown report.
Enhanced fetch script for version resolution
scripts/fetch_openapi.py
Adds --print-version flag so the workflow can resolve the target Protect version without the 74 MB deb download/extraction, enabling fast short-circuit checks.
GitHub Actions workflow orchestration
.github/workflows/spec-validation.yml
Daily-cron and manual-dispatch workflow that resolves the target Protect version, short-circuits when the stored validated-version marker matches the resolved release or a drift issue is already open, runs validation on demand, and opens green PRs bumping the marker on success or opens/updates red drift issues on failure while closing superseded issues.
Comprehensive test coverage
tests/test_validate_spec.py, tests/test_public_schema_conformance.py, tests/conftest.py
Unit tests for all validation checks, path normalization, format output, schema resolution, and main CLI behavior; integration tests that run the full suite against on-disk spec; conftest enables test imports of the non-package scripts/ directory.
Documentation and configuration
AGENTS.md, .gitignore, openapi/.validated-version
Documented conformance workflow including drift categories, local reproduction, committed vs runtime artifacts, and CI behavior; .gitignore ignores fetched spec but tracks the version marker; initial marker value set to 7.1.77.

Sequence Diagram(s)

sequenceDiagram
  participant Workflow as GitHub Actions
  participant Fetch as fetch_openapi.py
  participant Validate as validate_spec.py
  participant Registry as Decorator Registry
  participant Spec as OpenAPI Spec
  participant Report as Drift Report
  Workflow->>Fetch: --print-version
  Fetch-->>Workflow: resolved version
  Workflow->>Workflow: check marker & issues
  alt version unchanged
    Workflow-->>Workflow: exit (short-circuit)
  end
  Workflow->>Fetch: fetch spec for version
  Fetch-->>Spec: download integration.json
  Workflow->>Validate: run validation
  Validate->>Registry: derive covered endpoints
  Validate->>Spec: check spec against coverage
  Validate->>Validate: compare model fields
  Validate->>Validate: check enum values
  Validate->>Report: format summary
  Report-->>Workflow: markdown report + exit code
  alt validation success
    Workflow->>Workflow: open version-bump PR
  else validation error
    Workflow->>Workflow: open/update drift issue
    Workflow->>Workflow: close older issues
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • uilibs/uiprotect#852: Both PRs touch scripts/fetch_openapi.py—the retrieved PR introduces the spec-fetching CLI/script, while this PR extends that same script's CLI with --print-version for version resolution without download.

Suggested reviewers

  • RaHehl
  • bdraco

Poem

🐰 Hops with joy at conformance!
Specs and clients now dance in sync,
Each release gets a gentle nudge—
No more drift left in the murk! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'ci: automated public-API spec conformance validation' accurately and concisely summarizes the main objective of adding automated validation for API spec conformance, matching the primary change.
Linked Issues check ✅ Passed All PR objectives from #987 are fully implemented: automated drift detection with version-based short-circuit logic, spec validation checks (endpoints, schemas, enums), one-issue-per-version workflow automation, local test hooks, and exclusion from normal PR tests.
Out of Scope Changes check ✅ Passed All changes are directly scoped to #987: validation infrastructure, CI workflow, local testing, and documentation. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codspeed-hq

codspeed-hq Bot commented Jun 9, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 4 untouched benchmarks


Comparing bluetoothbot:koan/implement-987 (f4b212b) with main (d336fdd)

Open in CodSpeed

@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@RaHehl

RaHehl commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Hold — resequenced behind #989. Review of this PR's _ENDPOINT_TO_METHOD table concluded that a hand-maintained string mapping rots silently (renames, forgotten entries, never verifies the body's actual path). Instead of patching that here, #989 makes the uniform ~70% of the public-API surface declarative — the decorator registry then becomes the authoritative coverage source.

Once #989 lands, this PR should be reworked to:

  1. Replace _ENDPOINT_TO_METHOD with decorator registry ∪ recorded example calls for the hand-written exception methods (recording stub on BaseApiClient.request that captures (verb, path) and short-circuits with a sentinel — prototyped and validated against all call shapes).
  2. Add the completeness guard: every public-API coroutine on ProtectApiClient must appear in registry ∪ exercised set (no silent gaps).
  3. Drop the three leftover debug print statements flagged by the quality scan (fetch_openapi.py:125, validate_spec.py:370/378).

Everything else here (workflow, marker, dedupe state machine, field/required/enum checks) stays as-is.

@RaHehl

RaHehl commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

@bluetoothbot fix

#990 is merged — the declarative @public_get/patch/post decorators and the import-time registry (uiprotect._public_api.registry) are now in main. Rebase onto main and rework this PR's coverage source accordingly:

  1. Delete _ENDPOINT_TO_METHOD. Replace it as the coverage source with the decorator registry ∪ recorded example calls for the hand-written exception methods.
    • Registry side: registry.for_class("ProtectApiClient") gives (verb, path_template) → method name for every declarative endpoint — authoritative, can't drift (it is the implementation).
    • Recording side (for the ~hand-written exceptions: update_public, create/delete_camera_rtsps_streams, get_public_api_camera_snapshot, create_talkback_session_public, get/upload_file_public, get_alarm_hub(s)_public, the bridge/viewer/liveview obj-GETs with write-through, the grouped/validated PATCHes like update_camera/light/viewer_public, all subscribe_*): a test stub spies on BaseApiClient.request, captures (verb, path), and short-circuits via a sentinel exception. One executable example call per exception method.
  2. Placeholder normalization (important): registry paths use Python parameter names (/v1/cameras/{camera_id}) while the OpenAPI spec uses /v1/cameras/{id}. The coverage matcher must normalize placeholders (e.g. {…}{}) before comparing registry/recorded paths against spec paths. Otherwise every parametrized endpoint reports as uncovered.
  3. Completeness guard: assert every public-API coroutine on ProtectApiClient appears in registry ∪ recorded set — no silent gaps when someone adds a method.
  4. Drop the three leftover debug print statements flagged by the earlier quality scan (fetch_openapi.py, validate_spec.py).

Everything else here (workflow, .validated-version marker, dedupe state machine, field/required/enum checks) stays as-is.

@RaHehl

RaHehl commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

@bluetoothbot fix

The main merge is in (good — #990's registry is now available on the branch), but the actual rework is still missing: scripts/validate_spec.py still defines and uses _ENDPOINT_TO_METHOD (lines ~64, ~244, ~247). That hand-maintained table is exactly what #990 lets us delete. Please complete the rework now that the registry exists in main:

  1. Delete _ENDPOINT_TO_METHOD entirely. Replace it as the coverage source with uiprotect._public_api.registry ∪ recorded example calls:
    • Declarative endpoints: registry.for_class("ProtectApiClient") returns {(verb, path_template): method_name} — authoritative, can't drift (the decorator is the implementation). Use this as the covered set for everything declared via @public_get/@public_patch/@public_post.
    • Hand-written exceptions (not decorated — update_public, create/delete_camera_rtsps_streams, get_public_api_camera_snapshot, create_talkback_session_public, get/upload_file_public, get_alarm_hub(s)_public, the bridge/viewer/liveview obj-GETs, the grouped/validated PATCHes update_camera/light/viewer/speaker/link_station_public, all subscribe_*): cover these with a small recording helper — a test/util that spies on BaseApiClient.request, captures (verb, path), and short-circuits via a sentinel exception, with one executable example call per exception method.
  2. Placeholder normalization: registry templates use Python param names (/v1/cameras/{camera_id}), the OpenAPI spec uses /v1/cameras/{id}. Normalize placeholders ({…}{}) before comparing covered paths against spec paths, or every parametrized endpoint will report uncovered.
  3. Completeness guard: assert every public-API coroutine on ProtectApiClient appears in registry ∪ recorded set — no silent gaps.
  4. Drop the three debug print statements from the earlier quality scan (fetch_openapi.py, validate_spec.py).

Keep the rest (workflow, .validated-version marker, dedupe state machine, field/required/enum checks) as-is.

@RaHehl RaHehl marked this pull request as ready for review June 10, 2026 21:54
Copilot AI review requested due to automatic review settings June 10, 2026 21:54

Copilot AI 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.

Pull request overview

Adds automated CI validation to detect drift between this library’s hand-maintained Public Integration API surface and Ubiquiti’s Integration OpenAPI spec, while ensuring the spec itself is never committed (only a validated-version marker is tracked).

Changes:

  • Introduces scripts/validate_spec.py to run endpoint/model/required/enum conformance checks and emit a markdown report (non-zero exit on errors).
  • Adds a scheduled + manual GitHub Actions workflow to validate at most once per Protect release and open either a marker-bump PR (green) or a drift issue (red).
  • Adds unit tests for all validation branches and wires the same checks into the existing opt-in schema conformance test when a spec is present.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
scripts/validate_spec.py Implements spec drift checks and report formatting used by both CI and tests.
scripts/fetch_openapi.py Adds --print-version to resolve a target Protect version without downloading the deb.
.github/workflows/spec-validation.yml New scheduled/manual workflow to run validation once per release and manage PR/issue outcomes.
openapi/.validated-version Adds the tracked “last validated” version marker.
tests/test_validate_spec.py New network-free unit tests covering validation logic branches.
tests/test_public_schema_conformance.py Reuses validation helpers when a spec is present and adds a spec-free completeness test.
tests/conftest.py Exposes scripts/ on sys.path so tests can import validate_spec.
AGENTS.md Documents the new validation script, marker, and workflow behavior.
.gitignore Keeps the fetched spec ignored while allowing the marker file to be committed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/spec-validation.yml
Comment thread .github/workflows/spec-validation.yml Outdated
Comment thread .github/workflows/spec-validation.yml Outdated
Comment thread .github/workflows/spec-validation.yml Outdated

@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: 3

🤖 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 @.github/workflows/spec-validation.yml:
- Line 42: Update the workflow to remove unpinned action references and disable
credential persistence: replace actions/checkout@v6 and actions/setup-python@v6
with specific commit SHA pins (use the corresponding official repo commit
hashes) and set persist-credentials: false for the checkout step so credentials
are not written to the runner; ensure both action usages (the checkout step and
the setup-python step) are pinned to commit hashes rather than version tags.
- Around line 111-112: The fetch command should protect the user input from
shell word-splitting; update the invocation of fetch_openapi.py to pass the
version argument as a single quoted string (e.g. --version '${{ inputs.version
}}') so the value of inputs.version is not subject to shell splitting or
globbing. Modify the line that calls "poetry run python scripts/fetch_openapi.py
--version ..." to wrap the expansion in quotes, referencing the inputs.version
expansion and the fetch_openapi.py invocation to locate the change.
- Around line 62-63: The workflow directly expands ${{ inputs.version }} into
the shell command causing potential shell injection; fix by first assigning the
input to a quoted shell variable (e.g., version="${{ inputs.version }}") and
then use the quoted variable ("$version") when calling scripts/fetch_openapi.py
to populate latest, and apply the same quoted-variable pattern to the other
occurrence that calls scripts/fetch_openapi.py (the block that sets latest/uses
inputs.version later).
🪄 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: 89753f9f-333a-4203-b6a7-c4b8ce7124df

📥 Commits

Reviewing files that changed from the base of the PR and between 755cd5c and 391c840.

📒 Files selected for processing (9)
  • .github/workflows/spec-validation.yml
  • .gitignore
  • AGENTS.md
  • openapi/.validated-version
  • scripts/fetch_openapi.py
  • scripts/validate_spec.py
  • tests/conftest.py
  • tests/test_public_schema_conformance.py
  • tests/test_validate_spec.py

Comment thread .github/workflows/spec-validation.yml
Comment thread .github/workflows/spec-validation.yml Outdated
Comment thread .github/workflows/spec-validation.yml Outdated
@bluetoothbot

Copy link
Copy Markdown
Contributor Author

Rework complete — _ENDPOINT_TO_METHOD is gone; coverage is now derived, never hand-maintained.

  1. Deleted _ENDPOINT_TO_METHOD. Covered endpoints = registry.for_class("ProtectApiClient") (declarative @public_*) ∪ recorded example calls ∪ the two *_ws_path subscriptions (covered_endpoints() in scripts/validate_spec.py). The recorder spies on BaseApiClient.request, captures (verb, path), then short-circuits via a sentinel before any I/O — one executable example call per hand-written exception method (_EXAMPLE_CALLS).
  2. Placeholder normalization. _normalize_path collapses every {…} and the record sentinel to a bare {}, so registry templates (/v1/cameras/{camera_id}) compare equal to spec paths (/v1/cameras/{id}).
  3. Completeness guard. check_completeness() asserts every public-API coroutine on ProtectApiClient appears in registry ∪ _EXAMPLE_CALLS — a new method that nobody wires up fails the suite instead of silently leaving its endpoint uncovered.
  4. Debug prints. The three flagged lines are not debug output and were retained deliberately: fetch_openapi.py print(ver) is the --print-version feature, validate_spec.py's stderr line is the "spec not found" error, and the final print(format_summary(...)) is the markdown summary the workflow embeds in the drift issue. Removing them would break the script.

Workflow, .validated-version marker, dedupe state machine, and field/required/enum checks are unchanged. Branch rebased onto current main. tests/test_validate_spec.py (32) + the conformance extension pass; ruff lint/format clean.

1 similar comment
@bluetoothbot

Copy link
Copy Markdown
Contributor Author

Rework complete — _ENDPOINT_TO_METHOD is gone; coverage is now derived, never hand-maintained.

  1. Deleted _ENDPOINT_TO_METHOD. Covered endpoints = registry.for_class("ProtectApiClient") (declarative @public_*) ∪ recorded example calls ∪ the two *_ws_path subscriptions (covered_endpoints() in scripts/validate_spec.py). The recorder spies on BaseApiClient.request, captures (verb, path), then short-circuits via a sentinel before any I/O — one executable example call per hand-written exception method (_EXAMPLE_CALLS).
  2. Placeholder normalization. _normalize_path collapses every {…} and the record sentinel to a bare {}, so registry templates (/v1/cameras/{camera_id}) compare equal to spec paths (/v1/cameras/{id}).
  3. Completeness guard. check_completeness() asserts every public-API coroutine on ProtectApiClient appears in registry ∪ _EXAMPLE_CALLS — a new method that nobody wires up fails the suite instead of silently leaving its endpoint uncovered.
  4. Debug prints. The three flagged lines are not debug output and were retained deliberately: fetch_openapi.py print(ver) is the --print-version feature, validate_spec.py's stderr line is the "spec not found" error, and the final print(format_summary(...)) is the markdown summary the workflow embeds in the drift issue. Removing them would break the script.

Workflow, .validated-version marker, dedupe state machine, and field/required/enum checks are unchanged. Branch rebased onto current main. tests/test_validate_spec.py (32) + the conformance extension pass; ruff lint/format clean.

@RaHehl

RaHehl commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

@bluetoothbot refactor #988 — please address all 7 open review comments:

  1. Make scripts/fetch_openapi.py stdlib-only by replacing orjson with json (it's a one-shot fetch tool, not a hot path — the docstring already claims "Requires only stdlib"). That fixes the ModuleNotFoundError from calling it before dependency install, without reordering the workflow.
  2. Add explicit --limit to all gh issue list / gh pr list calls (lines ~93/137/174) so the dedupe/close checks are reliable.
  3. Pin actions/checkout and actions/setup-python to commit SHAs and set persist-credentials: false on checkout.
  4. Fix the template injections: assign ${{ inputs.version }} to an env/shell variable first and quote it in both the resolve and fetch steps (lines ~63/112).

Add scripts/validate_spec.py — checks the public-API client against a
fetched Integration OpenAPI spec (endpoint coverage, model fields both
directions, required fields, enum values), reusing the resolution helpers
shared with tests/test_public_schema_conformance.py and the model classes'
_get_unifi_remaps() as the remap source of truth.

Add .github/workflows/spec-validation.yml — daily cron + workflow_dispatch
that runs the full validation at most once per Protect release, gated by a
firmware-API check and the committed openapi/.validated-version marker; opens
a marker-bump PR on green or one drift issue on red. The spec is fetched
ephemerally and never committed (Ubiquiti IP).

Validation logic is unit-tested network-free against in-memory mock specs
in tests/test_validate_spec.py; the local hook in
test_public_schema_conformance.py runs the same checks when a spec is present
and skips when absent.
Replace the hand-maintained _ENDPOINT_TO_METHOD table with a coverage set
derived from the import-time @public_* decorator registry plus one recorded
example call per hand-written exception method (a request spy captures
(verb, path) then short-circuits before network I/O). Placeholder names are
normalized to a bare {} so registry/spec/recorded paths compare equal.

Add check_completeness: every public-API coroutine on ProtectApiClient must
be declarative or have a recorded example call, so a newly added method that
nobody wired up fails the suite instead of silently leaving its endpoint
uncovered.
RaHehl
RaHehl previously approved these changes Jun 18, 2026

@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: 2

🧹 Nitpick comments (3)
tests/test_validate_spec.py (1)

1-6: ⚡ Quick win

Use a terse single-line module docstring here.

The current module docstring is narrative-heavy; a short summary line matches repo conventions for test modules.

As per coding guidelines, Python modules should default to terse single-line docstrings and avoid explanatory rationale in comments/docstrings unless behavior is non-obvious.

🤖 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 `@tests/test_validate_spec.py` around lines 1 - 6, Replace the multi-line
module docstring at the top of the file with a single-line terse docstring that
provides a brief summary of the module's purpose. Remove the narrative
explanations about hand-built specs and CI details, and condense the information
into a concise one-liner that matches the repository's conventions for test
module docstrings. The docstring should be enclosed in triple quotes on a single
line.

Source: Coding guidelines

tests/test_public_schema_conformance.py (1)

22-23: ⚡ Quick win

Prefer orjson over stdlib json for spec parsing in this test.

This keeps parsing behavior consistent with the validator and matches the repo’s Protect-payload serialization guideline.

Proposed fix
diff --git a/tests/test_public_schema_conformance.py b/tests/test_public_schema_conformance.py
@@
-import json
+import orjson
@@
-    schemas = json.loads(_SPEC_PATH.read_text())["components"]["schemas"]
+    schemas = orjson.loads(_SPEC_PATH.read_bytes())["components"]["schemas"]
@@
-    spec = json.loads(_SPEC_PATH.read_text())
+    spec = orjson.loads(_SPEC_PATH.read_bytes())

As per coding guidelines, use orjson for serialization/parsing Protect payloads instead of stdlib json.

Also applies to: 92-93, 101-102

🤖 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 `@tests/test_public_schema_conformance.py` around lines 22 - 23, Replace the
stdlib `json` import with `orjson` to ensure consistent parsing behavior with
the validator and comply with repository serialization guidelines. Update the
import statement at the top of the file to import `orjson` instead of `json`,
and then replace all `json.loads()` calls throughout the file (including the
occurrences at lines 92-93 and 101-102) with `orjson.loads()` to maintain
consistency across the test file for spec parsing operations.

Source: Coding guidelines

scripts/validate_spec.py (1)

2-24: ⚡ Quick win

Docstrings are over-detailed for this repo’s Python style contract.

These docstrings include rationale and multi-line narrative where terse, single-line summaries are expected by default.

As per coding guidelines, **/*.py should use terse single-line docstrings by default and avoid rationale/motivation prose unless behavior is non-obvious.

Also applies to: 325-333

🤖 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 `@scripts/validate_spec.py` around lines 2 - 24, The module-level docstring in
the file is excessively detailed with multi-line narrative and rationale when
the repo's Python style guidelines require terse single-line summaries by
default. Replace the verbose docstring block (the entire multi-line docstring
from lines 2-24) with a concise single-line summary describing what the script
does without rationale or detailed logic explanation. Apply the same condensing
approach to the other docstring around lines 325-333 mentioned in the comment
review.

Source: Coding guidelines

🤖 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 @.github/workflows/spec-validation.yml:
- Around line 92-93: Add explicit `--limit` parameters to all three `gh` list
commands used for dedupe and supersede logic in the workflow to ensure complete
result retrieval beyond default pagination limits. Specifically, add `--limit`
to the `gh issue list` call on lines 92-93, the `gh pr list` call on line 137,
and the `gh issue list` call on lines 172-174. Use a sufficiently high limit
value (such as 100 or greater) to capture all potential matches for accurate
deduplication and superseding logic.

In `@scripts/validate_spec.py`:
- Around line 350-351: The code at lines 350-351 silently skips schema
validation when a schema_name is not found in schemas, but this masks real drift
for explicitly tracked schemas. Distinguish between explicitly tracked schemas
in _MODEL_SCHEMAS and _ENUM_SCHEMAS versus untracked ones: for tracked schemas
that are missing from the current schemas dict, raise an error or warning to
surface the drift instead of silently continuing; only use continue for schemas
that are not explicitly tracked (private-only or untracked). Apply the same
logic to the similar code block referenced at lines 381-383.

---

Nitpick comments:
In `@scripts/validate_spec.py`:
- Around line 2-24: The module-level docstring in the file is excessively
detailed with multi-line narrative and rationale when the repo's Python style
guidelines require terse single-line summaries by default. Replace the verbose
docstring block (the entire multi-line docstring from lines 2-24) with a concise
single-line summary describing what the script does without rationale or
detailed logic explanation. Apply the same condensing approach to the other
docstring around lines 325-333 mentioned in the comment review.

In `@tests/test_public_schema_conformance.py`:
- Around line 22-23: Replace the stdlib `json` import with `orjson` to ensure
consistent parsing behavior with the validator and comply with repository
serialization guidelines. Update the import statement at the top of the file to
import `orjson` instead of `json`, and then replace all `json.loads()` calls
throughout the file (including the occurrences at lines 92-93 and 101-102) with
`orjson.loads()` to maintain consistency across the test file for spec parsing
operations.

In `@tests/test_validate_spec.py`:
- Around line 1-6: Replace the multi-line module docstring at the top of the
file with a single-line terse docstring that provides a brief summary of the
module's purpose. Remove the narrative explanations about hand-built specs and
CI details, and condense the information into a concise one-liner that matches
the repository's conventions for test module docstrings. The docstring should be
enclosed in triple quotes on a single line.
🪄 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: 448ebe62-bf2f-4e8f-a6af-83bd3b38e0b4

📥 Commits

Reviewing files that changed from the base of the PR and between 391c840 and a0a373b.

📒 Files selected for processing (9)
  • .github/workflows/spec-validation.yml
  • .gitignore
  • AGENTS.md
  • openapi/.validated-version
  • scripts/fetch_openapi.py
  • scripts/validate_spec.py
  • tests/conftest.py
  • tests/test_public_schema_conformance.py
  • tests/test_validate_spec.py
✅ Files skipped from review due to trivial changes (1)
  • openapi/.validated-version
🚧 Files skipped from review as they are similar to previous changes (3)
  • .gitignore
  • tests/conftest.py
  • scripts/fetch_openapi.py

Comment thread .github/workflows/spec-validation.yml Outdated
Comment thread scripts/validate_spec.py Outdated
@RaHehl

RaHehl commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

@bluetoothbot fix — please apply CodeRabbit's two actionable findings plus the orjson nitpick, and skip the docstring nitpicks:

  1. Add an explicit --limit (e.g. 200) to all gh issue list / gh pr list calls in .github/workflows/spec-validation.yml — the dedupe/supersede logic currently relies on the CLI default (30), which can miss matches.
  2. In scripts/validate_spec.py, a tracked schema missing from the spec should be an error, not a silent continue — every _MODEL_SCHEMAS / _ENUM_SCHEMAS entry is a genuine public-spec schema, so a missing one is real drift that's currently masked (applies to both check_model_fields and check_enums).
  3. Use orjson instead of stdlib json in tests/test_public_schema_conformance.py (repo convention).

Please leave the terse-docstring nitpicks — the conformance architecture is non-obvious, so the multi-line docstrings are justified. Keep the check_required removal (it was guaranteed noise: the library models every public-API field optional by design).

- add explicit --limit 200 to all gh issue/pr list calls so dedupe and
  supersede checks no longer rely on the CLI default of 30
- treat a tracked _MODEL_SCHEMAS/_ENUM_SCHEMAS entry absent from the spec
  as an error (real drift) instead of a silent skip
- use orjson in tests/test_public_schema_conformance.py per repo convention
@bluetoothbot

Copy link
Copy Markdown
Contributor Author

Applied the three actionable findings (skipped docstring nitpicks per your note):

  1. gh list --limit 200. All three gh issue list/gh pr list calls in .github/workflows/spec-validation.yml now pass --limit 200 so the dedupe/supersede checks no longer silently miss matches past the CLI default of 30.
  2. Missing tracked schema → error. check_model_fields and check_enums in scripts/validate_spec.py now emit an error when a tracked _MODEL_SCHEMAS/_ENUM_SCHEMAS entry is absent from the spec (and when a tracked enum schema stops declaring enum), instead of a silent continue that masked real drift. Unit tests updated: the former skipped cases now assert the error; _chime_spec builds a full green spec across all tracked schemas so the all-green/removed/added cases stay focused on chime.
  3. orjson. tests/test_public_schema_conformance.py now uses orjson.loads(...read_bytes()) per repo convention.

check_required removal stays as-is (every public-API field is modelled optional by design). tests/test_validate_spec.py (29) + the conformance extension pass; ruff lint/format clean.

1 similar comment
@bluetoothbot

Copy link
Copy Markdown
Contributor Author

Applied the three actionable findings (skipped docstring nitpicks per your note):

  1. gh list --limit 200. All three gh issue list/gh pr list calls in .github/workflows/spec-validation.yml now pass --limit 200 so the dedupe/supersede checks no longer silently miss matches past the CLI default of 30.
  2. Missing tracked schema → error. check_model_fields and check_enums in scripts/validate_spec.py now emit an error when a tracked _MODEL_SCHEMAS/_ENUM_SCHEMAS entry is absent from the spec (and when a tracked enum schema stops declaring enum), instead of a silent continue that masked real drift. Unit tests updated: the former skipped cases now assert the error; _chime_spec builds a full green spec across all tracked schemas so the all-green/removed/added cases stay focused on chime.
  3. orjson. tests/test_public_schema_conformance.py now uses orjson.loads(...read_bytes()) per repo convention.

check_required removal stays as-is (every public-API field is modelled optional by design). tests/test_validate_spec.py (29) + the conformance extension pass; ruff lint/format clean.

RaHehl
RaHehl previously approved these changes Jun 19, 2026

@RaHehl RaHehl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-approving after the shell-injection fix (version input now passed via env). All conformance checks green; SHA-pin declined for repo-convention/credential-push reasons.

@RaHehl RaHehl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-approving after the shell-injection fix.

@RaHehl RaHehl merged commit 035f30e into uilibs:main Jun 19, 2026
18 of 21 checks passed
@bluetoothbot bluetoothbot deleted the koan/implement-987 branch June 19, 2026 07:11
RaHehl added a commit that referenced this pull request Jun 19, 2026
…#1015)

#1012 decorated get_alarm_hubs_public, get_alarm_hub_public and
update_alarm_hub_public with @public_get/@public_patch, making them
declarative. Their endpoints are now covered via the registry, so they
must be removed from the recorded-example-call table.

#1012 branched before #988 (the conformance test), so its CI never ran
test_example_calls_match_nondeclarative_coroutines; the two PRs were each
green against their base but the combination left main red. This restores
the table to exactly the non-declarative public coroutines.
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.

ci: automated public-API spec conformance validation, once per Protect release

3 participants