Skip to content
CAI
Software that uses CAICheck a score

dykyi-roman/crossword

34.5

Weak · 20 September 2026

7.1k

lines of production code

PHP

primary language

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is a Symfony-based web application that enables users to play crossword puzzles, manage player accounts, and track game history. It provides backend services for generating crossword grids, searching a dictionary with pattern masks, and retrieving word definitions from external sources like Google and Wikipedia. The architecture supports asynchronous processing and persistent storage using Redis, Elasticsearch, and RabbitMQ.

Features

Added CSV and text file readers for dictionary population

The Dictionary module now includes infrastructure implementations for reading word lists from CSV and plain text files. CsvFileReader and TextFileReader have been added to parse these formats and yield their contents, supporting the new word populate command that allows users to load dictionary data from local files.

code/src/Dictionary/Infrastructure/FileReader · high confidence

Added Google and Wikipedia word definition gateways

The Dictionary module now integrates two new external sources for word definitions. The new Google API gateway fetches definitions from a configurable Google API host and falls back to the parent implementation if the response is invalid or an error occurs. The new Wikipedia API gateway retrieves the first sentence of a page's extract (excluding entries that merely refer to the word) and replaces the search term with a placeholder in the returned text; it also falls back to the parent implementation on failure or if no valid extract is found.

code/src/Dictionary/Infrastructure/Gateway/Google, code/src/Dictionary/Infrastructure/Gateway/Wikipedia · high confidence

Added audit and failure logging middleware for message handling

Two new middleware components have been introduced to the Symfony Messenger infrastructure to improve observability. The AuditMiddleware logs the class name and body of every message as it is received and handled, providing a clear trail of incoming events. The FailureLoggerMiddleware automatically logs error messages whenever a message handler fails with a HandlerFailedException, ensuring that failures are captured in logs before the exception is re-thrown.

code/src/SharedKernel/Infrastructure/Messenger · high confidence

Added convenience scripts for Docker container interaction

New shell scripts (composer, console, php) have been added to the docker/scripts directory to simplify running commands inside the game\_php container. These scripts allow users to execute Composer, Symfony Console, and PHP commands directly from the host without manually typing docker exec commands.

docker/scripts · high confidence

Added history rating data access implementations

Introduced two new Data Access Object (DAO) implementations for the game history feature: a Doctrine-based repository for persistent storage and an in-memory version for testing or lightweight scenarios. Both classes implement the HistoryDaoInterface, providing a ratingHistory method that retrieves player nickname and level data, enabling the application to fetch historical game ratings from either a database or an in-memory collection.

code/src/Game/Infrastructure/Dao · high confidence

Added in-memory and Redis cache implementations for the Crossword module

The Crossword infrastructure now includes two concrete cache providers implementing the PSR-6 CacheItemPoolInterface: an InMemoryClient for simple, non-persistent caching and a RedisClient for persistent storage backed by a Predis client. These implementations, along with a shared CacheItem class, allow the Crossword application to store and retrieve data using either an in-memory array or a Redis instance, configurable via host and port parameters for the Redis backend.

code/src/Crossword/Infrastructure/Cache · high confidence

Added in-memory word definition gateway for testing

An in-memory implementation of the word definition API gateway has been added to the Dictionary infrastructure layer. This class allows the application to provide a static word definition for lookups, which is primarily useful for unit testing and scenarios where an external API is not required. It implements the standard gateway interface and throws a specific exception when the definition is empty or when attempting to chain to a next gateway.

code/src/Dictionary/Infrastructure/Gateway/InMemory · high confidence

Crossword feature module restructured with new API endpoints

The Crossword module has been reorganized into distinct feature areas (Generator, Receiver, Languages, Types), introducing new API endpoints for generating crosswords (\/api/crossword/generate\), retrieving supported languages (\/api/crossword/languages\), fetching supported types (\/api/crossword/types\), and constructing crosswords (\/api/crossword/construct/{language}/{type}/{words}\). The Generator feature now uses a console command and message bus for asynchronous generation, while the Receiver feature handles crossword retrieval from storage. The Languages and Types features provide metadata endpoints, and the old Dictionary test controller has been replaced by the new TypesAction endpoint.

(repo-wide) · high confidence

Crossword generation now supports multiple backend implementations

The game module now allows crossword puzzles to be generated via different backends, implemented through three new adapter classes in the infrastructure layer. An API adapter fetches puzzles from an external service, a direct adapter retrieves them from a local receiver, and an in-memory adapter provides static data for testing. This change enables the game to switch between external APIs, internal services, or mock data depending on the environment.

code/src/Game/Infrastructure/Adapter · high confidence

Elasticsearch-backed dictionary storage implementation

