Skip to content

docs: unify REST API docs under /docs/openapi/ and patch sitemap#1073

Merged
Aureliolo merged 5 commits intomainfrom
chore/openapi-unified-docs
Apr 5, 2026
Merged

docs: unify REST API docs under /docs/openapi/ and patch sitemap#1073
Aureliolo merged 5 commits intomainfrom
chore/openapi-unified-docs

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

Consolidates the REST API documentation surface under a single /docs/openapi/ URL prefix and makes the previously-invisible static artifacts (the interactive Scalar viewer and the raw OpenAPI schema) discoverable by search engines via a post-build sitemap patcher. Also fixes several factual errors in the landing page that the review agents caught during verification.

URL changes

Before After
/docs/rest-api/ /docs/openapi/ (Markdown landing, in sitemap natively)
/docs/_generated/api-reference.html /docs/openapi/reference.html (interactive viewer, in sitemap via patcher)
/docs/_generated/openapi.json /docs/openapi/openapi.json (raw schema, in sitemap via patcher)

The old /docs/rest-api/ path was URL is unknown to Google in GSC, so there is no ranking to preserve. The new /docs/openapi/ is a fresh discovery path with a meatier landing page (base URL/versioning, JWT auth flow, 32 endpoint groups, RFC 9457 errors, rate limiting, CORS, ETag concurrency, WebSocket).

What's in the PR

Path unification

  • docs/rest-api.mddocs/openapi/index.md with substantially expanded content
  • scripts/export_openapi.py now writes docs/openapi/reference.html + docs/openapi/openapi.json as siblings of the landing page, so zensical copies them through on build
  • mkdocs.yml nav entry updated (REST API: openapi/index.md)
  • Inbound links rewritten in docs/index.md, docs/user_guide.md, docs/architecture/index.md, docs/guides/quickstart.md, and CLAUDE.md
  • .gitignore now ignores the two generated artifacts specifically instead of the whole docs/_generated/ directory (which is gone)

Sitemap discoverability

  • New scripts/patch_sitemap.py inserts the static artifact URLs into _site/docs/sitemap.xml after zensical build. Idempotent, defusedxml-hardened, validates root element, normalizes whitespace, handles OSError on write
  • Wired into .github/workflows/pages.yml and pages-preview.yml after the zensical build step
  • defusedxml==0.7.1 added explicitly to the docs dependency group (was only transitive via py-serializable)
  • defusedxml.* added to mypy ignore_missing_imports overrides

