Status: Accepted Date: 2025-02-28 Deciders: Walmir Silva Context: KaririCode Framework Devkit v1.0.0
Each quality tool requires a configuration file (phpunit.xml.dist, phpstan.neon, php-cs-fixer.php, rector.php, psalm.xml). Across 35+ components, these files are near-identical, differing only in:
- Source directory paths (derived from PSR-4 autoload)
- Test suite directory structure
- PHP version target
- PHPStan analysis level
Maintaining 175+ config files manually leads to configuration drift, inconsistent rules, and merge-conflict friction when updating standards.
Config files are generated deterministically from a ProjectContext snapshot by ConfigGenerator implementations. The generation cycle is:
composer.json → ProjectDetector → ProjectContext → ConfigGenerator → .kcode/*.config
Manual customization is achieved through a single override file (devkit.php) that is merged with ecosystem defaults — not by editing generated configs.
Generated files include a header comment: Generated by KaririCode Devkit — override via devkit.php (project root).
- Single source of truth — Coding standards and analysis rules live in
ProjectDetector::DEFAULT_CS_RULESandDEFAULT_RECTOR_SETS. Updating the devkit updates all components. - Deterministic output — Same
ProjectContextalways produces the same config files. No hidden state, no manual edits to preserve. - Override granularity —
devkit.phpsupports per-project customization at the key level (PHPStan level, extra CS rules, excluded directories) without duplicating the entire config. - Safe regeneration —
kcode initcan be run repeatedly. Generated files are disposable artifacts.
// devkit.php — only specify what differs from defaults
<?php return [
'phpstan_level' => 8, // override: lower level
'exclude_dirs' => ['src/Contract', 'src/Legacy'], // override: extra exclusion
'cs_fixer_rules' => ['yoda_style' => false], // merge: added to defaults
];The merge strategy varies by key type:
| Key | Strategy | Rationale |
|---|---|---|
| Scalar (phpstan_level, php_version) | Replace | Project-specific requirement |
| List (source_dirs, exclude_dirs) | Replace | Full override for clarity |
| Map (cs_fixer_rules) | array_merge | Additive customization |
| Map (test_suites) | Replace | Suite structure is project-specific |
| Alternative | Rejected Because |
|---|---|
| Symlinks to shared configs | Doesn't support per-project overrides |
| Composer scripts + templates | Requires Twig/Blade; adds dependencies |
| .dist files with manual copy | Config drift returns immediately |
| Central config repo + git submodule | Poor developer experience; merge conflicts |
- Zero config drift across the ecosystem.
- One-command setup for new components:
kcode init. - Override file is version-controlled alongside the project.
- Generated configs are gitignored-friendly (optional).
- Developers cannot hand-edit generated configs (edits are overwritten on next
init). - The override merge logic must be well-documented to avoid confusion.
- Adding new config keys requires a devkit release.
- Microsoft documentation generators: config-as-code principle
- Terraform HCL: override files merged with base configuration
- ARFA 1.3 Specification, §4.3: Deterministic Configuration