The Dictionary module now uses Elasticsearch for word storage and retrieval. This change introduces a new infrastructure layer within the Repository component that includes a ClientFactory for connection management, a ReadWordsStorage for searching words by language and mask patterns, a WriteWordsStorage for indexing word definitions, and supporting DTOs (StorageWordDto, StorageWordDtoCollection) to map between Elasticsearch responses and application objects. Users benefit from the underlying shift to Elasticsearch for dictionary data persistence and querying capabilities.

code/src/Dictionary/Infrastructure/Repository · high confidence

Enable RabbitMQ Management and Visualiser plugins

The Docker configuration for RabbitMQ now includes the management and management visualiser plugins by default. This allows users to access the RabbitMQ Management UI and visualise queues, exchanges, and connections directly through the browser without needing to manually enable these plugins.

docker/rabbit · high confidence

Initial Docker environment setup for local development and testing

This change introduces the Docker infrastructure required to run the application locally, including a main docker-compose.yml that orchestrates the web server (Nginx), PHP application, Elasticsearch, Redis, and RabbitMQ services. It also adds specific configuration files for macOS volume synchronization (docker-compose.mac.yml) and a CI/testing environment (docker-compose.test.yml) that includes Xdebug coverage and code analysis tools, along with a .env file defining default RabbitMQ credentials.

docker · high confidence

Initial project scaffolding and modular architecture setup

The application is initialized with a modular structure separating Dictionary, Crossword, and Game domains, each with dedicated configuration for services, routes, and dependency analysis. This includes API endpoints for dictionary languages and word search, crossword construction and type/language retrieval, and game features like player authentication, answer checking, and rating history. Infrastructure is configured with Redis for crossword storage, Elasticsearch for dictionary data, and RabbitMQ for asynchronous messaging. The project also sets up development tooling including PHPUnit, Psalm, EasyCodingStandard, Deptrac, and Rector, along with Swagger API documentation generation.

code · high confidence

Introduce Crossword Constructor feature module

This change adds the internal implementation for the Crossword Constructor feature, introducing a new \ConstructorFactory\ that creates either \NormalConstructor\ or \FiguredConstructor\ instances based on the requested type. The module includes a message handler (\GenerateCrosswordMessageHandler\) to process asynchronous generation requests, a grid scanning system (\GridScanner\, \RowXScanner\, \RowYScanner\) to identify valid word placements, and a dictionary integration layer (\WordFinder\, \DictionarySearchInterface\) to fetch words and definitions. It also defines the necessary data transfer objects (\CrosswordDto\, \LineDto\, \DictionaryWordDto\) and repository interfaces (\PersistCrosswordRepositoryInterface\) to persist the generated puzzles.

code/src/Crossword/Features/Constructor · high confidence

Introduce Doctrine-based persistence and in-memory fallback for player and history data

The Game module now supports persistent storage for player accounts and game history via new Doctrine repository implementations (PersistPlayerRepository, PersistHistoryRepository, ReadPlayerRepository, ReadHistoryRepository) and a corresponding database migration that creates 'player' and 'history' tables. An in-memory player repository is also provided as an alternative implementation, allowing the application to operate without a database in development or testing environments. This change enables the game to store and retrieve player credentials, levels, roles, and historical game data.

code/src/Game/Infrastructure/Repository/Doctrine · high confidence

Introduce player domain model and event-driven level progression

This change adds the core Player feature components, including the Player aggregate root, value objects (PlayerId, Role, PlayerDto), and a level management system. It implements a domain event pattern where changing a player's level raises a LevelUpEvent, which is persisted via Doctrine and dispatched through Symfony Messenger. A specific handler (CrosswordPuzzleSolvedEventHandler) listens for crossword completion events to automatically advance the player's level, enforcing a maximum level cap defined in the Level enum.

code/src/Game/Features/Player · high confidence

Introduce player registration and authorization features

This change adds the core infrastructure for player registration and authorization within the Game module. It introduces a command-line interface (\game:create-player\) for registering new players with nickname, password, and optional role, including validation for password strength and supported roles. It also implements a web-based login flow, featuring a Twig template for the login page and backend actions to handle authentication, manage player tokens, and refresh session data upon level changes.

code/src/Game/Features/Authorization, code/src/Game/Features/Registration, code/src/Game/templates · high confidence

New Dictionary Words Finder API endpoint

The Dictionary module now exposes a new API endpoint at /api/dictionary/words/{language} that allows users to search for words using pattern masks (e.g., \.e.\\ or \na.\{0,4}\) and retrieve results with definitions. This feature introduces a structured domain layer including request handling, mask parsing, and response formatting, enabling pattern-based word lookups within the dictionary.

code/src/Dictionary/Features/WordsFinder · high confidence

New Doctrine types for Game history and player IDs

