Skip to content

fix: per-worktree git-hook isolation + hookify gate migration + MSW drift fix#1949

Merged
Aureliolo merged 7 commits into
mainfrom
fix/worktree-hooks-isolation
May 16, 2026
Merged

fix: per-worktree git-hook isolation + hookify gate migration + MSW drift fix#1949
Aureliolo merged 7 commits into
mainfrom
fix/worktree-hooks-isolation

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Closes #1947

Summary

  • Hook isolation (Option A): committed venv-agnostic wrappers scripts/git-hooks/{_run-hook.sh,pre-commit,pre-push,commit-msg} + relative core.hooksPath=scripts/git-hooks (set by scripts/install_git_hooks.sh). Each worktree resolves its own venv at runtime via git rev-parse --show-toplevel; UV_FROZEN=1/--frozen so no hook can rewrite uv.lock. No extensions.worktreeConfig, no per-worktree pre-commit install, deletion-safe by construction. Verified empirically: relative core.hooksPath resolves per-worktree on Git-for-Windows + linked worktrees. .gitattributes pins the extensionless wrappers to LF.
  • pytest-unit "files were modified": structural fix (UV_FROZEN) + a pre/post git status reconcile guard in scripts/run_affected_tests.py that reverts only run-induced tracked changes (never the developer's work), fails closed if post-run status is unreadable.
  • long-running-loops failure: root-caused as collateral of the shared-hooks band-aid + uv.lock churn (gate is read-only, passes clean on the rebased branch); structurally fixed by the per-worktree venv. Interpreter+frozen invariant pinned by a wrapper contract test.
  • Hookify enforcement (decision B2): migrated to guaranteed-firing gates (.claude/settings.json PreToolUse: check_no_pr_create.sh, check_no_cd_prefix.sh, check_no_local_coverage.sh, check_enforce_parallel_tests.sh; .pre-commit-config.yaml: check_no_stdlib_logging.py), 9 inert .claude/hookify.*.md deleted, decision recorded in docs/architecture/decisions.md. pep758-except/function-length classified advisory (902 pre-existing / ruff PLR0915 proxy). enforce-parallel-tests rewritten to correct intent (no explicit -n; -n0 only for a single :: test; benchmarks exempt) since the literal rule would have blocked the documented pytest -m unit.
  • Bulk-edit guard relaxed (user decision): native Edit/Write allowed; only shell in-place rewrites blocked.
  • MSW drift (option C): web/public/mockServiceWorker.js gitignored + regenerated by a guarded web postinstall. CI drift-guard out of scope (owned by CI: split test job by type (unit / integration / e2e) for faster signal #1938).
  • OpenCode parity: mirrored the 4 new gates in .opencode/plugins/synthorg-hooks.ts (replaced drifted inline regexes with runHookScript), removed deleted-hookify refs from opencode.json.

Test plan

  • New tests: tests/unit/scripts/test_git_hooks_wrapper.py (pins the pre-commit hook-impl argv contract), test_pretooluse_bash_gates.py, test_check_no_stdlib_logging.py, test_check_no_bulk_edit.py, plus reconcile-guard + fail-closed + malformed-envelope cases in test_run_affected_tests.py. 119 gate tests green.
  • uv run ruff check src/ tests/ scripts/, ruff format --check, mypy (changed) clean; full tests/unit/scripts/ (1480) pass (2 Windows symlink-privilege skips).
  • End-to-end: every commit + push on this branch ran through the new committed wrappers; the full pre-push gate suite (incl. long-running loops, convention-gate inventory, no-stdlib-logging) passed green with no "files were modified by this hook".

Review coverage

/pre-pr-review: 10 agents. issue-resolution-verifier confirmed all 5 acceptance criteria RESOLVED. 8 actionable findings (OpenCode parity + fail-closed hardening) implemented with test coverage; code-simplifier's one PCRE-in-grep -E regression caught empirically and reverted. Triage: _audit/pre-pr-review/triage.md.

Aureliolo added 5 commits May 16, 2026 23:37
Pre-reviewed by 10 agents; 8 findings addressed (OpenCode plugin/opencode.json parity, fail-closed git-status reconcile + _merge_base + 4 bash gates + check_no_bulk_edit on malformed envelopes, path-traversal regex comment).
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 16, 2026

Dependency Review

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

Scanned Files

None

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces structural improvements to development tooling, specifically focusing on Git hook isolation across worktrees and the enforcement of development conventions. By moving hookify rules into active PreToolUse gates and adding a reconcile guard for test runs, the changes significantly reduce flaky 'files modified' errors and improve environment consistency. Additionally, it streamlines Mock Service Worker maintenance by automating its generation.

Highlights

  • Git Hook Isolation: Implemented venv-agnostic wrappers and relative core.hooksPath configuration to ensure each worktree manages its own hooks independently, preventing cross-worktree venv poisoning.
  • Hookify Migration: Migrated declarative hookify rules to guaranteed-firing PreToolUse gates in .claude/settings.json and deleted the now-inert .claude/hookify.*.md files.
  • Test Stability: Added a git status reconcile guard to scripts/run_affected_tests.py and enforced UV_FROZEN to prevent spurious 'files were modified' errors during test execution.
  • MSW Management: Gitignored mockServiceWorker.js and automated its regeneration via the web package postinstall script to eliminate drift.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 16, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​types/​grecaptcha@​3.0.91001007180100
Addednpm/​vitest@​4.1.6961007999100
Addednpm/​@​astrojs/​sitemap@​3.7.21001008289100
Addednpm/​@​astrojs/​react@​5.0.5991008296100
Addednpm/​tailwindcss@​4.3.01001008498100
Addednpm/​astro@​6.3.3981008898100
Addednpm/​wrangler@​4.92.0991009296100

View full report

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: daf6e2e6-b636-460d-9b68-43344137409f

📥 Commits

Reviewing files that changed from the base of the PR and between 593265d and e8cca44.

📒 Files selected for processing (2)
  • scripts/check_no_bulk_edit.py
  • tests/unit/scripts/test_check_no_bulk_edit.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). (8)
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: Test E2E
  • GitHub Check: Test Integration
  • GitHub Check: Test Unit
  • GitHub Check: Dashboard Test
  • GitHub Check: Lighthouse Dashboard
  • GitHub Check: Lighthouse Site
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
{src,tests}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Comments explain WHY only; no reviewer citations / issue back-refs / migration framing. Enforced by check_no_review_origin_in_code.py + check_no_migration_framing.py

No from __future__ import annotations (Python 3.14 has PEP 649). Use PEP 758 except for except A, B: (require parens when binding)

Async: use asyncio.TaskGroup for fan-out/fan-in; helpers catch Exception (re-raise MemoryError/RecursionError)

Clock seam: clock: Clock | None = None; tests inject FakeClock. Lifecycle: services own _lifecycle_lock; timed-out stops mark unrestartable

Vendor-agnostic: NEVER use real vendor names in project code/tests. Use example-provider, test-provider, example-{large,medium,small}-001. Allowed in .claude/, third-party imports, providers/presets.py, web/public/provider-logos/

Files:

  • tests/unit/scripts/test_check_no_bulk_edit.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Test markers: @pytest.mark.{unit,integration,e2e,slow}. Async auto. Timeout 30s global. Coverage 80% min

Windows tests: use WindowsSelectorEventLoopPolicy (3.14 IOCP teardown race). Subprocess tests override back

Test doubles: use FakeClock for the Clock seam, mock_of[T](**overrides) for typed-boundary substitutions, SimpleNamespace for attribute-bags. Bare MagicMock at typed boundaries is blocked by scripts/check_mock_spec.py (zero-tolerance, no baseline)

FakeClock and mock_of import from tests._shared; inject via clock= and the helper's spec subscript

Hypothesis: 10 deterministic CI examples; failures are real bugs (fix + add @example(...))

Flaky tests: NEVER skip/xfail; fix fundamentally. Use asyncio.Event().wait() not sleep(large)

Files:

  • tests/unit/scripts/test_check_no_bulk_edit.py

⚙️ CodeRabbit configuration file

Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare @settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which @given() honors automatically.

Files:

  • tests/unit/scripts/test_check_no_bulk_edit.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Read `docs/design/` page before implementing; deviations need approval per DESIGN_SPEC.md
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Present every plan for accept/deny before coding
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Reuse `web/src/components/ui/` design tokens; see `web/CLAUDE.md` for React 19 Web Dashboard Design System
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: No region/currency/locale privileged; use metric units; use British English per docs/reference/regional-defaults.md
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Every convention PR must ship its enforcement gate per docs/reference/convention-gates.md
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Never edit `tests/baselines/unit_timing.json` or `scripts/*_baseline.{txt,json}` / `scripts/_*_baseline.py`; timeout/slow test failures indicate source-code regression. PreToolUse-blocked. Bypass via `ALLOW_BASELINE_GROWTH=1 git commit ...` with explicit user approval
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: After issue: branch + commit + push (no auto-PR); use `/pre-pr-review`. After PR: `/aurelio-review-pr` for external feedback. Fix EVERYTHING valid; no deferring
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Use `d2` for architecture/nested containers diagrams, `mermaid` for flowcharts/sequence/pipelines. Markdown tables for tabular data. D2 theme 200 (Dark Mauve), D2 CLI pinned to v0.7.1 in CI
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: API startup lifecycle: construction phase wires synchronous services; on_startup wires services needing connected persistence backend. Construction ordering: `agent_registry` before `auto_wire_meetings`; `tunnel_provider` wired unconditionally. On-startup ordering: `SettingsService` before `WorkflowExecutionObserver`; `OntologyService` after `persistence.connect()`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: `post_setup_reinit()` propagates failures, and `settings_svc.set("api", "setup_complete", "true")` only runs if reinit succeeds. Check/validate/reinit/persist sequence serialised under `COMPLETE_LOCK` to prevent concurrent setup races
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: xdist `-n 8 --dist=loadfile` auto-applied via pyproject `addopts` (`loadfile` prevents Python 3.14+ Windows ProactorEventLoop leak)
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Git commits: `<type>: <description>` (feat/fix/refactor/docs/test/chore/perf/ci); commitizen-enforced
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Signed commits required on protected refs (GPG/SSH or GitHub App via `synthorg-repo-bot`)
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Branches: `<type>/<slug>` from main
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Pre-commit/pre-push hooks: `.pre-commit-config.yaml`. Tool-call gates: `.claude/settings.json` PreToolUse (`scripts/check_*.sh`/`.py`)
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: Squash merge. PR body becomes squash commit; trailers (`Release-As`, `Closes `#N``) must be in PR body
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: GitHub queries: use `gh issue list` via Bash, NOT MCP `list_issues`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: After every squash merge → run `/post-merge-cleanup`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T23:00:39.975Z
Learning: CLI is Docker-only (init/start/stop/status); features go in dashboard + REST API
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.

Applied to files:

  • scripts/check_no_bulk_edit.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
🔇 Additional comments (8)
scripts/check_no_bulk_edit.py (3)

1-46: LGTM!


49-88: LGTM!


91-131: LGTM!

tests/unit/scripts/test_check_no_bulk_edit.py (5)

1-34: LGTM!


36-62: LGTM!


65-94: LGTM!


97-133: LGTM!


136-173: LGTM!


Walkthrough

This PR migrates hook enforcement from inert .claude/hookify.*.md markdown rule files to a committed, deterministic architecture. It introduces a venv-agnostic per-worktree git-hook system with core.hooksPath pointing to scripts/git-hooks/, new PreToolUse bash gate scripts for command restrictions (PR creation, cd prefix, coverage, parallel tests), and a Python AST-based stdlib logging enforcement gate. The system is wired into Claude Code via .claude/settings.json and pre-commit via .pre-commit-config.yaml. Test-run mutations are prevented via worktree reconciliation in run_affected_tests.py. Bulk-edit policy is refined to block only shell in-place rewrites. Comprehensive test coverage validates all gate behaviors, infrastructure contracts, and edge cases. Documentation and web configuration are updated to reflect the new approach.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: per-worktree git-hook isolation, hookify gate migration, and MSW drift fix. It is concise and specific.
Description check ✅ Passed The description is comprehensive and directly related to the changeset. It covers hook isolation, pytest-unit fixes, hookify migration, bulk-edit relaxation, MSW drift, and OpenCode parity, all supported by the file changes.
Docstring Coverage ✅ Passed Docstring coverage is 53.15% which is sufficient. The required threshold is 40.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 16, 2026 22:26 — with GitHub Actions Inactive
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 16, 2026

Merging this PR will not alter performance

✅ 21 untouched benchmarks
⏩ 33 skipped benchmarks1


Comparing fix/worktree-hooks-isolation (e8cca44) with main (0b818d5)

Open in CodSpeed

Footnotes

  1. 33 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

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 migrates "hookify" rules from declarative Markdown files to committed shell scripts and Python gates, ensuring consistent enforcement across Claude Code, OpenCode, and pre-commit. It introduces a venv-agnostic git-hook wrapper system using a relative core.hooksPath to provide worktree isolation and prevent broken hooks. Key additions include a gate against stdlib logging in application code, a worktree reconciliation step in run_affected_tests.py to revert tracked files modified during test runs, and an update to the bulk-edit guard to allow native tool-based replacements. Review feedback identifies necessary improvements to regex patterns for pytest flag enforcement to handle = syntax, a type check for JSON payloads in the bulk-edit guard to prevent potential AttributeErrors, and a more precise check for Git renames to avoid false positives with filenames containing ->.

Comment thread scripts/check_enforce_parallel_tests.sh Outdated

# An explicit, NON-zero worker count is always wrong: pyproject
# addopts already applies -n=8 --dist=loadfile. Omit the flag.
if echo "$COMMAND" | grep -qE '(^|[[:space:]])(-n[[:space:]]*([1-9][0-9]*|auto|logical)|--numprocesses[[:space:]]+([1-9][0-9]*|auto|logical))(\b|$)'; then
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 regex for -n and --numprocesses does not account for the = assignment syntax (e.g., -n=8 or --numprocesses=8), which is supported by pytest. This allows developers to bypass the parallel execution enforcement by using the equals sign.

Suggested change
if echo "$COMMAND" | grep -qE '(^|[[:space:]])(-n[[:space:]]*([1-9][0-9]*|auto|logical)|--numprocesses[[:space:]]+([1-9][0-9]*|auto|logical))(\b|$)'; then
if echo "$COMMAND" | grep -qE '(^|[[:space:]])(-n([[:space:]]*|=)([1-9][0-9]*|auto|logical)|--numprocesses([[:space:]]+|=)([1-9][0-9]*|auto|logical))(\b|$)'; then

Comment thread scripts/check_enforce_parallel_tests.sh Outdated

# xdist-disable: only legitimate to read ONE test's full log, so
# require a node id. A bare directory/suite run with -n0 is blocked.
if echo "$COMMAND" | grep -qE '(^|[[:space:]])(-n[[:space:]]*0|--numprocesses[[:space:]]+0|--dist[[:space:]]+no|-p[[:space:]]+no:xdist)(\b|$)'; then
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

Similar to the previous check, the regex for disabling xdist does not handle the = assignment syntax (e.g., -n=0, --numprocesses=0, or --dist=no), providing a way to bypass the enforcement.

Suggested change
if echo "$COMMAND" | grep -qE '(^|[[:space:]])(-n[[:space:]]*0|--numprocesses[[:space:]]+0|--dist[[:space:]]+no|-p[[:space:]]+no:xdist)(\b|$)'; then
if echo "$COMMAND" | grep -qE '(^|[[:space:]])(-n([[:space:]]*|=)0|--numprocesses([[:space:]]+|=)0|--dist([[:space:]]+|=)no|-p[[:space:]]+no:xdist)(\b|$)'; then

Comment on lines 56 to +57
payload = json.loads(raw)
except json.JSONDecodeError:
return 0

tool_name = payload.get("tool_name", "")
tool_input = payload.get("tool_input") or {}

if tool_name == "Edit" and tool_input.get("replace_all") is True:
except json.JSONDecodeError as exc:
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 script assumes json.loads(raw) always returns a dictionary. However, json.loads can return other types (like a list or a primitive), which would cause an AttributeError when calling .get() later. A type check should be added to ensure the payload is a dictionary. Following the project's Python 3.14 style, multiple exceptions can be caught without parentheses.

        payload = json.loads(raw)
        if not isinstance(payload, dict):
            raise ValueError(f"Expected JSON object, got {type(payload).__name__}")
    except json.JSONDecodeError, ValueError as exc:
References
  1. PEP 758 makes except A, B: (comma-separated, no parens) valid Python. This codebase uses that form intentionally. (link)

Comment on lines +847 to +854
# Porcelain v1: 2 status chars, a space, then the path(s).
payload = line[3:]
if " -> " in payload:
old, new = payload.split(" -> ", 1)
paths.add(old.strip())
paths.add(new.strip())
else:
paths.add(payload.strip())
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 logic for identifying renames is too broad as it splits any line containing -> regardless of the Git status. If a filename literally contains -> (which is valid in many filesystems), this will incorrectly parse it as a rename and attempt to restore non-existent paths, leading to a false-positive failure of the hook. The check should be restricted to lines with the R (Rename) status.

Suggested change
# Porcelain v1: 2 status chars, a space, then the path(s).
payload = line[3:]
if " -> " in payload:
old, new = payload.split(" -> ", 1)
paths.add(old.strip())
paths.add(new.strip())
else:
paths.add(payload.strip())
# Porcelain v1: 2 status chars, a space, then the path(s).
status = line[:2]
payload = line[3:]
if "R" in status and " -> " in payload:
old, new = payload.split(" -> ", 1)
paths.add(old.strip())
paths.add(new.strip())
else:
paths.add(payload.strip())

Copy link
Copy Markdown
Contributor

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

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

Inline comments:
In @.opencode/plugins/synthorg-hooks.ts:
- Around line 30-34: The comment block starting with "The former
.claude/hookify.*.md rules were migrated to the committed scripts..." contains
migration-framing prose and should be replaced with a short "why" comment that
explains the current implementation rationale only; remove references to
migration history or reviewer/issue back-refs and instead state the purpose
(e.g., that the listed scripts centralize hook rules for OpenCode and Claude
Code) so the comment in synthorg-hooks.ts contains only implementation
rationale.

In `@docs/reference/convention-gates.md`:
- Line 71: Update the markdown so the inline code span doesn't include a
trailing space: change the snippet `` `cd ` `` to `` `cd` `` and place any
necessary trailing space outside the backticks; apply this change in the
description of check_no_cd_prefix.sh in the convention-gates documentation where
the `cd ` example appears to satisfy markdownlint MD038.

In `@scripts/check_enforce_parallel_tests.sh`:
- Around line 65-75: The regex checks on COMMAND for explicit -n/--numprocesses
and for single-process flags miss equals-sign forms (e.g. -n=8,
--numprocesses=0, --dist=no), so update both grep -qE patterns to accept either
whitespace or an equals sign after the option names; specifically modify the
expressions that reference COMMAND (the first if checking -n/--numprocesses and
the second if checking -n0/--numprocesses0/--dist/no/-p no:xdist) to allow
(?:[[:space:]]*|=) between the flag and its value and to handle --dist=no and
-p=no:xdist forms so equals-sign variants cannot bypass the gate, leaving the
deny/exit logic 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 (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 740bf58f-3d77-4616-b753-dc0280ad2230

📥 Commits

Reviewing files that changed from the base of the PR and between 0b818d5 and dce259a.

📒 Files selected for processing (40)
  • .claude/hookify.block-double-push.md
  • .claude/hookify.block-pr-create.md
  • .claude/hookify.enforce-parallel-tests.md
  • .claude/hookify.function-length.md
  • .claude/hookify.missing-logger.md
  • .claude/hookify.no-cd-prefix.md
  • .claude/hookify.no-future-annotations.md
  • .claude/hookify.no-local-coverage.md
  • .claude/hookify.pep758-except.md
  • .claude/settings.json
  • .gitattributes
  • .opencode/plugins/synthorg-hooks.ts
  • .pre-commit-config.yaml
  • CLAUDE.md
  • data/runtime_stats.yaml
  • docs/architecture/decisions.md
  • docs/getting_started.md
  • docs/reference/convention-gates.md
  • opencode.json
  • scripts/check_enforce_parallel_tests.sh
  • scripts/check_image_signatures.py
  • scripts/check_no_bulk_edit.py
  • scripts/check_no_cd_prefix.sh
  • scripts/check_no_local_coverage.sh
  • scripts/check_no_pr_create.sh
  • scripts/check_no_stdlib_logging.py
  • scripts/git-hooks/_run-hook.sh
  • scripts/git-hooks/commit-msg
  • scripts/git-hooks/pre-commit
  • scripts/git-hooks/pre-push
  • scripts/install_git_hooks.sh
  • scripts/run_affected_tests.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_check_no_stdlib_logging.py
  • tests/unit/scripts/test_git_hooks_wrapper.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • tests/unit/scripts/test_run_affected_tests.py
  • web/.gitignore
  • web/package.json
  • web/public/mockServiceWorker.js
💤 Files with no reviewable changes (11)
  • .claude/hookify.function-length.md
  • .claude/hookify.no-future-annotations.md
  • .claude/hookify.missing-logger.md
  • opencode.json
  • .claude/hookify.block-pr-create.md
  • .claude/hookify.no-cd-prefix.md
  • .claude/hookify.no-local-coverage.md
  • .claude/hookify.enforce-parallel-tests.md
  • .claude/hookify.pep758-except.md
  • .claude/hookify.block-double-push.md
  • web/public/mockServiceWorker.js
📜 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). (9)
  • GitHub Check: Lighthouse Site
  • GitHub Check: Lighthouse Dashboard
  • GitHub Check: Test E2E
  • GitHub Check: Test Unit
  • GitHub Check: Test Integration
  • GitHub Check: Dashboard Test
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: CodSpeed Web benchmarks
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (10)
!(src/synthorg/persistence/**)

📄 CodeRabbit inference engine (CLAUDE.md)

Only src/synthorg/persistence/ may import sqlite/psycopg or emit raw SQL

Files:

  • web/.gitignore
  • scripts/git-hooks/pre-push
  • scripts/git-hooks/pre-commit
  • .gitattributes
  • scripts/install_git_hooks.sh
  • scripts/check_no_pr_create.sh
  • web/package.json
  • scripts/check_no_cd_prefix.sh
  • scripts/git-hooks/commit-msg
  • docs/getting_started.md
  • scripts/git-hooks/_run-hook.sh
  • data/runtime_stats.yaml
  • scripts/check_no_local_coverage.sh
  • .claude/settings.json
  • docs/architecture/decisions.md
  • scripts/check_image_signatures.py
  • scripts/check_enforce_parallel_tests.sh
  • scripts/check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_stdlib_logging.py
  • .opencode/plugins/synthorg-hooks.ts
  • CLAUDE.md
  • .pre-commit-config.yaml
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_git_hooks_wrapper.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • scripts/run_affected_tests.py
  • docs/reference/convention-gates.md
  • scripts/check_no_bulk_edit.py
  • tests/unit/scripts/test_run_affected_tests.py
scripts/**/*.sh

📄 CodeRabbit inference engine (CLAUDE.md)

GitHub queries: use gh issue list via Bash, NOT MCP list_issues

Files:

  • scripts/install_git_hooks.sh
  • scripts/check_no_pr_create.sh
  • scripts/check_no_cd_prefix.sh
  • scripts/git-hooks/_run-hook.sh
  • scripts/check_no_local_coverage.sh
  • scripts/check_enforce_parallel_tests.sh
{README.md,docs/**/*.md,data/runtime_stats.yaml}

📄 CodeRabbit inference engine (CLAUDE.md)

Source numerics in README + public docs from data/runtime_stats.yaml via <!--RS:NAME--> markers

Files:

  • docs/getting_started.md
  • data/runtime_stats.yaml
  • docs/architecture/decisions.md
  • docs/reference/convention-gates.md
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Use d2 for architecture/nested containers, mermaid for flowcharts/sequence/pipelines; Markdown tables for tabular data

Files:

  • docs/getting_started.md
  • docs/architecture/decisions.md
  • docs/reference/convention-gates.md
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Configuration Precedence: DB > env > code default via SettingsService/ConfigResolver (Cat-1) or env > code default (Cat-2, read_only_post_init); Cat-3 bootstrap secrets are pure env; no os.environ.get outside startup

No from __future__ import annotations (3.14 has PEP 649); PEP 758 except: except A, B: no parens unless binding

Files:

  • scripts/check_image_signatures.py
  • scripts/check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_git_hooks_wrapper.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • scripts/run_affected_tests.py
  • scripts/check_no_bulk_edit.py
  • tests/unit/scripts/test_run_affected_tests.py
**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Comments WHY only; no reviewer citations / issue back-refs / migration framing; enforced by check_no_review_origin_in_code.py + check_no_migration_framing.py

Files:

  • scripts/check_image_signatures.py
  • scripts/check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_git_hooks_wrapper.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • scripts/run_affected_tests.py
  • scripts/check_no_bulk_edit.py
  • tests/unit/scripts/test_run_affected_tests.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Test markers: @pytest.mark.{unit,integration,e2e,slow}; async auto; timeout 30s global; coverage 80% min

Windows: unit tests use WindowsSelectorEventLoopPolicy (3.14 IOCP teardown race); subprocess tests override back

Test doubles: use FakeClock for Clock seam, mock_of[T](**overrides) for typed-boundary substitutions, SimpleNamespace for attribute-bags; bare MagicMock at typed boundaries forbidden; enforced by scripts/check_mock_spec.py

Hypothesis: 10 deterministic CI examples; failures are real bugs (fix + add @example(...))

Flaky tests: NEVER skip/xfail; fix fundamentally; use asyncio.Event().wait() not sleep(large)

Files:

  • tests/unit/scripts/test_check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_git_hooks_wrapper.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • tests/unit/scripts/test_run_affected_tests.py

⚙️ CodeRabbit configuration file

Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare @settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which @given() honors automatically.

Files:

  • tests/unit/scripts/test_check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_git_hooks_wrapper.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • tests/unit/scripts/test_run_affected_tests.py
{src/**/*.py,tests/**/*.py}

📄 CodeRabbit inference engine (CLAUDE.md)

Vendor-agnostic: NEVER use real vendor names in project code/tests; use example-provider, test-provider, example-{large,medium,small}-001

Files:

  • tests/unit/scripts/test_check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_git_hooks_wrapper.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • tests/unit/scripts/test_run_affected_tests.py
{,.opencode/plugins/}synthorg-hooks.ts

📄 CodeRabbit inference engine (AGENTS.md)

synthorg-hooks.ts plugin uses PreToolUse/PostToolUse hooks that call the same validation scripts as Claude Code hooks

Files:

  • .opencode/plugins/synthorg-hooks.ts
.pre-commit-config.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Pre-commit/pre-push hooks: .pre-commit-config.yaml; tool-call gates: .claude/settings.json PreToolUse

Files:

  • .pre-commit-config.yaml
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Read `docs/design/` page before implementing; deviations need approval per DESIGN_SPEC.md
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Present every plan for accept/deny before coding
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Use no region/currency/locale privileges; use metric units; use British English
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Every convention PR ships its enforcement gate
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: After issue: branch + commit + push (no auto-PR); use `/pre-pr-review`; after PR: use `/aurelio-review-pr` for external feedback; fix EVERYTHING valid
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Commits: `<type>: <description>` (feat/fix/refactor/docs/test/chore/perf/ci); commitizen-enforced
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Signed commits required on protected refs (GPG/SSH or GitHub App via `synthorg-repo-bot`)
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Branches: `<type>/<slug>` from main
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Squash merge; PR body becomes squash commit; trailers (`Release-As`, `Closes `#N``) must be in PR body
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: After every squash merge → `/post-merge-cleanup`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: CLI is Docker-only (init/start/stop/status); features go in dashboard + REST API
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Web configuration: see `web/CLAUDE.md`; CLI: see `cli/CLAUDE.md` (use `go -C cli`, never `cd cli`); Shell: see `~/.claude/rules/common/bash.md`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:26:08.777Z
Learning: Framework: Python 3.14+ for synthorg (src layout), BUSL-1.1 → Apache 2.0 after Change Date; React 19 for web; Go binary for CLI
📚 Learning: 2026-05-16T18:36:31.446Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/reference/conventions.md:787-789
Timestamp: 2026-05-16T18:36:31.446Z
Learning: In Aureliolo/synthorg, do not require adding `<!--RS:...-->` “Doc Numeric Claims (MANDATORY)” numeric macros for Python version numbers mentioned in documentation prose (e.g., “Python 3.14”, “Python 3.15”). The `scripts/check_doc_numeric_macros.py` gate only applies to `README.md`, `docs/index.md`, `docs/roadmap/index.md`, `docs/architecture/decisions.md`, and `docs/reference/convention-gates.md`, and it only flags digits adjacent to specific stat nouns (tests/providers/agents/stars/releases), not language version mentions like “Python 3.14”.

Applied to files:

  • docs/getting_started.md
  • docs/architecture/decisions.md
  • CLAUDE.md
  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:35.250Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/getting_started.md:109-109
Timestamp: 2026-05-16T18:36:35.250Z
Learning: When reviewing Markdown in the synthorg repo, account for the CI gate `check_doc_numeric_macros.py`: it skips fenced code blocks entirely, and it only flags digits that are adjacent to these stat nouns: `tests`, `providers`, `agents`, `stars`, `releases`. Therefore, numeric examples such as CLI flag values (e.g., `--num-workers=4` in fenced bash blocks) and prose version numbers (e.g., `3.14`/`3.15`) are not expected to trigger this check; prioritize changes only when digits appear next to one of the listed nouns (e.g., “5 tests”, “10 stars”, etc.).

Applied to files:

  • docs/getting_started.md
  • docs/architecture/decisions.md
  • CLAUDE.md
  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:35.250Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/getting_started.md:109-109
Timestamp: 2026-05-16T18:36:35.250Z
Learning: When reviewing markdown files for the "Doc Numeric Claims (MANDATORY)" RS-marker rule, only require/flag missing RS markers in the files that are actually in-scope for the rule. The scope is enforced via an identical _SCOPED_FILES allowlist in scripts/check_doc_numeric_macros.py and scripts/inject_runtime_stats.py, and currently includes: README.md; docs/index.md; docs/roadmap/index.md; docs/architecture/decisions.md; docs/reference/convention-gates.md. For any other markdown files (e.g., docs/getting_started.md, docs/guides/*), missing RS markers for numeric claims are no-ops and should NOT be flagged.

Applied to files:

  • docs/getting_started.md
  • docs/architecture/decisions.md
  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:35.250Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/getting_started.md:109-109
Timestamp: 2026-05-16T18:36:35.250Z
Learning: When reviewing Markdown in the synthorg repo against the `check_doc_numeric_macros.py` gate, account for its documented behavior: it skips fenced code blocks entirely, and it only flags digits that are adjacent to specific stat nouns (`tests`, `providers`, `agents`, `stars`, `releases`). As a result, CLI-style numbers (e.g., `--num-workers=4`) inside fenced bash code blocks should never be treated as violations of this gate; only non-fenced text needs checking, and only around those specific nouns.

Applied to files:

  • docs/getting_started.md
  • docs/architecture/decisions.md
  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:19.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/guides/contributing.md:95-95
Timestamp: 2026-05-16T18:36:19.195Z
Learning: In the SynthOrg repo, the “Doc Numeric Claims (MANDATORY)” RS-marker rule should be applied only to these docs: README.md; docs/index.md; docs/roadmap/index.md; docs/architecture/decisions.md; docs/reference/convention-gates.md. This rule is enforced by scripts/check_doc_numeric_macros.py (with runtime substitution by scripts/inject_runtime_stats.py), so reviewers should not flag similar numeric-claim issues in other paths (e.g., anything under docs/guides/). When checking those scoped files, the rule skips fenced code blocks and only flags digits that are adjacent to stat nouns (tests/providers/agents/stars/releases). Numeric CLI flags like “--num-workers=4” inside fenced bash code blocks are not subject to this rule.

Applied to files:

  • docs/architecture/decisions.md
  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:31.446Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/reference/conventions.md:787-789
Timestamp: 2026-05-16T18:36:31.446Z
Learning: In Aureliolo/synthorg, follow the `Doc Numeric Claims (MANDATORY)` rule enforced by `scripts/check_doc_numeric_macros.py` only for these markdown files: `README.md`, `docs/index.md`, `docs/roadmap/index.md`, `docs/architecture/decisions.md`, and `docs/reference/convention-gates.md`. The gate flags digits that appear adjacent to the stat nouns `tests`, `providers`, `agents`, `stars`, and `releases`—those numeric claims must use the required `<!--RS:...-->` macro format. Do not apply this rule to prose that mentions Python version numbers (e.g., “Python 3.14” / “Python 3.15”); those should not be flagged as requiring `<!--RS:...-->`.

Applied to files:

  • docs/architecture/decisions.md
  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:35.250Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/getting_started.md:109-109
Timestamp: 2026-05-16T18:36:35.250Z
Learning: In the synthorg repo, the “Doc Numeric Claims (MANDATORY)” RS-marker rule is enforced only for this exact set of Markdown files: README.md, docs/index.md, docs/roadmap/index.md, docs/architecture/decisions.md, and docs/reference/convention-gates.md. During code reviews, do not raise RS-marker/numeric-claims findings for numeric values in any other files (e.g., docs/getting_started.md, docs/guides/*, docs/reference/conventions.md), since they are not checked or injected by scripts/check_doc_numeric_macros.py or scripts/inject_runtime_stats.py.

Applied to files:

  • docs/architecture/decisions.md
  • docs/reference/convention-gates.md
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.

Applied to files:

  • scripts/check_image_signatures.py
  • scripts/check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_stdlib_logging.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_git_hooks_wrapper.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • scripts/run_affected_tests.py
  • scripts/check_no_bulk_edit.py
  • tests/unit/scripts/test_run_affected_tests.py
🪛 markdownlint-cli2 (0.22.1)
docs/reference/convention-gates.md

[warning] 71-71: Spaces inside code span elements

(MD038, no-space-in-code)

🔇 Additional comments (22)
docs/architecture/decisions.md (1)

139-168: LGTM!

CLAUDE.md (1)

19-19: LGTM!

Also applies to: 37-37, 107-107

.gitattributes (1)

28-34: LGTM!

scripts/git-hooks/_run-hook.sh (1)

1-45: LGTM!

scripts/git-hooks/commit-msg (1)

1-7: LGTM!

scripts/git-hooks/pre-commit (1)

1-7: LGTM!

scripts/git-hooks/pre-push (1)

1-7: LGTM!

scripts/install_git_hooks.sh (1)

1-33: LGTM!

scripts/check_no_bulk_edit.py (1)

1-90: LGTM!

scripts/run_affected_tests.py (1)

72-79: LGTM!

Also applies to: 104-122, 833-970

tests/unit/scripts/test_check_no_bulk_edit.py (1)

1-134: LGTM!

tests/unit/scripts/test_check_no_stdlib_logging.py (1)

1-86: LGTM!

tests/unit/scripts/test_git_hooks_wrapper.py (1)

1-143: LGTM!

tests/unit/scripts/test_pretooluse_bash_gates.py (1)

1-211: LGTM!

tests/unit/scripts/test_run_affected_tests.py (1)

16-16: LGTM!

Also applies to: 42-46, 873-1029

scripts/check_no_pr_create.sh (1)

1-40: LGTM!

scripts/check_no_cd_prefix.sh (1)

1-43: LGTM!

scripts/check_no_local_coverage.sh (1)

1-47: LGTM!

scripts/check_no_stdlib_logging.py (1)

1-129: LGTM!

.claude/settings.json (1)

49-65: LGTM!

.pre-commit-config.yaml (1)

212-224: LGTM!

.opencode/plugins/synthorg-hooks.ts (1)

342-352: LGTM!

Comment thread .opencode/plugins/synthorg-hooks.ts Outdated
Comment thread docs/reference/convention-gates.md Outdated
Comment thread scripts/check_enforce_parallel_tests.sh Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.22%. Comparing base (0b818d5) to head (e8cca44).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1949   +/-   ##
=======================================
  Coverage   85.22%   85.22%           
=======================================
  Files        1846     1846           
  Lines      107867   107867           
  Branches     9298     9298           
=======================================
+ Hits        91931    91933    +2     
+ Misses      13677    13675    -2     
  Partials     2259     2259           

☔ 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.

…t equals-assignment pytest flag forms in check_enforce_parallel_tests.sh, fail closed on non-object JSON in check_no_bulk_edit.py, restrict rename payload split to R/C porcelain status in run_affected_tests.py, WHY-only comment in synthorg-hooks.ts, clear markdownlint MD038 in convention-gates.md, dismiss CodeQL alert 296 as false positive, add test coverage
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 16, 2026 22:50 — with GitHub Actions Inactive
Copy link
Copy Markdown
Contributor

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/check_no_bulk_edit.py (1)

81-87: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Harden tool_input/command typing to keep fail-closed behaviour explicit.

payload is validated as a dict, but tool_input and tool_input["command"] are not. A non-dict tool_input (or non-string command) can raise AttributeError/TypeError, producing a crash path instead of your explicit malformed-envelope denial flow.

Suggested patch
-    tool_name = payload.get("tool_name", "")
-    tool_input = payload.get("tool_input") or {}
+    tool_name = payload.get("tool_name", "")
+    tool_input_raw = payload.get("tool_input")
+    if tool_input_raw is None:
+        tool_input: dict[str, object] = {}
+    elif not isinstance(tool_input_raw, dict):
+        print(
+            "BLOCKED: malformed PreToolUse JSON envelope (tool_input must be object); "
+            "check_no_bulk_edit fails closed.",
+            file=sys.stderr,
+        )
+        return 2
+    else:
+        tool_input = tool_input_raw
 
     if tool_name == "Bash":
-        command = tool_input.get("command", "") or ""
+        command_raw = tool_input.get("command", "")
+        if command_raw is None:
+            command = ""
+        elif not isinstance(command_raw, str):
+            print(
+                "BLOCKED: malformed PreToolUse JSON envelope (tool_input.command must be string); "
+                "check_no_bulk_edit fails closed.",
+                file=sys.stderr,
+            )
+            return 2
+        else:
+            command = command_raw
         for pattern in _BULK_BASH_PATTERNS:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check_no_bulk_edit.py` around lines 81 - 87, The code currently
assumes payload["tool_input"] is a dict and tool_input["command"] is a string,
which can raise exceptions; inside the tool_name == "Bash" branch (where
tool_input, command and _BULK_BASH_PATTERNS are used) explicitly validate types:
ensure tool_input is a dict (fallback to {} if not) and coerce or validate
command to a str (fallback to "" or treat as malformed and run the denial path)
before iterating over _BULK_BASH_PATTERNS, so any non-dict/non-string input
yields the same explicit fail-closed behavior rather than raising
AttributeError/TypeError.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@scripts/check_no_bulk_edit.py`:
- Around line 81-87: The code currently assumes payload["tool_input"] is a dict
and tool_input["command"] is a string, which can raise exceptions; inside the
tool_name == "Bash" branch (where tool_input, command and _BULK_BASH_PATTERNS
are used) explicitly validate types: ensure tool_input is a dict (fallback to {}
if not) and coerce or validate command to a str (fallback to "" or treat as
malformed and run the denial path) before iterating over _BULK_BASH_PATTERNS, so
any non-dict/non-string input yields the same explicit fail-closed behavior
rather than raising AttributeError/TypeError.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: ac39ec62-d73e-4a92-a1ae-d156f2c8bb70

📥 Commits

Reviewing files that changed from the base of the PR and between dce259a and 593265d.

📒 Files selected for processing (7)
  • .opencode/plugins/synthorg-hooks.ts
  • docs/reference/convention-gates.md
  • scripts/check_enforce_parallel_tests.sh
  • scripts/check_no_bulk_edit.py
  • scripts/run_affected_tests.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_pretooluse_bash_gates.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). (8)
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: Test Unit
  • GitHub Check: Test E2E
  • GitHub Check: Test Integration
  • GitHub Check: Dashboard Test
  • GitHub Check: Lighthouse Site
  • GitHub Check: Lighthouse Dashboard
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Use d2 for architecture / nested containers diagrams; use mermaid for flowcharts / sequence / pipelines

Use Markdown tables for tabular data

Files:

  • docs/reference/convention-gates.md
{,.opencode/plugins/}synthorg-hooks.ts

📄 CodeRabbit inference engine (AGENTS.md)

synthorg-hooks.ts plugin uses PreToolUse/PostToolUse hooks that call the same validation scripts as Claude Code hooks

Files:

  • .opencode/plugins/synthorg-hooks.ts
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use markers: @pytest.mark.{unit,integration,e2e,slow} for tests

Async tests use auto mode; timeout 30s global; coverage 80% minimum

Windows: unit tests use WindowsSelectorEventLoopPolicy (3.14 IOCP teardown race); subprocess tests override back

Test doubles: FakeClock for Clock seam, mock_of[T](**overrides) for typed-boundary substitutions, SimpleNamespace for attribute-bags

Bare MagicMock at a typed boundary (constructor / fn arg / annotated local / typed fixture return) is blocked by scripts/check_mock_spec.py (zero-tolerance, no baseline)

FakeClock and mock_of import from tests._shared; inject via clock= and the helper's spec subscript

Hypothesis: 10 deterministic CI examples; failures are real bugs (fix + add @example(...))

Flaky tests: NEVER skip/xfail; fix fundamentally. Use asyncio.Event().wait() not sleep(large)

Files:

  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py

⚙️ CodeRabbit configuration file

Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare @settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which @given() honors automatically.

Files:

  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
{src/synthorg/**/*.py,tests/**/*.py}

📄 CodeRabbit inference engine (CLAUDE.md)

NEVER use real vendor names in project code/tests; use example-provider, test-provider, example-{large,medium,small}-001

Files:

  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Read `docs/design/` page before implementing; deviations need approval. See DESIGN_SPEC.md
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Present every plan for accept/deny before coding
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Use no region/locale privilege; metric units; British English
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Every convention PR ships its enforcement gate
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: YAML is a company-template ingestion format, not a precedence tier
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Enforced by `scripts/check_no_magic_numbers.py`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Timeout/slow failures = source-code regression; test baseline files are PreToolUse-blocked
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Per-invocation bypass for gate baselines: `ALLOW_BASELINE_GROWTH=1 git commit ...` (requires explicit user approval)
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: After issue: branch + commit + push (no auto-PR); use `/pre-pr-review` (`gh pr create` is blocked by `scripts/check_no_pr_create.sh`)
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: After PR: use `/aurelio-review-pr` for external feedback
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Fix EVERYTHING valid; no deferring
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Use `uv sync` for all dependencies; `uv sync --group docs` for docs toolchain
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Enforced by `check_no_review_origin_in_code.py` + `check_no_migration_framing.py`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Enforced by `check_domain_error_hierarchy.py`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Enforced by `check_boundary_typed.py`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Enforced by `check_logger_exception_str_exc.py`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Use xdist `-n 8 --dist=loadfile` (auto-applied via pyproject `addopts`; loadfile prevents 3.14+Windows ProactorEventLoop leak)
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Real vendor names allowed in `.claude/`, third-party imports, `providers/presets.py`, `web/public/provider-logos/`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Enforced by `check_dual_backend_test_parity.py`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Git commit format: `<type>: <description>` (feat/fix/refactor/docs/test/chore/perf/ci); commitizen-enforced
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Signed commits required on protected refs (GPG/SSH or GitHub App via `synthorg-repo-bot`)
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Branch naming: `<type>/<slug>` from main
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Use pre-commit/pre-push hooks from `.pre-commit-config.yaml`; tool-call gates in `.claude/settings.json` PreToolUse
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: Squash merge PR body becomes squash commit; trailers (`Release-As`, `Closes `#N``) must be in PR body
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: GitHub queries: use `gh issue list` via Bash, NOT MCP `list_issues`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: After every squash merge, use `/post-merge-cleanup`
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: CLI is Docker-only (init/start/stop/status); features go in dashboard + REST API
Learnt from: CR
Repo: Aureliolo/synthorg

Timestamp: 2026-05-16T22:50:14.600Z
Learning: D2 theme 200 (Dark Mauve), D2 CLI pinned to v0.7.1 in CI
📚 Learning: 2026-05-16T18:36:19.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/guides/contributing.md:95-95
Timestamp: 2026-05-16T18:36:19.195Z
Learning: In the SynthOrg repo, the “Doc Numeric Claims (MANDATORY)” RS-marker rule should be applied only to these docs: README.md; docs/index.md; docs/roadmap/index.md; docs/architecture/decisions.md; docs/reference/convention-gates.md. This rule is enforced by scripts/check_doc_numeric_macros.py (with runtime substitution by scripts/inject_runtime_stats.py), so reviewers should not flag similar numeric-claim issues in other paths (e.g., anything under docs/guides/). When checking those scoped files, the rule skips fenced code blocks and only flags digits that are adjacent to stat nouns (tests/providers/agents/stars/releases). Numeric CLI flags like “--num-workers=4” inside fenced bash code blocks are not subject to this rule.

Applied to files:

  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:31.446Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/reference/conventions.md:787-789
Timestamp: 2026-05-16T18:36:31.446Z
Learning: In Aureliolo/synthorg, follow the `Doc Numeric Claims (MANDATORY)` rule enforced by `scripts/check_doc_numeric_macros.py` only for these markdown files: `README.md`, `docs/index.md`, `docs/roadmap/index.md`, `docs/architecture/decisions.md`, and `docs/reference/convention-gates.md`. The gate flags digits that appear adjacent to the stat nouns `tests`, `providers`, `agents`, `stars`, and `releases`—those numeric claims must use the required `<!--RS:...-->` macro format. Do not apply this rule to prose that mentions Python version numbers (e.g., “Python 3.14” / “Python 3.15”); those should not be flagged as requiring `<!--RS:...-->`.

Applied to files:

  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:35.250Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/getting_started.md:109-109
Timestamp: 2026-05-16T18:36:35.250Z
Learning: In the synthorg repo, the “Doc Numeric Claims (MANDATORY)” RS-marker rule is enforced only for this exact set of Markdown files: README.md, docs/index.md, docs/roadmap/index.md, docs/architecture/decisions.md, and docs/reference/convention-gates.md. During code reviews, do not raise RS-marker/numeric-claims findings for numeric values in any other files (e.g., docs/getting_started.md, docs/guides/*, docs/reference/conventions.md), since they are not checked or injected by scripts/check_doc_numeric_macros.py or scripts/inject_runtime_stats.py.

Applied to files:

  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:31.446Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/reference/conventions.md:787-789
Timestamp: 2026-05-16T18:36:31.446Z
Learning: In Aureliolo/synthorg, do not require adding `<!--RS:...-->` “Doc Numeric Claims (MANDATORY)” numeric macros for Python version numbers mentioned in documentation prose (e.g., “Python 3.14”, “Python 3.15”). The `scripts/check_doc_numeric_macros.py` gate only applies to `README.md`, `docs/index.md`, `docs/roadmap/index.md`, `docs/architecture/decisions.md`, and `docs/reference/convention-gates.md`, and it only flags digits adjacent to specific stat nouns (tests/providers/agents/stars/releases), not language version mentions like “Python 3.14”.

Applied to files:

  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:35.250Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/getting_started.md:109-109
Timestamp: 2026-05-16T18:36:35.250Z
Learning: When reviewing Markdown in the synthorg repo, account for the CI gate `check_doc_numeric_macros.py`: it skips fenced code blocks entirely, and it only flags digits that are adjacent to these stat nouns: `tests`, `providers`, `agents`, `stars`, `releases`. Therefore, numeric examples such as CLI flag values (e.g., `--num-workers=4` in fenced bash blocks) and prose version numbers (e.g., `3.14`/`3.15`) are not expected to trigger this check; prioritize changes only when digits appear next to one of the listed nouns (e.g., “5 tests”, “10 stars”, etc.).

Applied to files:

  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:35.250Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/getting_started.md:109-109
Timestamp: 2026-05-16T18:36:35.250Z
Learning: When reviewing markdown files for the "Doc Numeric Claims (MANDATORY)" RS-marker rule, only require/flag missing RS markers in the files that are actually in-scope for the rule. The scope is enforced via an identical _SCOPED_FILES allowlist in scripts/check_doc_numeric_macros.py and scripts/inject_runtime_stats.py, and currently includes: README.md; docs/index.md; docs/roadmap/index.md; docs/architecture/decisions.md; docs/reference/convention-gates.md. For any other markdown files (e.g., docs/getting_started.md, docs/guides/*), missing RS markers for numeric claims are no-ops and should NOT be flagged.

Applied to files:

  • docs/reference/convention-gates.md
📚 Learning: 2026-05-16T18:36:35.250Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1944
File: docs/getting_started.md:109-109
Timestamp: 2026-05-16T18:36:35.250Z
Learning: When reviewing Markdown in the synthorg repo against the `check_doc_numeric_macros.py` gate, account for its documented behavior: it skips fenced code blocks entirely, and it only flags digits that are adjacent to specific stat nouns (`tests`, `providers`, `agents`, `stars`, `releases`). As a result, CLI-style numbers (e.g., `--num-workers=4`) inside fenced bash code blocks should never be treated as violations of this gate; only non-fenced text needs checking, and only around those specific nouns.

Applied to files:

  • docs/reference/convention-gates.md
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.

Applied to files:

  • scripts/run_affected_tests.py
  • tests/unit/scripts/test_check_no_bulk_edit.py
  • tests/unit/scripts/test_pretooluse_bash_gates.py
  • scripts/check_no_bulk_edit.py

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 16, 2026
…t tool_input / non-string command in check_no_bulk_edit Bash path (extracted _scan_bash helper), add coverage
@Aureliolo Aureliolo merged commit e3f8495 into main May 16, 2026
78 checks passed
@Aureliolo Aureliolo deleted the fix/worktree-hooks-isolation branch May 16, 2026 23:05
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 16, 2026 23:05 — with GitHub Actions Inactive
Aureliolo pushed a commit that referenced this pull request May 17, 2026
<!-- HIGHLIGHTS_START -->
## Highlights

> _AI-generated summary (model: `openai/gpt-4.1-mini` via GitHub
Models). Commit-based changelog below._

### What you'll notice
- Frontend WP-6 update with UX polish improves user interface and
workflow.
- Dashboard and training endpoint improvements enhance observability and
dispatch behavior.
- Web storybook now supports change detection for more responsive UI
interactions.
- Git hooks now isolated per worktree for cleaner repository management.
- Providers automatically detect native streaming support in Litellm
models.

### What's new
- Added a new pipeline to convert Pydantic DTOs to TypeScript for better
front-end compatibility.

### Under the hood
- Refactored settings to three precedence categories, removing YAML tier
for simpler configuration.
- Completed RootConfig mirror coverage for enhanced configuration
consistency.
- Adopted API conventions with better query performance and forbidden
extra fields for stricter validation.
- Improved persistence, layer discipline, and restart safety in core
work packages.
- CI updated with split test jobs and tightened coverage gates for
better test quality.
- Switched to direct Trivy binary for security scans, removing previous
Trivy action dependency.
- Enhanced memory management with per-call processing options and better
observability during speech-to-text encoding.
- Various dependency updates for Python, infrastructure, and lock files
maintain security and stability.
- Removed TypeScript DTO type-tightening overlays to simplify type
management.
- Codebase audit tightened skill sets to prevent false positivity in
class detection by 2026.

<!-- HIGHLIGHTS_END -->

:robot: I have created a release *beep* *boop*
---


##
[0.8.5](v0.8.4...v0.8.5)
(2026-05-17)


### Features

* **codegen:** pydantic-to-typescript DTO pipeline + parity gate (closes
[#1889](#1889))
([#1909](#1909))
([0265ef5](0265ef5))
* **storybook:** enable changeDetection + trim web/CLAUDE.md
([#1939](#1939))
([3b1f4c0](3b1f4c0))
* **web,setup:** WP-6 frontend + UX polish
([#1941](#1941))
([d9ca76d](d9ca76d))


### Bug Fixes

* correct invalid git for-each-ref syntax in post-merge-cleanup skill
([#1946](#1946))
([69a1649](69a1649))
* dashboard polish, training endpoint dispatch, and observability
cleanup ([#1911](#1911))
([b61e9e8](b61e9e8))
* per-worktree git-hook isolation + hookify gate migration + MSW drift
fix ([#1949](#1949))
([e3f8495](e3f8495))
* **providers:** read supports_native_streaming from litellm model info
([#1942](#1942))
([60364ca](60364ca))
* security and audit coverage (closes
[#1883](#1883))
([#1904](#1904))
([d8ebf55](d8ebf55))


### Performance

* **ci:** mypy --num-workers=4 + enable ruff TID255
([#1944](#1944))
([484c1d3](484c1d3))


### Refactoring

* **ci:** drop aquasecurity/trivy-action, use direct trivy binary
([#1940](#1940))
([df1f946](df1f946))
* **memory:** per-call processing_kwargs + observability for ST encode
([#1943](#1943))
([3aa9d20](3aa9d20))
* Phase 7 follow-up — complete RootConfig mirror coverage (closes
[#1907](#1907))
([#1914](#1914))
([605500b](605500b))
* **settings:** collapse precedence to three categories; drop YAML tier
(closes [#1890](#1890))
([#1910](#1910))
([efd54c9](efd54c9))
* WP-3 API conventions + query performance + project-wide extra=forbid
([#1953](#1953))
([504d579](504d579)),
closes [#1918](#1918)
* WP-4 settings + cross-cutting (clock seam, contextvars, dispatch,
plugin surfaces)
([#1954](#1954))
([7207d92](7207d92))
* **wp1:** persistence + layer discipline + restart safety
([#1945](#1945))
([57586fb](57586fb))


### Documentation

* **wp5:** public-facing truth refresh
([#1924](#1924))
([afb5cc5](afb5cc5))


### CI/CD

* split test job by marker with airtight aggregate coverage gate
([#1948](#1948))
([0b818d5](0b818d5)),
closes [#1938](#1938)
[#1937](#1937)


### Maintenance

* **codebase-audit:** tighten skill to prevent 2026-05-15 FP classes
([#1923](#1923))
([9317ed1](9317ed1))
* Lock file maintenance
([#1913](#1913))
([c08a355](c08a355))
* Lock file maintenance
([#1950](#1950))
([8940ab1](8940ab1))
* remove TS DTO type-tightening overlays
([#1915](#1915))
([d296214](d296214)),
closes [#1906](#1906)
* Update Infrastructure dependencies
([#1928](#1928))
([d19fae5](d19fae5))
* Update Python dependencies
([#1929](#1929))
([75cc2c8](75cc2c8))
* **wp7:** hygiene, stubs, test/CI/tooling, doc gaps, boundary patterns
doc ([#1926](#1926))
([c29eb32](c29eb32))

---
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: synthorg-repo-bot[bot] <279117679+synthorg-repo-bot[bot]@users.noreply.github.com>
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.

Worktree isolation: shared core.hooksPath bakes one worktree's venv, breaks all others

1 participant