Backend fix uncovered during review

  • src/synthorg/api/controllers/reports.py: ReportsController.path was hardcoded to /api/v1/reports, producing the double-prefixed /api/v1/api/v1/reports/* routes when wrapped by the /api/v1 Router. Changed to /reports so endpoints register at /api/v1/reports/generate and /api/v1/reports/periods, matching docs/design/operations.md and the new landing page. Verified via live OpenAPI schema dump

SRI for Scalar CDN script

  • scripts/export_openapi.py now emits the Scalar viewer <script> tag with integrity="sha384-..." + crossorigin="anonymous" so a CDN compromise can't silently serve tampered JS to reference.html viewers
  • Hash recomputation command documented next to SCALAR_VERSION

Test plan

  • uv run ruff check, ruff format --check, mypy all clean on touched files
  • uv run python -m pytest tests/unit/api/ -n 8 → 1493 passed
  • Cold build verification: rm -rf _site/export_openapi.pygenerate_comparison.pyzensical buildpatch_sitemap.py → sitemap contains all 3 openapi URLs; _site/docs/openapi/ contains index.html, reference.html, openapi.json; SRI attributes present on the CDN script tag
  • Patcher idempotency verified: second run prints skip (already present) for both URLs and doesn't rewrite
  • Reports path fix verified via OpenAPI schema dump: routes now register correctly at /api/v1/reports/generate and /api/v1/reports/periods

Review coverage

Pre-reviewed by 7 agents in parallel:

  • docs-consistency
  • code-reviewer (scripts focus)
  • python-reviewer (scripts focus)
  • silent-failure-hunter
  • comment-analyzer
  • infra-reviewer
  • security-reviewer

17 findings triaged and addressed (5 CRITICAL, 1 HIGH, 4 MAJOR, 5 MEDIUM, 2 LOW). All CRITICAL/HIGH findings were docs factual errors (fabricated auth endpoints, wrong pagination envelope, overstated ETag scope, wrong role name, incomplete WebSocket auth description) or real code bugs (Reports controller double-prefix, missing root validation in patcher). A follow-up polish pass (code-simplifier) returned "ship it" with no suggestions.

Sub-threshold observations (cosmetic comment wording, premature ruff rule suppressions, stylistic preferences) were intentionally skipped.

Consolidates the REST API landing page, interactive Scalar viewer, and
raw OpenAPI schema under a single /docs/openapi/ URL prefix.

Changes:
- Move docs/rest-api.md -> docs/openapi/index.md and expand the landing
  page with substantive content: base URL, versioning, JWT auth flow,
  endpoint groups (all 32 controllers), RFC 9457 error format with
  category codes, rate limiting, CORS, ETag optimistic concurrency,
  WebSocket, and links to the interactive viewer + schema.
- Move the generated artifacts from docs/_generated/ to docs/openapi/:
  api-reference.html -> reference.html, openapi.json stays. Both are
  written as static siblings of index.md so zensical copies them into
  _site/docs/openapi/ on build.
- Add scripts/patch_sitemap.py to insert the two static artifact URLs
  into the built _site/docs/sitemap.xml so search engines can discover
  them (zensical only sitemaps markdown pages by default).
- Wire the patcher into pages.yml and pages-preview.yml after the
  zensical build step.
- Update all inbound doc links (index.md, user_guide.md, architecture,
  quickstart), the mkdocs nav entry, CLAUDE.md, and .gitignore.
Triaged 17 findings across 7 review agents. Fixes applied:

Docs factual accuracy (docs/openapi/index.md):
- Auth: POST /auth/password was fabricated; real path is /auth/change-password
- Auth: DELETE /auth/sessions bulk-revoke was fabricated; documented the real
  POST /auth/logout + single-session DELETE /auth/sessions/{session_id}
- Auth: setup creates a CEO account, not an 'admin user' (no ADMIN role exists)
- WebSocket ticket: documented first-message auth as preferred over the legacy
  query-param flow (matches controller docstring and reasoning)
- Pagination envelope: replaced fabricated {items, total} with the real
  PaginatedResponse[T] shape (data, pagination, degraded_sources, error,
  error_detail, success)
- ETag/If-Match scope: narrowed from 'workflow definitions, settings, agent
  configs' to the actually instrumented 5 controllers (workflows,
  workflow_versions, workflow_executions, tasks, settings)
- Static snapshot description: clarified the export script also runs
  inject_rfc9457_responses, producing a superset of /docs/openapi.json
- Local-server path table: split into fixed /docs/* (Litestar OpenAPIConfig)
  and api_prefix-relative /api/v1/* to prevent misconfiguration confusion
- Users row: (admin-only) -> (CEO-only)
- WebSocket events: rewrote to describe real subscribe/unsubscribe channel
  protocol instead of the incorrect 'no per-channel subscriptions over the
  wire' claim

Code fixes:
- src/synthorg/api/controllers/reports.py: ReportsController.path was hardcoded
  to '/api/v1/reports', producing the double-prefixed '/api/v1/api/v1/reports/*'
  routes when wrapped by the /api/v1 Router. Changed to '/reports' so the
  endpoints register at /api/v1/reports/generate and /api/v1/reports/periods,
  matching docs/design/operations.md and the new landing page. Verified via
  live OpenAPI schema dump and the 1493 API unit tests pass.

scripts/patch_sitemap.py hardening:
- Swapped xml.etree.ElementTree.parse for defusedxml.ElementTree.parse to guard
  against billion-laughs, XXE, and DTD abuse; removed the # noqa: S314
- Added root-element validation (must be {ns}urlset): prevents silent corruption
  if zensical ever switches to a sitemap index or a new schema version
- Normalized the existing-URL set: strip whitespace and discard empty entries
  so pretty-printed <loc> tags can't defeat idempotency
- Wrapped tree.write in try/except OSError with an actionable error message
- Fixed the register_namespace comment (the constraint is on tree.write,
  not on parse)
- Included the sitemap path in the ParseError message
- Rewrote main() docstring to be self-contained and document return codes

scripts/export_openapi.py:
- Added Subresource Integrity (sha384 + crossorigin='anonymous') to the
  Scalar CDN script tag so a CDN compromise can't silently serve tampered
  JS to reference.html viewers
- Documented the hash recomputation command next to SCALAR_VERSION so future
  bumps don't forget to update the pair

pyproject.toml:
- Declared defusedxml==0.7.1 explicitly in the docs dependency group (it
  was only a transitive via py-serializable, which is fragile for a
  load-bearing CI script)
- Added defusedxml.* to the mypy ignore_missing_imports overrides

Pre-reviewed by 7 agents, 17 findings addressed (5 CRITICAL, 1 HIGH, 4 MAJOR,
5 MEDIUM, 2 LOW). Sub-threshold observations intentionally skipped.
Copilot AI review requested due to automatic review settings April 4, 2026 21:35
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f735e1e0-a304-484e-84b1-a1425813b956

📥 Commits

Reviewing files that changed from the base of the PR and between 4517045 and 722a02d.

📒 Files selected for processing (1)
  • scripts/patch_sitemap.py
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Deploy Preview
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do not use from __future__ import annotations in Python -- Python 3.14 has PEP 649 native lazy annotations
Use except A, B: syntax (no parentheses) for exception handling in Python 3.14 per PEP 758 -- ruff enforces this
All public functions and methods must have type hints, with mypy strict mode enforcement
Google-style docstrings are required on all public classes and functions, enforced by ruff D rules
Create new objects rather than mutating existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (via model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 with conventions: allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields; use @computed_field for derived values instead of storing redundant fields; use NotBlankStr for all identifier and name fields including optional and tuple variants, instead of manual whitespace validators
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Maintain a line length of 88 characters (enforced by ruff)
Functions must be less than 50 lines, files must be less than 800 lines
Handle errors explicitly, never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)

Files:

  • scripts/patch_sitemap.py
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to {docs/rest-api.md,docs/_generated/api-reference.html} : REST API reference in `docs/rest-api.md` + `docs/_generated/api-reference.html` (generated by `scripts/export_openapi.py`)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:21:16.739Z
Learning: Applies to .github/workflows/pages.yml : Pages job: version extraction from `pyproject.toml`, OpenAPI export, Astro + Zensical docs build (with version banner), GitHub Pages deploy on push to main
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:28:28.895Z
Learning: Applies to docs/**/*.md : Documentation files in `docs/` (Markdown, built with Zensical, config: `mkdocs.yml`); design spec in `docs/design/` (11 pages)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Export OpenAPI schema with `uv run python scripts/export_openapi.py` (required before docs build)
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to **/*.py : Functions must be less than 50 lines; files must be less than 800 lines

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-04-04T19:50:52.893Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-04T19:50:52.893Z
Learning: Applies to **/*.py : Functions must be less than 50 lines, files must be less than 800 lines

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-04-01T06:12:03.047Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T06:12:03.047Z
Learning: Applies to {**/*.py,web/src/**/*.{ts,tsx}} : Keep functions under 50 lines and files under 800 lines

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-03-31T21:07:37.470Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T21:07:37.470Z
Learning: Applies to **/*.py : Use `except A, B:` (no parentheses) per PEP 758 exception syntax on Python 3.14

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to **/*.py : Use `except A, B:` syntax (without parentheses) per PEP 758 for exception handling in Python 3.14

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to **/*.py : Use `except A, B:` syntax (no parentheses) for exception handling — PEP 758 exception syntax enforced by ruff on Python 3.14

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-04-04T19:50:52.893Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-04T19:50:52.893Z
Learning: Applies to **/*.py : Use `except A, B:` syntax (no parentheses) for exception handling in Python 3.14 per PEP 758 -- ruff enforces this

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to **/*.py : Use PEP 758 except syntax: `except A, B:` (no parentheses) — enforced by ruff on Python 3.14

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to **/*.py : Use PEP 758 except syntax with `except A, B:` (no parentheses) for multiple exceptions—ruff enforces this on Python 3.14.

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-03-15T16:55:07.730Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:55:07.730Z
Learning: Applies to **/*.py : Use PEP 758 except syntax: use `except A, B:` (no parentheses) — ruff enforces this on Python 3.14.

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to **/*.py : Handle errors explicitly—never silently swallow exceptions.

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to **/*.py : Handle errors explicitly, never silently swallow exceptions

Applied to files:

  • scripts/patch_sitemap.py
🔇 Additional comments (2)
scripts/patch_sitemap.py (2)

72-72: Use PEP 758 exception syntax without parentheses.

Line 72 still uses parenthesized exception handling. Per coding guidelines, Python 3.14 should use except A, B: syntax.

🔧 Proposed fix
-    except (ET.ParseError, DefusedXmlException) as exc:
+    except ET.ParseError, DefusedXmlException as exc:

1-180: Well-structured script with proper error handling and idempotency.

The refactoring to extract helpers (_parse_sitemap, _validate_root, _collect_existing_urls, _derive_base_url, _add_extra_urls, _write_sitemap) keeps all functions well under the 50-line limit. The dynamic base URL derivation from existing sitemap entries (line 118) elegantly handles production, staging, and PR preview environments without hardcoding. The use of defusedxml with the documented type: ignore[no-any-return] is the correct approach given the library lacks py.typed.


Walkthrough

Replaces the legacy REST API reference with an OpenAPI-based docs layout under docs/openapi/, removes docs/rest-api.md, updates navigation and links across docs and mkdocs.yml, and moves generated OpenAPI artifacts from docs/_generated/ to docs/openapi/ (adds Subresource Integrity for the Scalar UI). Adds scripts/export_openapi.py updates, adds new scripts/patch_sitemap.py and CI steps in both Pages workflows to run it, updates .gitignore, pins defusedxml in pyproject.toml, and changes ReportsController.path from "/api/v1/reports" to "/reports".

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main objectives: unifying REST API docs under /docs/openapi/ and adding sitemap patching for search engine discoverability.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering URL consolidation, tooling updates, sitemap discoverability, backend fixes, SRI security, and verification testing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 40.00%.

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


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

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request restructures the REST API documentation by moving it to a dedicated docs/openapi/ directory and introducing a new landing page. It updates the export_openapi.py script to output artifacts to the new location and adds a patch_sitemap.py script to ensure these static assets are discoverable by search engines. Additionally, defusedxml was added as a dependency for secure XML parsing. Feedback was provided regarding the hardcoded production domain in the sitemap patching script, which limits its flexibility for non-production environments like staging or PR previews.

Comment on lines +38 to +41
EXTRA_URLS: tuple[str, ...] = (
"https://synthorg.io/docs/openapi/reference.html",
"https://synthorg.io/docs/openapi/openapi.json",
)
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.

medium

The EXTRA_URLS are hardcoded with the production domain https://synthorg.io. This makes the script less flexible for non-production environments (such as staging or PR previews) where the sitemap should ideally point to the environment-specific domain. Consider defining these as relative paths and dynamically prepending the base URL discovered from existing entries in the sitemap to make the script environment-agnostic.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 4, 2026 21:36 — with GitHub Actions Inactive
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 4, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 722a02d.
Ensure that dependencies are being submitted on PR branches. Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice.

Scanned Files

None

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Consolidates the public REST/OpenAPI documentation under /docs/openapi/, ensures the generated Scalar viewer + OpenAPI JSON are shipped alongside the landing page, and makes those static artifacts discoverable by search engines by patching the built sitemap post-build. Also fixes an API route prefixing bug for the Reports controller.

Changes:

  • Move REST API docs to docs/openapi/index.md and update all internal nav/link references.
  • Update export_openapi.py to emit docs/openapi/reference.html + docs/openapi/openapi.json (with SRI on the Scalar CDN script).
  • Add scripts/patch_sitemap.py and wire it into GitHub Pages workflows; add defusedxml as an explicit docs dependency; fix ReportsController.path.

Reviewed changes

Copilot reviewed 14 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
uv.lock Adds defusedxml to docs/dev groups in the lockfile.
src/synthorg/api/controllers/reports.py Fixes controller path to avoid double /api/v1 prefixing.
scripts/patch_sitemap.py New post-build sitemap patcher to add static OpenAPI artifact URLs.
scripts/export_openapi.py Writes artifacts under docs/openapi/ and adds SRI attributes to Scalar script tag.
pyproject.toml Declares defusedxml==0.7.1 in the docs dependency group; adds mypy override for defusedxml.*.
mkdocs.yml Updates nav to point to openapi/index.md.
docs/user_guide.md Updates REST API link to new location.
docs/rest-api.md Removes old REST API landing page.
docs/openapi/index.md New expanded REST/OpenAPI landing page content.
docs/index.md Updates REST API link to new location.
docs/guides/quickstart.md Updates REST API link to new location.
docs/architecture/index.md Updates REST API link to new location.
CLAUDE.md Updates documentation structure notes for new OpenAPI doc/artifact locations.
.gitignore Stops ignoring the whole generated dir; ignores only the two generated OpenAPI artifacts.
.github/workflows/pages.yml Runs sitemap patcher after docs build.
.github/workflows/pages-preview.yml Runs sitemap patcher after docs build (preview).

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

Comment on lines +154 to +158
"type": "https://synthorg.io/docs/errors/#validation-error",
"title": "Validation failed",
"status": 422,
"detail": "Field 'name' is required",
"code": 2001,
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

The RFC 9457 example JSON uses a type URI fragment #validation-error and fields code/category, but the API’s ProblemDetail schema uses type fragments like .../docs/errors#validation and field names error_code / error_category (see docs/errors.md and src/synthorg/api/dto.py). Update the example to match the real response shape so clients don’t implement against the wrong keys.

Copilot uses AI. Check for mistakes.
"detail": "Field 'name' is required",
"code": 2001,
"category": "validation",
"instance": "/api/v1/agents"
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

In RFC 9457 responses, instance is populated with the request correlation ID (not the request path). The example currently shows /api/v1/agents, which doesn’t match the runtime/other docs examples.

Suggested change
"instance": "/api/v1/agents"
"instance": "req_01HZY3J8K9M7N4P2Q6R5S1T8UV"

Copilot uses AI. Check for mistakes.
Comment on lines +164 to +165
The `code` field is a 4-digit machine-readable error code grouped by category:

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

This paragraph refers to a code field, but the structured error payload uses error_code (and error_category) in both the ProblemDetail body and the error_detail envelope. Consider renaming the prose here to avoid implying a code JSON key.

Copilot uses AI. Check for mistakes.

## Rate Limiting

The API applies per-IP rate limiting via Litestar's built-in `RateLimitConfig`. Limits are configurable per deployment. Clients that exceed the limit receive `429 Too Many Requests` with code `RATE_LIMITED` (5000) and a `Retry-After` header.
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

Rate limiting section says responses include code RATE_LIMITED (5000); the JSON key is error_code (or error_detail.error_code in the envelope). Adjust wording to match the actual field names to avoid client confusion.

Suggested change
The API applies per-IP rate limiting via Litestar's built-in `RateLimitConfig`. Limits are configurable per deployment. Clients that exceed the limit receive `429 Too Many Requests` with code `RATE_LIMITED` (5000) and a `Retry-After` header.
The API applies per-IP rate limiting via Litestar's built-in `RateLimitConfig`. Limits are configurable per deployment. Clients that exceed the limit receive `429 Too Many Requests`; the response includes `error_code` `5000` (`RATE_LIMITED`), or `error_detail.error_code` `5000` in the enveloped form, and a `Retry-After` header.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/openapi/index.md`:
- Around line 14-16: Add a language specifier to the fenced code block
containing the endpoint example (the block showing "https://<your-host>/api/v1")
so markdown linting and syntax highlighting work; replace the opening fence ```
with ```text (or another appropriate language like bash) so the block becomes a
fenced code block with a language identifier.

In `@scripts/patch_sitemap.py`:
- Around line 38-41: EXTRA_URLS currently contains hardcoded absolute URLs tied
to the mkdocs site_url; update the code so it doesn't break when site_url
changes by either (a) adding a clear comment above EXTRA_URLS explaining the
dependency on mkdocs.yml's site_url and that these values must be updated if
site_url changes, or (b) programmatically reading mkdocs.yml to extract site_url
at runtime and constructing EXTRA_URLS from that base (parse mkdocs.yml for the
site_url key and join the known paths to form the full URLs before assigning to
EXTRA_URLS).
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 17dbdeaa-bb0d-4111-aff5-da5ab4d36edf

📥 Commits

Reviewing files that changed from the base of the PR and between 7af94de and 15cdc27.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • .github/workflows/pages-preview.yml
  • .github/workflows/pages.yml
  • .gitignore
  • CLAUDE.md
  • docs/architecture/index.md
  • docs/guides/quickstart.md
  • docs/index.md
  • docs/openapi/index.md
  • docs/rest-api.md
  • docs/user_guide.md
  • mkdocs.yml
  • pyproject.toml
  • scripts/export_openapi.py
  • scripts/patch_sitemap.py
  • src/synthorg/api/controllers/reports.py
💤 Files with no reviewable changes (1)
  • docs/rest-api.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Deploy Preview
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Agent
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Analyze (python)
  • GitHub Check: Dependency Review
🧰 Additional context used
📓 Path-based instructions (6)
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation is in docs/ (Markdown, built with Zensical, config: mkdocs.yml). Design spec in docs/design/ (12 pages). Architecture in docs/architecture/. Roadmap in docs/roadmap/. Security in docs/security.md. Licensing in docs/licensing.md.

Files:

  • docs/guides/quickstart.md
  • docs/user_guide.md
  • docs/index.md
  • docs/architecture/index.md
  • docs/openapi/index.md
pyproject.toml

📄 CodeRabbit inference engine (CLAUDE.md)

pyproject.toml: Set a global test timeout of 30 seconds per test in pyproject.toml. Do not add per-file pytest.mark.timeout(30) markers; non-default overrides like timeout(60) are allowed.
Pin all Python dependency versions using == in pyproject.toml
Organize Python dependencies into groups: test (pytest + plugins, hypothesis), dev (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Required: mem0ai, mmh3, cryptography, faker.

Files:

  • pyproject.toml
{pyproject.toml,src/synthorg/__init__.py}

📄 CodeRabbit inference engine (CLAUDE.md)

Version locations are pyproject.toml ([tool.commitizen].version) and src/synthorg/__init__.py (__version__)

Files:

  • pyproject.toml
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do not use from __future__ import annotations in Python -- Python 3.14 has PEP 649 native lazy annotations
Use except A, B: syntax (no parentheses) for exception handling in Python 3.14 per PEP 758 -- ruff enforces this
All public functions and methods must have type hints, with mypy strict mode enforcement
Google-style docstrings are required on all public classes and functions, enforced by ruff D rules
Create new objects rather than mutating existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (via model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 with conventions: allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields; use @computed_field for derived values instead of storing redundant fields; use NotBlankStr for all identifier and name fields including optional and tuple variants, instead of manual whitespace validators
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Maintain a line length of 88 characters (enforced by ruff)
Functions must be less than 50 lines, files must be less than 800 lines
Handle errors explicitly, never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)

Files:

  • scripts/export_openapi.py
  • scripts/patch_sitemap.py
  • src/synthorg/api/controllers/reports.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Every module with business logic must have from synthorg.observability import get_logger then logger = get_logger(__name__)
Always use logger as the variable name (not _logger, not log)
Always use event name constants from domain-specific modules under synthorg.observability.events (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT
Use structured logging with logger.info(EVENT, key=value) -- never logger.info("msg %s", val)
Log all error paths at WARNING or ERROR level with context before raising
Log all state transitions at INFO level
Use DEBUG level logging for object creation, internal flow, and entry/exit of key functions
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001, large/medium/small as aliases. Vendor names allowed only in: (1) Operations design page, (2) .claude/ files, (3) third-party import paths, (4) provider presets which are user-facing runtime data. Tests must use test-provider, test-small-001, etc.

Files:

  • src/synthorg/api/controllers/reports.py
src/**/*.py