Added Doctrine type converters for the Game module's domain identifiers. HistoryIdType maps the database GUID column to the HistoryId value object, while PlayerIdType performs the same mapping for PlayerId, utilizing Symfony's UuidV4 component for conversion. These types enable the persistence layer to correctly serialize and deserialize these specific ID structures.

code/src/Game/Infrastructure/Repository/DoctrineTypes · high confidence

New Game module with crossword play, answer validation, and history tracking

The codebase now includes a new Game module that introduces three core capabilities. First, the GamePlay feature allows players to start a new crossword puzzle, with the grid size and type (normal or figured) determined by the player's role and level, and renders the game via a Twig template. Second, the Answers feature provides a mechanism for players to submit their answers, which are validated against correct solutions; successful submissions trigger a CrosswordPuzzleSolved event, while incorrect answers return specific error details. Third, the History feature tracks player progression by persisting records when a player levels up and exposes a player rating history endpoint that returns the top 10 players by level.

code/src/Game/Features/Answers, code/src/Game/Features/GamePlay, code/src/Game/Features/History · high confidence

New HTTP client infrastructure with retry and logging middleware

The application now includes a new \GuzzleClient\ implementation in the shared kernel infrastructure that wraps the Guzzle HTTP client. This client supports a pluggable middleware pipeline, specifically introducing a \RetryMiddleware\ that automatically retries requests on 429 and 503 status codes or connection timeouts, and a \LoggerMiddleware\ that logs request and response bodies. This change provides robust error handling and observability for outbound HTTP calls without requiring individual services to implement these patterns.

code/src/SharedKernel/Infrastructure/HttpClient · high confidence

New content-type-aware responders for JSON, XML, and HTML responses

The application now includes dedicated responder classes (JsonResponder, WebResponder, XmlResponder) that automatically convert controller results into appropriate HTTP responses based on the request's content type. JsonResponder handles 'json' requests by wrapping the result in a JsonResponse, WebResponder handles null or 'form' content types by setting the result as HTML content, and XmlResponder converts array data into XML format for 'xml' requests. These responders are registered as event subscribers to the Symfony kernel's VIEW event, enabling automatic response formatting without requiring explicit response handling in controllers.

code/src/SharedKernel/Infrastructure/Responder · high confidence

New dictionary population and upload commands

The Dictionary module now includes two new console commands: \dictionary:populate\ and \dictionary:upload\. The populate command allows users to add new words to the storage by providing a language code and an optional text file path, while the upload command enables users to upload words and their definitions from a CSV file. Both commands are designed to integrate with the existing storage system, ensuring that new dictionary entries are properly saved and managed.

code/src/Dictionary/Features/PopulateStorage · high confidence

New infrastructure adapters for dictionary services and Redis-backed crossword persistence

This change introduces new adapter implementations within the Crossword infrastructure layer to support dictionary lookups and crossword storage. For dictionary services, three adapters are added: ApiDictionaryAdapter for external API calls, DirectDictionaryAdapter for local word-finding logic, and InMemoryDictionaryAdapter for testing. Additionally, Redis-based repositories are implemented for crossword data: PersistCrosswordRepository handles saving crossword DTOs to a cache pool, while ReadCrosswordRepository retrieves and shuffles crossword lists from the same cache, throwing a specific exception if a crossword is not found.

code/src/Crossword/Infrastructure/Adapter · high confidence

Project scaffolding and CI/CD integration

The repository is initialized with essential project files including an MIT license, a .gitignore configuration for development artifacts, and a comprehensive README documenting the architecture (Symfony 5.2, PHP 8.0, Elasticsearch, Redis, RabbitMQ) and usage instructions. A Travis CI configuration is added to automate testing via Docker, and the Makefile is expanded to support various quality checks (phpcs, psalm, deptrac, ecs) and Postman API tests, establishing a baseline for continuous integration and code quality enforcement.

(repo-wide) · high confidence

Behavioural changes

15 commits (0 fixes) modifying code/var

A change to existing behaviour in code/var — 15 commits, 2 files.

code/var · medium confidence · unverified

Adopts modular architecture with Redis and Elasticsearch integration

The application has been restructured into distinct feature modules (Crossword, Dictionary, Game, SharedKernel, Swagger), each with its own service configuration. This change introduces Redis as a base storage layer and integrates Elasticsearch for dictionary data, configured via environment variables for hosts and ports. Additionally, the Symfony kernel now registers Monolog, Doctrine, Doctrine Migrations, and Security bundles, while the global service configuration delegates to module-specific service files and binds external API hosts (Google, Wikipedia, Dictionary, Crossword) to application services.

code/config · high confidence

Introduces chain-of-responsibility pattern for word definition lookups

The Dictionary infrastructure now supports a chain-of-responsibility pattern for word definition lookups via the new AbstractWordDefinition class. This allows multiple gateway implementations to be linked together, enabling sequential processing or fallback logic when searching for word definitions in a specific language.

