docs: unify REST API docs under /docs/openapi/ and patch sitemap#1073
docs: unify REST API docs under /docs/openapi/ and patch sitemap#1073
Conversation
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.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 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)
🧰 Additional context used📓 Path-based instructions (1)**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (13)📓 Common learnings📚 Learning: 2026-03-16T07:22:28.134ZApplied to files:
📚 Learning: 2026-04-04T19:50:52.893ZApplied to files:
📚 Learning: 2026-04-01T06:12:03.047ZApplied to files:
📚 Learning: 2026-03-31T21:07:37.470ZApplied to files:
📚 Learning: 2026-03-20T21:44:04.528ZApplied to files:
📚 Learning: 2026-03-16T07:22:28.134ZApplied to files:
📚 Learning: 2026-04-04T19:50:52.893ZApplied to files:
📚 Learning: 2026-03-14T15:43:05.601ZApplied to files:
📚 Learning: 2026-03-14T16:18:57.267ZApplied to files:
📚 Learning: 2026-03-15T16:55:07.730ZApplied to files:
📚 Learning: 2026-03-14T16:18:57.267ZApplied to files:
📚 Learning: 2026-03-14T15:43:05.601ZApplied to files:
🔇 Additional comments (2)
WalkthroughReplaces 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)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
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.
scripts/patch_sitemap.py
Outdated
| EXTRA_URLS: tuple[str, ...] = ( | ||
| "https://synthorg.io/docs/openapi/reference.html", | ||
| "https://synthorg.io/docs/openapi/openapi.json", | ||
| ) |
There was a problem hiding this comment.
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.
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure 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 FilesNone |
There was a problem hiding this comment.
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.mdand update all internal nav/link references. - Update
export_openapi.pyto emitdocs/openapi/reference.html+docs/openapi/openapi.json(with SRI on the Scalar CDN script). - Add
scripts/patch_sitemap.pyand wire it into GitHub Pages workflows; adddefusedxmlas an explicit docs dependency; fixReportsController.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.
docs/openapi/index.md
Outdated
| "type": "https://synthorg.io/docs/errors/#validation-error", | ||
| "title": "Validation failed", | ||
| "status": 422, | ||
| "detail": "Field 'name' is required", | ||
| "code": 2001, |
There was a problem hiding this comment.
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.
docs/openapi/index.md
Outdated
| "detail": "Field 'name' is required", | ||
| "code": 2001, | ||
| "category": "validation", | ||
| "instance": "/api/v1/agents" |
There was a problem hiding this comment.
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.
| "instance": "/api/v1/agents" | |
| "instance": "req_01HZY3J8K9M7N4P2Q6R5S1T8UV" |
docs/openapi/index.md
Outdated
| The `code` field is a 4-digit machine-readable error code grouped by category: | ||
|
|
There was a problem hiding this comment.
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.
docs/openapi/index.md
Outdated
|
|
||
| ## 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. |
There was a problem hiding this comment.
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.
| 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. |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (15)
.github/workflows/pages-preview.yml.github/workflows/pages.yml.gitignoreCLAUDE.mddocs/architecture/index.mddocs/guides/quickstart.mddocs/index.mddocs/openapi/index.mddocs/rest-api.mddocs/user_guide.mdmkdocs.ymlpyproject.tomlscripts/export_openapi.pyscripts/patch_sitemap.pysrc/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 indocs/design/(12 pages). Architecture indocs/architecture/. Roadmap indocs/roadmap/. Security indocs/security.md. Licensing indocs/licensing.md.
Files:
docs/guides/quickstart.mddocs/user_guide.mddocs/index.mddocs/architecture/index.mddocs/openapi/index.md
pyproject.toml
📄 CodeRabbit inference engine (CLAUDE.md)
pyproject.toml: Set a global test timeout of 30 seconds per test inpyproject.toml. Do not add per-filepytest.mark.timeout(30)markers; non-default overrides liketimeout(60)are allowed.
Pin all Python dependency versions using==inpyproject.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) andsrc/synthorg/__init__.py(__version__)
Files:
pyproject.toml
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Do not usefrom __future__ import annotationsin Python -- Python 3.14 has PEP 649 native lazy annotations
Useexcept 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), usecopy.deepcopy()at construction +MappingProxyTypewrapping for read-only enforcement.
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (viamodel_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=Falsein all ConfigDict declarations to reject NaN/Inf in numeric fields; use@computed_fieldfor derived values instead of storing redundant fields; useNotBlankStrfor all identifier and name fields including optional and tuple variants, instead of manual whitespace validators
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_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.pyscripts/patch_sitemap.pysrc/synthorg/api/controllers/reports.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
src/synthorg/**/*.py: Every module with business logic must havefrom synthorg.observability import get_loggerthenlogger = get_logger(__name__)
Always useloggeras the variable name (not_logger, notlog)
Always use event name constants from domain-specific modules undersynthorg.observability.events(e.g.,API_REQUEST_STARTEDfromevents.api,TOOL_INVOKE_STARTfromevents.tool). Import directly:from synthorg.observability.events.<domain> import EVENT_CONSTANT
Use structured logging withlogger.info(EVENT, key=value)-- neverlogger.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/smallas 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 usetest-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.mddocs/user_guide.mdmkdocs.yml.gitignoredocs/index.mdCLAUDE.mddocs/architecture/index.mdscripts/export_openapi.pydocs/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.mdmkdocs.yml.gitignoredocs/index.mdCLAUDE.mddocs/architecture/index.mddocs/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.mddocs/index.mdCLAUDE.mddocs/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.mddocs/index.mddocs/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.mdmkdocs.yml.gitignoredocs/index.mdCLAUDE.mddocs/architecture/index.mddocs/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.mddocs/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.mddocs/index.mddocs/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.mdmkdocs.yml.gitignoredocs/index.mdCLAUDE.mddocs/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.mdCLAUDE.mddocs/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.gitignoredocs/index.mdCLAUDE.mddocs/architecture/index.mddocs/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.gitignoreCLAUDE.mddocs/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.ymldocs/index.mddocs/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.ymlscripts/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.ymlscripts/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.mdCLAUDE.mddocs/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.ymlCLAUDE.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.pymounts all controllers underapi_config.api_prefix(default:/api/v1), so the controller'spathshould be the relative segment only. Changing from/api/v1/reportsto/reportsensures 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
defusedxmlfor 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: Explicitdefusedxmlpin 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_importsoverride fordefusedxml.*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.mdis correct fromdocs/user_guide.md.docs/architecture/index.md (1)
65-65: Link and description updated consistently.The relative path
../openapi/index.mdcorrectly navigates fromdocs/architecture/todocs/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.mdcorrectly navigates fromdocs/guides/todocs/openapi/.mkdocs.yml (1)
136-136: Navigation entry updated to new OpenAPI docs location.The path
openapi/index.mdcorrectly points to the new landing page underdocs/openapi/.docs/index.md (1)
132-132: Landing page link updated with accurate description.The path
openapi/index.mdand 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 afterexport_openapi.py(which generates the OpenAPI artifacts that zensical copies into_site/docs/openapi/). This ordering matches the documented dependency chain inscripts/patch_sitemap.py..gitignore (1)
68-72: LGTM!The ignore patterns correctly target the two generated artifacts (
reference.htmlandopenapi.json) in their new location underdocs/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.mdas the landing page with generatedreference.html(Scalar viewer) andopenapi.jsonas static siblings. This aligns with the output paths inscripts/export_openapi.pyand the.gitignorepatterns. Based on learnings, this replaces the previousdocs/rest-api.md+docs/_generated/api-reference.htmlstructure.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. Sincereference.htmlis now a sibling ofindex.md(rendered asindex.html) indocs/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/v1matchesApiConfig.api_prefixdefault (verified insrc/synthorg/api/config.py:268-270)- Documentation paths
/docs/apiand/docs/openapi.jsonmatch theOpenAPIConfiginsrc/synthorg/api/app.py:897-905- WebSocket path
/api/v1/wsmatches the path construction insrc/synthorg/api/app.py:948-950The endpoint groupings, authentication flow, pagination format, and error taxonomy provide a solid reference for API consumers.
Codecov Report✅ All modified and coverable lines are covered by tests. 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. 🚀 New features to boost your workflow:
|
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).
There was a problem hiding this comment.
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
📒 Files selected for processing (2)
docs/openapi/index.mdscripts/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 usefrom __future__ import annotationsin Python -- Python 3.14 has PEP 649 native lazy annotations
Useexcept 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), usecopy.deepcopy()at construction +MappingProxyTypewrapping for read-only enforcement.
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (viamodel_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=Falsein all ConfigDict declarations to reject NaN/Inf in numeric fields; use@computed_fieldfor derived values instead of storing redundant fields; useNotBlankStrfor all identifier and name fields including optional and tuple variants, instead of manual whitespace validators
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_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 indocs/design/(12 pages). Architecture indocs/architecture/. Roadmap indocs/roadmap/. Security indocs/security.md. Licensing indocs/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—theas excclause is incompatible with PEP 758's simplified syntax.PEP 758 allows
except A, B:only when the exception is not captured with anasclause. Since this code usesas exc, the parenthesized syntaxexcept (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.
There was a problem hiding this comment.
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
📒 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 usefrom __future__ import annotationsin Python -- Python 3.14 has PEP 649 native lazy annotations
Useexcept 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), usecopy.deepcopy()at construction +MappingProxyTypewrapping for read-only enforcement.
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (viamodel_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=Falsein all ConfigDict declarations to reject NaN/Inf in numeric fields; use@computed_fieldfor derived values instead of storing redundant fields; useNotBlankStrfor all identifier and name fields including optional and tuple variants, instead of manual whitespace validators
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_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
defusedxmlfor 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_PATHSwith runtime base URL derivation correctly decouples the script from a hardcodedsite_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.mdmaps 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.indentfor readable output and explicitOSErrorhandling 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: |
There was a problem hiding this comment.
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.
🤖 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>
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
/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 wasURL is unknown to Googlein 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.md→docs/openapi/index.mdwith substantially expanded contentscripts/export_openapi.pynow writesdocs/openapi/reference.html+docs/openapi/openapi.jsonas siblings of the landing page, so zensical copies them through on buildmkdocs.ymlnav entry updated (REST API: openapi/index.md)docs/index.md,docs/user_guide.md,docs/architecture/index.md,docs/guides/quickstart.md, andCLAUDE.md.gitignorenow ignores the two generated artifacts specifically instead of the wholedocs/_generated/directory (which is gone)Sitemap discoverability
scripts/patch_sitemap.pyinserts the static artifact URLs into_site/docs/sitemap.xmlafter zensical build. Idempotent, defusedxml-hardened, validates root element, normalizes whitespace, handles OSError on write.github/workflows/pages.ymlandpages-preview.ymlafter the zensical build stepdefusedxml==0.7.1added explicitly to thedocsdependency group (was only transitive viapy-serializable)defusedxml.*added to mypyignore_missing_importsoverridesBackend fix uncovered during review
src/synthorg/api/controllers/reports.py:ReportsController.pathwas hardcoded to/api/v1/reports, producing the double-prefixed/api/v1/api/v1/reports/*routes when wrapped by the/api/v1Router. Changed to/reportsso endpoints register at/api/v1/reports/generateand/api/v1/reports/periods, matchingdocs/design/operations.mdand the new landing page. Verified via live OpenAPI schema dumpSRI for Scalar CDN script
scripts/export_openapi.pynow emits the Scalar viewer<script>tag withintegrity="sha384-..."+crossorigin="anonymous"so a CDN compromise can't silently serve tampered JS toreference.htmlviewersSCALAR_VERSIONTest plan
uv run ruff check,ruff format --check,mypyall clean on touched filesuv run python -m pytest tests/unit/api/ -n 8→ 1493 passedrm -rf _site/→export_openapi.py→generate_comparison.py→zensical build→patch_sitemap.py→ sitemap contains all 3 openapi URLs;_site/docs/openapi/containsindex.html,reference.html,openapi.json; SRI attributes present on the CDN script tagskip (already present)for both URLs and doesn't rewrite/api/v1/reports/generateand/api/v1/reports/periodsReview coverage
Pre-reviewed by 7 agents in parallel:
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.