⚙️ CodeRabbit configuration file

This project uses Python 3.14+ with PEP 758 except syntax: "except A, B:" (comma-separated, no parentheses) is correct and mandatory -- do NOT flag it as a typo or suggest parenthesized form. The "except builtins.MemoryError, RecursionError: raise" pattern is intentional project convention for system-error propagation. When evaluating the 50-line function limit, count only the function body excluding the signature lines, decorators, and docstring. Functions 1-5 lines over due to docstrings or multi-line signatures should not be flagged. Do not suggest extracting single-use helper functions called exactly once -- this reduces readability without improving maintainability.

Files:

  • src/synthorg/api/controllers/reports.py
🧠 Learnings (43)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to {docs/rest-api.md,docs/_generated/api-reference.html} : REST API reference in `docs/rest-api.md` + `docs/_generated/api-reference.html` (generated by `scripts/export_openapi.py`)
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to {docs/rest-api.md,docs/_generated/api-reference.html} : REST API reference in `docs/rest-api.md` + `docs/_generated/api-reference.html` (generated by `scripts/export_openapi.py`)

Applied to files:

  • docs/guides/quickstart.md
  • docs/user_guide.md
  • mkdocs.yml
  • .gitignore
  • docs/index.md
  • CLAUDE.md
  • docs/architecture/index.md
  • scripts/export_openapi.py
  • docs/openapi/index.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.