code/src/Dictionary/Infrastructure/Gateway · high confidence

Test coverage

Added test coverage for the Game module; Added test infrastructure and unit tests for the Game module; Added test infrastructure for Crossword and Dictionary modules; Added unit tests for Dictionary module features; Added unit tests for the Crossword and Dictionary modules.

Dependencies

Upgrade to PHP 8.0 and expand Symfony/Doctrine ecosystem dependencies

The project now requires PHP 8.0 (up from 7.2.5) and introduces a broader set of dependencies, including Symfony 5.2 components (Messenger, AMQP Messenger, Security, UID), Doctrine bundles (ORM, Migrations, Bundle), Elasticsearch, Guzzle, Predis, and various dev tools like PHPUnit 9.5, Psalm, and Deptrac. This shift enables modern PHP features, asynchronous messaging, enhanced security, and improved code quality analysis capabilities.

(dependencies) · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings — which rule fired, in which file, on which line, and how to fix it — are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.

Score

  • CAI 46 → 35 (-11.5)
  • Rubric changed (rubric-2026.08.17 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 99 → 99 (-0.2)
  • Architecture 100 → 91 (-9.0)
  • Maturity 46 → 48 (+2.5)
  • Readiness 23 → 28 (+5.3)
  • Security 77 → 75 (-2.0)
  • Accessibility 19 (new)

Resolved (20)

  • Coverage not included — suite not readable by the collector
  • Dependency hygiene not measured — no supported dependency manifest was read
  • Duplicated block (12 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/RowXScanner.php)
  • Duplicated block (12 lines × 4) (code/src/Crossword/Features/Generator/Console/AbstractCommand.php)
  • Duplicated block (14 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/RowXScanner.php)
  • Duplicated block (15 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/RowXScanner.php)
  • Duplicated block (5 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/Grid/RowMask.php)
  • Duplicated block (6 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/Grid/RowMask.php)
  • Duplicated block (9–10 lines × 2) (code/src/Game/Features/Answers/Authentication/PlayerFromTokenExtractor.php)
  • High IaC: DS-0025 (docker/nginx/Dockerfile)
  • High IaC: DS-0029 (docker/php/Dockerfile)
  • Low IaC: DS-0026 (docker/newman/Dockerfile)
  • Low IaC: DS-0026 (docker/php-ci/Dockerfile)
  • Low IaC: DS-0026 (docker/php/Dockerfile)
  • Medium: security finding (details withheld)
  • Medium: security finding (details withheld)
  • Medium: security finding (details withheld)
  • No exposed public API
  • Test reliability not included
  • dormant codebase — no living knowledge left to concentrate

New (58)

  • Critical CVE: [GHSA redacted] (code/composer.lock)
  • Documentation: no installation or build instructions (README.md)
  • Documentation: no usage examples (README.md)
  • Duplicated block (12 lines × 2) (code/src/Dictionary/Infrastructure/FileReader/CsvFileReader.php)
  • Duplicated block (13 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/RowXScanner.php)
  • Duplicated block (13 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/RowXScanner.php)
  • Duplicated block (14 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/RowXScanner.php)
  • Duplicated block (15 lines × 2) (code/src/Dictionary/Features/PopulateStorage/Populate/FileAssert.php)
  • Duplicated block (18 lines × 2) (code/src/Crossword/Features/Constructor/Message/GenerateCrosswordMessage.php)
  • Duplicated block (18 lines × 4) (code/src/Crossword/Features/Generator/Console/AbstractCommand.php)
  • Duplicated block (19 lines × 6) (code/src/Game/Features/Answers/Player/PlayerId.php)
  • Duplicated block (26 lines × 3) (code/src/Crossword/Features/Constructor/Dictionary/Word.php)
  • Duplicated block (34 lines × 2) (code/src/Game/Features/GamePlay/Player/PlayerDto.php)
  • Duplicated block (5 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/Grid/RowMask.php)
  • Duplicated block (5 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/Grid/RowMask.php)
  • Duplicated block (7 lines × 2) (code/src/Dictionary/Features/PopulateStorage/Populate/WordsStoragePopulate.php)
  • Duplicated block (7–10 lines × 2) (code/src/Game/Features/Answers/Authentication/PlayerFromTokenExtractor.php)
  • Duplicated block (9 lines × 2) (code/src/Crossword/Features/Constructor/Scanner/Grid/RowMask.php)
  • High CVE: [GHSA redacted] (code/composer.lock)
  • High CVE: [GHSA redacted] (code/composer.lock)
  • …and 38 more

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

dykyi-roman/crossword was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 20 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit 00cd7c526b66cdba591eaf421d670602f7dfc9d2 — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-28e75b8e3254.