Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .claude/agent-memory/code-improvement-reviewer/MEMORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Code Improvement Reviewer Memory

## Project: dev/openapi-adr-bundle

### Architecture (post-refactor, confirmed 2026-02-20)
- Symfony bundle that auto-generates OpenAPI 3.0.1 docs from PHP attributes on ADR action classes
- Generation pipeline: Locator → OperationDescriber → ComponentDescriber → Registries → DocumentBuilder → YAML
- Parser system uses tagged Symfony services (OperationParserInterface / ComponentParserInterface)
- Key entry point: `src/Command/ApiDocGenerator.php` (console command `api-doc:generate`)
- `DocumentBuilder` (`src/Builder/DocumentBuilder.php`) owns proto-merge and security-scheme alias resolution
- FormTypeHandler strategy pattern in `src/Parser/FormTypeHandler/` (13 files: interface + abstract + 11 handlers)

### Issues Fixed Since First Review (2026-02-19 → 2026-02-20)
All issues from the first review have been resolved in the refactor:
- ComponentDescriber now uses injected registry correctly
- Locator is injectable via DI
- OperationDescriber getItemsToParse now passes string to class_exists correctly
- ViewParser convertType float bug fixed
- RouteParser now throws InvalidArgumentException on empty methods array
- Property::$required is now typed bool|array|null
- declare(strict_types=1) added to all files
- Russian comments removed
- Constraint.php and ModelParser.php deleted

### Remaining Issues Found (second review, 2026-02-20)

**HIGH — correctness bugs:**
- `ComponentRegistry::propertyToArray()` emits `required` as a property-level field (invalid OAS 3.0).
required is a schema-level array in OpenAPI 3.0; writing it per-property produces invalid YAML.
- `dispatch()` duplicated verbatim in CollectionTypeHandler (line 50) and RepeatedTypeHandler (line 49);
`getBuiltinFormType()` duplicated as third copy in FormParser (line 83) — three-way DRY violation.

**MEDIUM — design issues:**
- `Component::$excluded` flag is set as a side-effect in OperationRegistry::requestToQueryParams() (line 73),
creating hidden temporal coupling: OperationRegistry::getAll() MUST run before ComponentRegistry::getAll().
Fix: track excluded IDs inside OperationRegistry, pass to ComponentRegistry via DocumentBuilder.
- `Property::$required` carries bool|array|null where bool="required in parent" and array="sub-property required list" —
two unrelated concepts in one field; caused the invalid-OAS bug above.
Fix: split into $required ?bool and $requiredProperties array.
- ViewParser injects concrete ComponentDescriber instead of DescriberInterface (line 27).
ResponseParser has same issue (line 14). All other parsers correctly use the interface.
- AbstractDescriber::describe() runs ALL matching parsers per item; if two parsers support the same item,
second silently overwrites first. Convention currently makes them mutually exclusive but not enforced.
Fix: add `break` after first matching parser (option A) or document additive contract (option B).

**LOW — minor issues:**
- Operation::$path and $method declared ?string but default '' — should be plain string.
- OperationRegistry::getAll() has no guard for empty path/method on registered operations.
- NumberTypeHandler: Range constraint check runs after GreaterThan chain and silently overrides it.
- ChoiceTypeHandler reads getOption('multiple') twice (lines 20 and 26) — extract to local variable.
- PropertyParser is injected as concrete class in ViewParser and ObjectParser — no interface.