Applied to files:

  • docs/user_guide.md
  • mkdocs.yml
  • .gitignore
  • docs/index.md
  • CLAUDE.md
  • docs/architecture/index.md
  • docs/openapi/index.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations

Applied to files:

  • docs/user_guide.md
  • docs/index.md
  • CLAUDE.md
  • docs/architecture/index.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)

Applied to files:

  • docs/user_guide.md
  • docs/index.md
  • docs/architecture/index.md
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/user_guide.md
  • mkdocs.yml
  • .gitignore
  • docs/index.md
  • CLAUDE.md
  • docs/architecture/index.md
  • docs/openapi/index.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 7 design pages (index, agents, organization, communication, engine, memory, operations).

Applied to files:

  • docs/user_guide.md
  • docs/architecture/index.md
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/user_guide.md
  • docs/index.md
  • docs/architecture/index.md
📚 Learning: 2026-04-04T19:50:52.893Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-04T19:50:52.893Z
Learning: Applies to docs/**/*.md : Documentation is in `docs/` (Markdown, built with Zensical, config: `mkdocs.yml`). Design spec in `docs/design/` (12 pages). Architecture in `docs/architecture/`. Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`.

Applied to files:

  • docs/user_guide.md
  • mkdocs.yml
  • .gitignore
  • docs/index.md
  • CLAUDE.md
  • docs/architecture/index.md
📚 Learning: 2026-04-04T19:50:52.893Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-04T19:50:52.893Z
Learning: Before implementing any feature, read the relevant `docs/design/` page. When a spec topic is referenced (e.g. "the Agents page"), read that specific `docs/design/` page before coding.

Applied to files:

  • docs/user_guide.md
📚 Learning: 2026-04-04T19:50:52.893Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-04T19:50:52.893Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 12 design pages. The design spec is the starting point for architecture, data models, and behavior.

Applied to files:

  • docs/user_guide.md
  • CLAUDE.md
  • docs/architecture/index.md
📚 Learning: 2026-04-01T18:57:46.655Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T18:57:46.655Z
Learning: Applies to docs/api/**/*.md : Library reference in `docs/api/` (auto-generated via mkdocstrings + Griffe, AST-based)

Applied to files:

  • mkdocs.yml
  • .gitignore
  • docs/index.md
  • CLAUDE.md
  • docs/architecture/index.md
  • docs/openapi/index.md
📚 Learning: 2026-03-31T14:28:28.895Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:28:28.895Z
Learning: Applies to docs/**/*.md : Documentation files in `docs/` (Markdown, built with Zensical, config: `mkdocs.yml`); design spec in `docs/design/` (11 pages)

Applied to files:

  • mkdocs.yml
  • .gitignore
  • CLAUDE.md
  • docs/architecture/index.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers

Applied to files:

  • mkdocs.yml
  • docs/index.md
  • docs/openapi/index.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Build docs with `uv run zensical build` (output: `_site/docs/`); preview locally with `uv run zensical serve`

Applied to files:

  • .gitignore
  • .github/workflows/pages.yml
  • .github/workflows/pages-preview.yml
  • scripts/export_openapi.py
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Export OpenAPI schema with `uv run python scripts/export_openapi.py` (required before docs build)

Applied to files:

  • .gitignore
  • .github/workflows/pages.yml
  • .github/workflows/pages-preview.yml
  • scripts/export_openapi.py
📚 Learning: 2026-03-30T10:41:40.176Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-30T10:41:40.176Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations from spec occur

Applied to files:

  • docs/index.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality

Applied to files:

  • docs/index.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • docs/index.md
  • CLAUDE.md
  • docs/openapi/index.md
📚 Learning: 2026-04-02T12:21:16.739Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:21:16.739Z
Learning: Applies to .github/workflows/pages.yml : Pages job: version extraction from `pyproject.toml`, OpenAPI export, Astro + Zensical docs build (with version banner), GitHub Pages deploy on push to main

Applied to files:

  • .github/workflows/pages.yml
  • .github/workflows/pages-preview.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.

Applied to files:

  • .github/workflows/pages.yml
  • .github/workflows/pages-preview.yml
📚 Learning: 2026-04-04T19:50:52.893Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-04T19:50:52.893Z
Learning: Applies to site/src/**/*.{ts,tsx,astro} : Astro landing page (in `site/` directory) uses Astro 6, astrojs/react, React 19, Tailwind CSS 4, js-yaml

Applied to files:

  • .github/workflows/pages.yml
  • .github/workflows/pages-preview.yml
📚 Learning: 2026-04-02T12:21:16.739Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:21:16.739Z
Learning: Applies to site/package.json : Landing page dependencies in `site/package.json` (Astro 6, astrojs/react, React 19, Tailwind CSS 4)

Applied to files:

  • .github/workflows/pages.yml
  • .github/workflows/pages-preview.yml
📚 Learning: 2026-04-02T12:21:16.739Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:21:16.739Z
Learning: Applies to site/**/*.{astro,tsx,ts} : Landing page in `site/` (Astro + React islands via `astrojs/react`), includes `/get/` CLI install page, contact form, interactive dashboard preview, SEO

Applied to files:

  • .github/workflows/pages.yml
  • .github/workflows/pages-preview.yml
  • CLAUDE.md
📚 Learning: 2026-04-01T18:57:46.655Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T18:57:46.655Z
Learning: Applies to pyproject.toml : Docs group in `pyproject.toml` includes: `zensical`, `mkdocstrings[python]`, `griffe-pydantic`

Applied to files:

  • pyproject.toml
📚 Learning: 2026-04-04T19:50:52.893Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-04T19:50:52.893Z
Learning: Applies to pyproject.toml : Organize Python dependencies into groups: `test` (pytest + plugins, hypothesis), `dev` (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Required: `mem0ai`, `mmh3`, `cryptography`, `faker`.

Applied to files:

  • pyproject.toml
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Version bumping (pre-1.0): `fix:` = patch, `feat:` = patch, `feat!:` = minor, `BREAKING CHANGE` trailer = minor. Update version in `pyproject.toml` (`[tool.commitizen].version`) and `src/synthorg/__init__.py` (`__version__`)

Applied to files:

  • pyproject.toml
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to {pyproject.toml,src/synthorg/__init__.py} : Update version in `pyproject.toml` (`[tool.commitizen].version`) and `src/synthorg/__init__.py` (`__version__`)

Applied to files:

  • pyproject.toml
📚 Learning: 2026-04-02T08:47:46.313Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T08:47:46.313Z
Learning: Applies to pyproject.toml : Dev group in `pyproject.toml` includes: test group + ruff, mypy, pre-commit, commitizen, pip-audit

Applied to files:

  • pyproject.toml
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to scripts/**/*.py : Scripts in `scripts/` (CI/build utilities and development-time validation hooks) — relaxed ruff rules: `print` and deferred imports allowed

Applied to files:

  • pyproject.toml
📚 Learning: 2026-04-01T21:17:42.724Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T21:17:42.724Z
Learning: Applies to pyproject.toml : Required runtime dependencies: `mem0ai` (default and currently only memory backend), `cryptography` (Fernet encryption), `faker` (multi-locale name generation)

Applied to files:

  • pyproject.toml
📚 Learning: 2026-04-02T08:47:46.313Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T08:47:46.313Z
Learning: Applies to **/*.py : Include type hints for all public functions; enforce with mypy strict mode

Applied to files:

  • pyproject.toml
📚 Learning: 2026-03-15T22:16:31.632Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T22:16:31.632Z
Learning: Applies to **/*.py : Type hints: all public functions and classes require type hints, enforced with mypy strict mode.

Applied to files:

  • pyproject.toml
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).

Applied to files:

  • .github/workflows/pages-preview.yml
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).

Applied to files:

  • .github/workflows/pages-preview.yml
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile.sandbox : Docker sandbox: `synthorg-sandbox` — Python 3.14 + Node.js + git, non-root (UID 10001), agent code execution sandbox

Applied to files:

  • .github/workflows/pages-preview.yml
📚 Learning: 2026-04-02T08:47:46.313Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T08:47:46.313Z
Learning: Run full pytest suite with coverage: `uv run python -m pytest tests/ -n auto --cov=synthorg --cov-fail-under=80`

Applied to files:

  • .github/workflows/pages-preview.yml
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/api/**/*.py : Use Litestar for REST API and WebSocket API with JWT + API key + WS ticket authentication, RFC 9457 structured errors, and content negotiation.

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/api/**/*.py : Use Litestar for REST + WebSocket API. Controllers, guards, channels, JWT + API key + WS ticket auth, RFC 9457 structured errors.

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/api/**/*.py : REST API: Litestar framework, controllers with guards, channels for WebSocket, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. RFC 9457 structured errors (ErrorCategory, ErrorCode, ErrorDetail, ProblemDetail, CATEGORY_TITLES, category_title, category_type_uri, content negotiation).

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/synthorg/api/**/*.py : Litestar API must include setup wizard, auth/, auto-wiring, and lifecycle management

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/api/**/*.py : Authentication uses JWT + API key. Approval gate integration for high-risk operations.

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)

Applied to files:

  • docs/openapi/index.md
🪛 markdownlint-cli2 (0.22.0)
docs/openapi/index.md

[warning] 14-14: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (17)
src/synthorg/api/controllers/reports.py (1)

108-108: Correct fix for double-prefixed routes.

The Router in app.py mounts all controllers under api_config.api_prefix (default: /api/v1), so the controller's path should be the relative segment only. Changing from /api/v1/reports to /reports ensures endpoints register at the intended /api/v1/reports/* paths rather than /api/v1/api/v1/reports/*.

scripts/patch_sitemap.py (1)

44-127: Well-structured idempotent script with proper error handling.

The implementation correctly:

  • Uses defusedxml for secure XML parsing
  • Validates the root element before modification
  • Prevents duplicate entries by checking existing <loc> values
  • Skips rewriting when no changes are needed
  • Handles both parse and I/O errors with informative messages
pyproject.toml (2)

64-67: Explicit defusedxml pin with clear rationale.

The comment explains the dependency is also pulled transitively but is pinned explicitly for build script stability. This follows the project's convention of version pinning with ==.


215-217: Mypy override follows established pattern.

The ignore_missing_imports override for defusedxml.* is consistent with the existing overrides for other third-party libraries without complete type stubs.

docs/user_guide.md (1)

118-118: Link correctly updated to new OpenAPI docs location.

The relative path openapi/index.md is correct from docs/user_guide.md.

docs/architecture/index.md (1)

65-65: Link and description updated consistently.

The relative path ../openapi/index.md correctly navigates from docs/architecture/ to docs/openapi/, and the description accurately indicates coverage of both REST and WebSocket APIs.

docs/guides/quickstart.md (1)

131-131: Link updated to new OpenAPI docs location.

The relative path ../openapi/index.md correctly navigates from docs/guides/ to docs/openapi/.

mkdocs.yml (1)

136-136: Navigation entry updated to new OpenAPI docs location.

The path openapi/index.md correctly points to the new landing page under docs/openapi/.

docs/index.md (1)

132-132: Landing page link updated with accurate description.

The path openapi/index.md and description "REST + WebSocket API reference (Scalar/OpenAPI)" are consistent with the other documentation updates in this PR.

.github/workflows/pages.yml (1)

80-82: LGTM!

The sitemap patching step is correctly positioned after zensical build (which generates _site/docs/sitemap.xml) and after export_openapi.py (which generates the OpenAPI artifacts that zensical copies into _site/docs/openapi/). This ordering matches the documented dependency chain in scripts/patch_sitemap.py.

.gitignore (1)

68-72: LGTM!

The ignore patterns correctly target the two generated artifacts (reference.html and openapi.json) in their new location under docs/openapi/. The comment accurately documents their origin and purpose. This is a cleaner approach than ignoring an entire _generated/ directory.

.github/workflows/pages-preview.yml (1)

127-129: LGTM!

The sitemap patching step mirrors the production workflow (pages.yml), ensuring PR previews have complete sitemaps with the OpenAPI artifact URLs. The step ordering is correct.

CLAUDE.md (1)

62-62: LGTM!

The updated REST API reference documentation accurately reflects the new structure: docs/openapi/index.md as the landing page with generated reference.html (Scalar viewer) and openapi.json as static siblings. This aligns with the output paths in scripts/export_openapi.py and the .gitignore patterns. Based on learnings, this replaces the previous docs/rest-api.md + docs/_generated/api-reference.html structure.

scripts/export_openapi.py (3)

26-31: Good security hardening with Subresource Integrity.

Adding SRI (integrity + crossorigin="anonymous") to the Scalar CDN script prevents execution of tampered or compromised CDN content. The documented command for recomputing the hash when bumping versions is helpful for maintainability.


75-75: LGTM!

The banner link change from ../ to ./ is correct. Since reference.html is now a sibling of index.md (rendered as index.html) in docs/openapi/, the relative path ./ correctly navigates to the landing page.


83-87: SRI hash for Scalar 1.48.5 verified as correct.

The integrity hash matches the pinned version and will not cause browsers to block the script.

docs/openapi/index.md (1)

1-116: Comprehensive and well-structured API landing page.

The documentation accurately reflects the codebase:

  • Base URL /api/v1 matches ApiConfig.api_prefix default (verified in src/synthorg/api/config.py:268-270)
  • Documentation paths /docs/api and /docs/openapi.json match the OpenAPIConfig in src/synthorg/api/app.py:897-905
  • WebSocket path /api/v1/ws matches the path construction in src/synthorg/api/app.py:948-950

The endpoint groupings, authentication flow, pagination format, and error taxonomy provide a solid reference for API consumers.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.59%. Comparing base (7af94de) to head (722a02d).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1073   +/-   ##
=======================================
  Coverage   89.59%   89.59%           
=======================================
  Files         742      742           
  Lines       43408    43408           
  Branches     4359     4359           
=======================================
  Hits        38892    38892           
  Misses       3745     3745           
  Partials      771      771           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Second round of review fixes, covering 9 items from 4 external reviewers
(Gemini Code Assist, Copilot, Copilot PR reviewer, CodeRabbit) and
1 local docs-consistency agent re-run.

docs/openapi/index.md -- factual corrections:

- RFC 9457 example and prose: wrong field names (code/category) replaced
  with the real schema (error_code/error_category from ProblemDetail in
  src/synthorg/api/dto.py:115-117). Also corrected the 'instance' example
  value -- it's a request correlation ID (a1b2c3d4-...), not a request
  path. Fixed the type URI fragment format (#validation, not
  #validation-error) to match docs/errors.md and api/errors.py's
  category_type_uri(). Added the envelope (ApiResponse) form alongside
  the bare application/problem+json shape to mirror docs/errors.md.
  (Copilot C1, C2, C3, C4)
- Rate limiting section: error_code field name, not code. (Copilot C4)
- ETag/If-Match scope: only settings actually uses HTTP ETag/If-Match.
  Workflows, workflow_versions, workflow_executions, and tasks use an
  in-body expected_version: int field (a different optimistic-concurrency
  mechanism). Both produce the same VERSION_CONFLICT (4002) error shape
  but via different input channels. (docs-consistency CRITICAL)
- /auth/login: TokenResponse carries token/expires_in/must_change_password
  only, not a 'session record'. Session is a server-side side effect.
  (docs-consistency)
- /auth/me: UserInfoResponse is id/username/role/must_change_password,
  not 'session metadata'. (docs-consistency)
- /auth/sessions: documented the CEO ?scope=all behavior for listing all
  users' sessions across the org. (docs-consistency)
- Reports row: dropped 'scheduled' since reports.py only exposes
  POST /generate and GET /periods. (docs-consistency)
- Base URL fenced code block: added 'text' language specifier to satisfy
  markdownlint MD040. (CodeRabbit)

scripts/patch_sitemap.py -- dynamic base URL derivation:

- Replaced hardcoded EXTRA_URLS with EXTRA_PATHS (relative paths) and
  derive the base URL at runtime from the shortest existing <loc> entry
  in the sitemap (which is always the mkdocs index.md root). This keeps
  the script in sync with whatever site_url resolves to -- production,
  staging, or PR previews -- without requiring a code change when the
  docs domain moves. (Gemini G1, CodeRabbit R2)
- Added an early return if the sitemap has no <url> entries (would
  leave us with no base URL to derive from).
- # noqa: PLR0911 added to main() with justification (one return per
  distinct failure mode; 7 total, linter max is 6).
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/patch_sitemap.py`:
- Around line 47-143: main() is too large (~97 lines) and must be split into
<50-line helpers; refactor by extracting logical steps into small functions:
parsing (e.g., parse_sitemap or load_sitemap uses DefusedET.parse and the
ET.register_namespace call), root validation (validate_root checks root is not
None and tag == URLSET_TAG and returns root or exits), existing-URL collection
and base derivation (collect_existing_urls returns the existing set and
derive_base_url returns base_url), adding extras (add_extra_paths takes root,
base_url, EXTRA_PATHS and returns count added while printing skip/added lines),
and final write (write_sitemap handles ET.indent and tree.write with OSError
handling). Replace the monolithic main() flow with calls to these helpers (main
orchestrates the checks and returns the same exit codes) while preserving all
existing messages and symbols: SITEMAP_FILE, REPO_ROOT, SITEMAP_NS, URLSET_TAG,
URL_TAG, LOC_TAG, EXTRA_PATHS. Ensure each helper stays under the function-size
limit and unit of responsibility is single purpose.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9554cfce-540a-4f5a-b9e5-950a07d5ee38