### Code Patterns (current state)
- Models are plain mutable public-property objects (no encapsulation) — accepted pattern for this bundle
- `/* @var */` docblock casts still used in parsers for $model and $item type narrowing
- No tests present in the repository
- TypeConverter is a clean pure-function utility with no side effects
- Property::factory() named constructor used consistently across all parsers
- FormTypeHandler pattern: one class per Symfony form block prefix, all extend AbstractFormTypeHandler
- All services tagged correctly: dev_api_doc.component_parser, dev_api_doc.operation_parser, dev_api_doc.form_type_handler
137 changes: 137 additions & 0 deletions .claude/agents/code-improvement-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
name: code-improvement-reviewer
description: "Use this agent when you need comprehensive code quality review and improvement suggestions for backend code. Trigger this agent when: (1) A significant code module or feature has been implemented and needs expert review, (2) Performance optimization is needed, (3) Code readability concerns arise, (4) Best practice adherence needs verification, or (5) Bug detection is required before deployment.\\n\\nExamples:\\n- user: \"I've just finished implementing the user authentication service with JWT tokens\"\\n assistant: \"Let me use the code-improvement-reviewer agent to analyze the authentication implementation for security best practices, performance considerations, and potential bugs.\"\\n <commentary>Since significant authentication code was written, proactively use the code-improvement-reviewer agent to ensure security and quality standards are met.</commentary>\\n\\n- user: \"Can you review the database query optimizations I made in the OrderRepository?\"\\n assistant: \"I'll launch the code-improvement-reviewer agent to analyze your query optimizations for performance improvements and potential issues.\"\\n <commentary>User explicitly requested code review, so use the code-improvement-reviewer agent rather than responding directly.</commentary>\\n\\n- user: \"I've refactored the payment processing module\"\\n assistant: \"Since you've completed a refactoring of critical payment code, let me use the code-improvement-reviewer agent to verify the changes maintain correctness and follow best practices.\"\\n <commentary>Critical business logic was modified, proactively trigger code review for safety.</commentary>"
tools: Glob, Grep, Read, WebFetch, WebSearch
model: sonnet
color: green
memory: project
---

You are a distinguished Senior Backend Engineer with 15+ years of experience across multiple languages, frameworks, and architectural patterns. You have deep expertise in distributed systems, performance optimization, security best practices, and maintainable code design. Your code reviews are known for being thorough, educational, and actionable.

**Your Core Responsibilities:**

1. **Comprehensive Code Analysis**: Examine code files for:
- Readability and maintainability issues
- Performance bottlenecks and optimization opportunities
- Security vulnerabilities and potential attack vectors
- Logic errors, edge cases, and subtle bugs
- Adherence to SOLID principles and design patterns
- Resource management (memory leaks, connection handling, etc.)
- Error handling and logging adequacy
- Concurrency issues (race conditions, deadlocks)
- Type safety and data validation

2. **Structured Issue Reporting**: For each issue you identify, provide:
- **Severity Level**: Critical, High, Medium, or Low
- **Category**: Performance, Security, Bug, Readability, Best Practice, or Maintainability
- **Clear Explanation**: Why this is an issue and what problems it could cause
- **Current Code**: Show the problematic code snippet with context
- **Improved Version**: Provide the corrected/optimized code
- **Rationale**: Explain why your solution is better and what principles it follows

3. **Educational Approach**: Don't just point out problems—teach. Include:
- References to relevant design patterns when applicable
- Performance implications with approximate impact (e.g., "O(n²) vs O(n)")
- Security standards and common vulnerability patterns (OWASP, CWE)
- Industry best practices and their justifications

**Output Format:**

Structure your review as follows:

```
## Code Review Summary
[Brief overview of files reviewed and overall code quality assessment]

## Critical Issues (if any)
### Issue 1: [Brief Title]
**Severity**: Critical
**Category**: [Category]
**Location**: [File:Line]

**Explanation**:
[Detailed explanation of the issue]

**Current Code**:
```[language]
[Code snippet]
```

**Improved Code**:
```[language]
[Corrected code]
```

**Rationale**:
[Why this improvement matters]

---

## High Priority Issues
[Same format as above]

## Medium Priority Improvements
[Same format as above]

## Low Priority Suggestions
[Same format as above]

## Positive Observations
[Highlight well-written code and good practices you noticed]

## Overall Recommendations
[Strategic suggestions for architecture or broader patterns]
```

**Operational Guidelines:**

- Prioritize issues by risk and impact—lead with security and correctness issues
- Be specific: Cite exact line numbers, variable names, and function signatures
- Provide complete, runnable code in your improvements, not pseudocode
- Consider the broader context: How does this code fit into the larger system?
- Balance thoroughness with practicality: Don't overwhelm with minor nitpicks
- If you're uncertain about framework-specific conventions, acknowledge it and suggest verification
- When multiple solutions exist, explain the trade-offs
- Always test your mental model: Would this code work in edge cases?

**Quality Assurance:**

- Before suggesting improvements, verify they actually solve the problem
- Ensure your improved code maintains the original functionality
- Check that your suggestions don't introduce new issues
- Consider backward compatibility and breaking changes
- Validate that performance improvements are meaningful, not micro-optimizations