📥 Commits

Reviewing files that changed from the base of the PR and between 15cdc27 and e3138a9.

📒 Files selected for processing (2)
  • docs/openapi/index.md
  • scripts/patch_sitemap.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do not use from __future__ import annotations in Python -- Python 3.14 has PEP 649 native lazy annotations
Use except A, B: syntax (no parentheses) for exception handling in Python 3.14 per PEP 758 -- ruff enforces this
All public functions and methods must have type hints, with mypy strict mode enforcement
Google-style docstrings are required on all public classes and functions, enforced by ruff D rules
Create new objects rather than mutating existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (via model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 with conventions: allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields; use @computed_field for derived values instead of storing redundant fields; use NotBlankStr for all identifier and name fields including optional and tuple variants, instead of manual whitespace validators
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Maintain a line length of 88 characters (enforced by ruff)
Functions must be less than 50 lines, files must be less than 800 lines
Handle errors explicitly, never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)

Files:

  • scripts/patch_sitemap.py
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation is in docs/ (Markdown, built with Zensical, config: mkdocs.yml). Design spec in docs/design/ (12 pages). Architecture in docs/architecture/. Roadmap in docs/roadmap/. Security in docs/security.md. Licensing in docs/licensing.md.

Files:

  • docs/openapi/index.md
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to {docs/rest-api.md,docs/_generated/api-reference.html} : REST API reference in `docs/rest-api.md` + `docs/_generated/api-reference.html` (generated by `scripts/export_openapi.py`)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to {docs/rest-api.md,docs/_generated/api-reference.html} : REST API reference in `docs/rest-api.md` + `docs/_generated/api-reference.html` (generated by `scripts/export_openapi.py`)

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/api/**/*.py : Use Litestar for REST API and WebSocket API with JWT + API key + WS ticket authentication, RFC 9457 structured errors, and content negotiation.

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/api/**/*.py : Use Litestar for REST + WebSocket API. Controllers, guards, channels, JWT + API key + WS ticket auth, RFC 9457 structured errors.

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/api/**/*.py : REST API: Litestar framework, controllers with guards, channels for WebSocket, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. RFC 9457 structured errors (ErrorCategory, ErrorCode, ErrorDetail, ProblemDetail, CATEGORY_TITLES, category_title, category_type_uri, content negotiation).

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-04-01T18:57:46.655Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T18:57:46.655Z
Learning: Applies to docs/api/**/*.md : Library reference in `docs/api/` (auto-generated via mkdocstrings + Griffe, AST-based)

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/api/**/*.py : Authentication uses JWT + API key. Approval gate integration for high-risk operations.

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/synthorg/api/**/*.py : Litestar API must include setup wizard, auth/, auto-wiring, and lifecycle management