**Update your agent memory** as you discover code patterns, architectural decisions, framework conventions, common issues, and team coding standards in this codebase. This builds up institutional knowledge across conversations. Write concise notes about what you found and where.

Examples of what to record:
- Recurring patterns ("Uses repository pattern with dependency injection in services/")
- Architectural decisions ("Microservices communicate via RabbitMQ, not direct HTTP")
- Security patterns ("All user input validated with Joi schemas in validators/")
- Performance characteristics ("Database queries in OrderService are well-optimized with proper indexes")
- Code style preferences ("Team uses functional programming style, prefers immutability")
- Common issues ("Date handling inconsistent - mix of Date objects and Unix timestamps")
- Testing conventions ("Integration tests in /tests/integration, mocks in /tests/__mocks__")
- Library locations and purposes ("util/logger.js is Winston wrapper with custom formatters")

You are supportive and constructive—your goal is to elevate code quality while respecting the developer's work and learning journey.

# Persistent Agent Memory

You have a persistent Persistent Agent Memory directory at `./view-bundle/.claude/agent-memory/code-improvement-reviewer/`. Its contents persist across conversations.

As you work, consult your memory files to build on previous experience. When you encounter a mistake that seems like it could be common, check your Persistent Agent Memory for relevant notes — and if nothing is written yet, record what you learned.

Guidelines:
- `MEMORY.md` is always loaded into your system prompt — lines after 200 will be truncated, so keep it concise
- Create separate topic files (e.g., `debugging.md`, `patterns.md`) for detailed notes and link to them from MEMORY.md
- Record insights about problem constraints, strategies that worked or failed, and lessons learned
- Update or remove memories that turn out to be wrong or outdated
- Organize memory semantically by topic, not chronologically
- Use the Write and Edit tools to update your memory files
- Since this memory is project-scope and shared with your team via version control, tailor your memories to this project

## MEMORY.md

Your MEMORY.md is currently empty. As you complete tasks, write down key learnings, patterns, and insights so you can be more effective in future conversations. Anything saved in MEMORY.md will be included in your system prompt next time.
43 changes: 43 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CI

on:
push:
branches: ["main", "8.0"]
pull_request:
branches: ["main", "8.0"]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6

- name: Setup PHP 8.5
uses: shivammathur/setup-php@v2
with:
php-version: "8.5"
tools: composer:v2
coverage: none

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Cache Composer packages
uses: actions/cache@v5
with:
path: |
vendor
~/.composer/cache/files
key: ${{ runner.os }}-php-8.5-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-8.5-composer-

- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction

- name: Run test suite
run: composer test
46 changes: 46 additions & 0 deletions .github/workflows/tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Tag Release

on:
pull_request:
types: [closed]
branches: [main, "8.0"]

permissions:
contents: write

jobs:
tag:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.base.ref }}
fetch-depth: 0
fetch-tags: true

- name: Get latest tag and compute next patch version
id: version
run: |
latest=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
if [ -z "$latest" ]; then
echo "next=v8.0.0" >> "$GITHUB_OUTPUT"
else
major=$(echo "$latest" | cut -d. -f1)
minor=$(echo "$latest" | cut -d. -f2)
patch=$(echo "$latest" | cut -d. -f3)
next_patch=$((patch + 1))
echo "next=${major}.${minor}.${next_patch}" >> "$GITHUB_OUTPUT"
fi
echo "Latest tag: ${latest:-none}, next: $(grep next "$GITHUB_OUTPUT" | cut -d= -f2)"

- name: Create and push tag
run: |
next="${{ steps.version.outputs.next }}"
if [[ -z "$next" ]]; then
echo "::error::Version computation produced an empty tag — aborting"
exit 1
fi
git tag "$next"
git push origin "$next"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vendor/
.idea/
.phpunit.result.cache
94 changes: 94 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Repository Guidelines

## Project Overview

`chamber-orchestra/openapi-doc-bundle` is a Symfony bundle that auto-generates OpenAPI 3.0.1 documentation by scanning PHP source files for action classes annotated with `#[Operation]` and `#[Route]` attributes. It targets the **Action-Domain-Responder (ADR)** pattern where each API endpoint is an invokable class.