Applied to files:

  • docs/openapi/index.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)

Applied to files:

  • docs/openapi/index.md
🔇 Additional comments (2)
docs/openapi/index.md (1)

1-225: Documentation migration looks consistent and complete.

The new /docs/openapi/ landing page is clear, internally consistent, and aligns with the sitemap/export changes and route updates in this PR.

scripts/patch_sitemap.py (1)

77-77: No change needed—the as exc clause is incompatible with PEP 758's simplified syntax.

PEP 758 allows except A, B: only when the exception is not captured with an as clause. Since this code uses as exc, the parenthesized syntax except (ET.ParseError, DefusedXmlException) as exc: is the correct and only valid form.

			> Likely an incorrect or invalid review comment.

…imit

CodeRabbit round-2 review flagged main() as ~97 lines, exceeding the
CLAUDE.md project convention 'Functions must be less than 50 lines, files
must be less than 800 lines'.

Extracted six single-purpose helpers (all under 25 lines):
- _parse_sitemap()          file existence + defusedxml parse
- _validate_root(tree)      urlset root element check
- _collect_existing_urls(r) existing <loc> text set builder
- _derive_base_url(set)     shortest-loc docs root derivation
- _add_extra_urls(...)      append missing EXTRA_PATHS entries
- _write_sitemap(tree, n)   ET.indent + tree.write with OSError handling

main() becomes a thin orchestrator (~20 lines) that composes the helpers
and returns the same exit codes as before. All existing error messages,
stderr routing, idempotent behavior, and return-code semantics preserved.

Also added a typing.cast on DefusedET.parse's return to satisfy mypy
strict under the defusedxml.* ignore_missing_imports override (which
otherwise resolves the call to Any and triggers no-any-return). The
cast pins the return type to ET.ElementTree[ET.Element[str] | None],
matching the declared helper signature.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/patch_sitemap.py`:
- Line 76: Replace the parenthesized multiple-exception clause with the PEP 758
style: change the except line that currently reads except (ET.ParseError,
DefusedXmlException) as exc: to use the non-parenthesized form so the handler
still catches both ET.ParseError and DefusedXmlException and binds the exception
to exc (i.e., update the except clause in scripts/patch_sitemap.py that
references ET.ParseError and DefusedXmlException to remove the parentheses).
- Around line 72-75: The cast uses an invalid generic type
ET.ElementTree[ET.Element[str] | None]; replace it with a non-generic
ElementTree type so mypy can understand it. Update the cast in the return
statement that wraps DefusedET.parse(SITEMAP_FILE) to cast to ET.ElementTree
(e.g., typing.cast(ET.ElementTree, DefusedET.parse(SITEMAP_FILE))) or to a
string literal "ET.ElementTree" if you prefer stringly-typed hints, keeping the
call to DefusedET.parse and SITEMAP_FILE unchanged.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 63663cb5-39d7-45d1-847b-405192a72ff0

📥 Commits

Reviewing files that changed from the base of the PR and between e3138a9 and 4517045.

📒 Files selected for processing (1)
  • scripts/patch_sitemap.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do not use from __future__ import annotations in Python -- Python 3.14 has PEP 649 native lazy annotations
Use except A, B: syntax (no parentheses) for exception handling in Python 3.14 per PEP 758 -- ruff enforces this
All public functions and methods must have type hints, with mypy strict mode enforcement
Google-style docstrings are required on all public classes and functions, enforced by ruff D rules
Create new objects rather than mutating existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (via model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 with conventions: allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields; use @computed_field for derived values instead of storing redundant fields; use NotBlankStr for all identifier and name fields including optional and tuple variants, instead of manual whitespace validators
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Maintain a line length of 88 characters (enforced by ruff)
Functions must be less than 50 lines, files must be less than 800 lines
Handle errors explicitly, never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)

Files:

  • scripts/patch_sitemap.py
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to {docs/rest-api.md,docs/_generated/api-reference.html} : REST API reference in `docs/rest-api.md` + `docs/_generated/api-reference.html` (generated by `scripts/export_openapi.py`)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:21:16.739Z
Learning: Applies to .github/workflows/pages.yml : Pages job: version extraction from `pyproject.toml`, OpenAPI export, Astro + Zensical docs build (with version banner), GitHub Pages deploy on push to main
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Export OpenAPI schema with `uv run python scripts/export_openapi.py` (required before docs build)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to **/*.py : Functions must be less than 50 lines; files must be less than 800 lines

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-04-04T19:50:52.893Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-04T19:50:52.893Z
Learning: Applies to **/*.py : Functions must be less than 50 lines, files must be less than 800 lines

Applied to files:

  • scripts/patch_sitemap.py
📚 Learning: 2026-04-01T06:12:03.047Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T06:12:03.047Z
Learning: Applies to {**/*.py,web/src/**/*.{ts,tsx}} : Keep functions under 50 lines and files under 800 lines

Applied to files:

  • scripts/patch_sitemap.py
🔇 Additional comments (7)
scripts/patch_sitemap.py (7)

1-27: Module structure and imports look good.

The docstring clearly explains the purpose, usage, and CI integration. Using defusedxml for hardened XML parsing is appropriate security hygiene, even for trusted build outputs.


29-45: Constants are well-structured with runtime base URL derivation.

Using relative paths in EXTRA_PATHS with runtime base URL derivation correctly decouples the script from a hardcoded site_url, supporting production, staging, and PR preview deployments.


84-99: Validation logic is robust.

Good defensive check for unexpected root elements with helpful error messaging that guides users toward resolution.


102-122: URL collection and base derivation logic is sound.

The shortest-URL heuristic for deriving the base URL is appropriate for mkdocs-generated sitemaps where index.md maps to the shortest path. The assumption is clearly documented.


125-138: Idempotent URL addition with good observability.

The function correctly checks against existing URLs before adding, ensuring idempotent reruns. Progress output aids CI debugging.


141-155: Write function with proper error handling.

ET.indent for readable output and explicit OSError handling with informative error messages is well-implemented.


158-184: Clean orchestration with proper exit codes.

The refactored main() is a concise orchestrator (~23 lines) with early returns for each failure mode. Idempotency is correctly implemented by skipping the write when no URLs were added.

"ET.ElementTree[ET.Element[str] | None]",
DefusedET.parse(SITEMAP_FILE),
)
except (ET.ParseError, DefusedXmlException) as exc:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use PEP 758 exception syntax without parentheses.

As per coding guidelines, Python 3.14 exception handling should use except A, B: syntax without parentheses.

🔧 Proposed fix
-    except (ET.ParseError, DefusedXmlException) as exc:
+    except ET.ParseError, DefusedXmlException as exc:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/patch_sitemap.py` at line 76, Replace the parenthesized
multiple-exception clause with the PEP 758 style: change the except line that
currently reads except (ET.ParseError, DefusedXmlException) as exc: to use the
non-parenthesized form so the handler still catches both ET.ParseError and
DefusedXmlException and binds the exception to exc (i.e., update the except
clause in scripts/patch_sitemap.py that references ET.ParseError and
DefusedXmlException to remove the parentheses).