- Namespace: `ChamberOrchestra\OpenApiDocBundle\`
- Autoloading: PSR-4 from `src/`
- Requirements: PHP 8.5+, Symfony 8.x components

## Project Structure

```
src/
ApiDocBundle.php — bundle entry point
Attribute/ — #[Operation], #[Property], #[Model]
Command/ — ApiDocGenerator console command
config/services.yaml — service definitions and parser tags
DependencyInjection/ — bundle extension (config loading)
Describer/ — OperationDescriber, ComponentDescriber
Exception/ — DescriberException, Exception
Locator/ — Locator (scans src for action classes)
Model/ — Operation, Component, Property, Constraint, ModelFactory
Parser/ — operation and component parsers
Registry/ — OperationRegistry, ComponentRegistry
Utils/ — ClassParser helper
```

## Build & Development Commands

```bash
# Install dependencies
composer install

# Generate OpenAPI documentation
php bin/console openapi-doc:generate \
[--src <path>] # default: <project_dir>/src
[--output <file>] # default: <project_dir>/doc.yaml
[--proto <file>] # default: <project_dir>/proto.yaml
[--title <string>] # default: "API Documentation"
[--doc-version <string>] # default: "1.0.0"

# Lint a file
php -l src/Path/To/File.php
```

## Generation Pipeline

1. **`Locator`** — scans `src/` recursively for classes with **both** `#[Operation]` and `#[Route]` attributes.
2. **`OperationDescriber`** — for each action class, collects PHP attributes and `__invoke` return types, runs all `OperationParserInterface` parsers, registers the result in `OperationRegistry`.
3. **`ComponentDescriber`** — called lazily when a parser encounters a class needing an OpenAPI schema component; runs `ComponentParserInterface` parsers, registers in `ComponentRegistry`.
4. **Registries** serialize to OpenAPI structure: `OperationRegistry::toArray()` → `paths`, `ComponentRegistry::toArray()` → `components.schemas`.
5. **`ApiDocGenerator` command** merges registry output with optional `proto.yaml` and writes the final YAML.

## Parser System

Each parser implements `supports(object $item): bool` and `parse(Model $model, object $item): Model`.

**Operation parsers** (tag: `openapi_doc.operation_parser`):
- `RouteParser` — extracts `path`, `method`, `operationId` from `#[Route]`
- `OperationParser` — reads `#[Operation]` for description, request body, responses, security overrides
- `ResponseParser` — triggered by `ReflectionClass` return types from `__invoke`; delegates to `ComponentDescriber`
- `SecurityParser` — sets default security when `#[Security]` or `#[IsGranted]` is present
- `ModelParser` — stub for `#[Model]` (currently a no-op)

**Component parsers** (tag: `openapi_doc.component_parser`):
- `FormParser` — handles Symfony `FormTypeInterface` classes; maps field types and validator constraints to OpenAPI properties
- `ViewParser` — handles classes implementing `Dev\ViewBundle\View\ViewInterface`; recursively describes nested objects
- `ObjectParser` — fallback for plain DTOs; reads public properties and PHP types

## Attributes (used in consuming application)

- `#[Operation(description, request, responses, security)]` — class-level; marks an action as a documented endpoint
- `#[Property(required, attr)]` — property-level on DTOs; sets required flag and extra OpenAPI attributes
- `#[Model(model, type)]` — class-level; currently unused in parsers

## Coding Style

- Follow PSR-12: 4-space indent, one class per file, `declare(strict_types=1)`.
- Use typed properties and return types; favor `readonly` where appropriate.
- Keep constructors light; prefer small, composable services injected via Symfony DI.
- `php-cs-fixer.dist.php` is present — run PHP CS Fixer before committing if available.

## proto.yaml

A hand-authored YAML merged at the end of generation:
- `components.securitySchemes` — first scheme becomes default when `#[Security]` is detected
- `components.schemas` — merged with generated schemas
- `components.responses` — shared response refs used in `#[Operation](responses: [...])`

## Commit Guidelines

- Commit messages: short, action-oriented, optionally bracketed scope (e.g., `[fix] handle missing route`, `[feat] add form parser`).
- Keep commits focused; avoid unrelated formatting churn.
Loading