CodeRabbit round-3 review flagged the generic cast type parameters
on ET.ElementTree/ET.Element as over-specified. While they are valid
in typeshed (both are generic), a simple type: ignore[no-any-return]
is cleaner and expresses the intent directly: defusedxml lacks
py.typed so mypy sees the call as Any and we are deliberately
silencing the warning because the result IS correctly-typed at
runtime.

Note: CodeRabbit also suggested switching the except clause to
PEP 758 unparenthesized form, but that is invalid Python syntax
when binding the exception with 'as' -- parentheses are still
required for multi-type except with a name binding. The
parenthesized form is kept.
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 5, 2026 07:05 — with GitHub Actions Inactive
@Aureliolo Aureliolo merged commit af19382 into main Apr 5, 2026
35 checks passed
@Aureliolo Aureliolo deleted the chore/openapi-unified-docs branch April 5, 2026 07:24
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 5, 2026 07:24 — with GitHub Actions Inactive
Aureliolo added a commit that referenced this pull request Apr 6, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.6.2](v0.6.1...v0.6.2)
(2026-04-06)


### Features

* add issue analyzer script for priority/scope management
([#1084](#1084))
([1ccba27](1ccba27))
* config fixes and deferred improvements from PR
[#1058](#1058) review
([#1067](#1067))
([2cac2d3](2cac2d3)),
closes [#1061](#1061)
[#1060](#1060)
* cumulative risk-unit action budgets
([#806](#806)) and automated
reporting ([#245](#245))
([#1063](#1063))
([4689816](4689816))
* fine-tuning pipeline + CompositeBackend + workflow lifecycle
([#1065](#1065))
([85b05bc](85b05bc)),
closes [#1001](#1001)
[#850](#850)
[#1058](#1058)
* memory consolidation upgrades (LLM Merge, Search-and-Ask, diversity
penalty, distillation capture)
([#1071](#1071))
([174e2be](174e2be)),
closes [#704](#704)
* migrate web dashboard from Radix UI to Base UI, activate CSP nonce,
rebuild org chart page, and fix agent routing
([#1083](#1083))
([ebc6921](ebc6921))
* v0.7.0 engine foundations -- structured failure diagnosis + auditable
decisions ([#1072](#1072))
([d341d37](d341d37))
* workflow templates and versioning with diff and rollback
([#1069](#1069))
([7af94de](7af94de)),
closes [#1006](#1006)
[#1008](#1008)


### Documentation

* unify REST API docs under /docs/openapi/ and patch sitemap
([#1073](#1073))
([af19382](af19382))


### Maintenance

* bump hypothesis from 6.151.10 to 6.151.11 in the all group
([#1086](#1086))
([3176318](3176318))
* bump nginxinc/nginx-unprivileged from `f99cc61` to `601c823` in
/docker/web in the all group
([#1085](#1085))
([5eb99ac](5eb99ac))
* bump the all group in /web with 3 updates
([#1087](#1087))
([8deae44](8deae44))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants