Files
XC_VM/build/phpcs.xml.dist
T
Divarion_D b9de28f624 build: widen the Rector set, fix its cache trap, and quiet the fixerless phpcs sniffs
Rector — enable instanceOf, earlyReturn and if. Each was measured at zero changes
across the analysed tree, so they cost nothing now and only hold the line on new
code. The counts for every set that stays off are recorded next to them, with the
reason, so the decision does not have to be re-derived: typeDeclarations(319) is
the native-type footgun TYPE_AUDIT.md tracks, typeDeclarationDocblocks(86) feeds
that same footgun one step removed because `make cs-fix` derives native types from
docblocks, codingStyle(255) rewrites the `use` imports check-procedural-use depends
on, naming(132) fights the $r-prefix convention and render()-by-name views, and
privatization reads as 0 only because there are almost no final classes yet.

Makefile — `make rector` now passes --clear-cache. Rector's cache key does not
track the rule set, so after editing the config a cached run prints "Rector is
done!" and a newly enabled set looks like a no-op. The measurements above first
came back all-zero for exactly this reason.

phpcs — silence the four sniffs that were still reporting. Every one of them was
checked for a fixer first (none calls addFixable), so `make cs-fix` could never
have cleared them; what was left was 769 warnings no tool can act on:

  NoSilencedErrors(473)  each @ is either deliberate or masking a real error, so
                         they need judging one at a time, with a test each
  CyclomaticComplexity   (201 err + 190 warn) and NestingLevel (2 + 84) — already
                         ratcheted per-function by the CRAP gate, which blocks NEW
                         complexity; the sniffs only restated the old backlog
  PSR1.Files.SideEffects(22)  needs files split, which moves loading and autoload

LineLength(3480) went the same way earlier and is marked as not part of the
ratchet: it has no fixer at all, so "re-enable and fix" would mean splitting those
lines by hand.

Own rules are commented out so they read as toggles; the PSR12-inherited ones
(SideEffects, LineLength) can only be <exclude>d, which the ratchet summary now
says out loud. That summary is updated with every new toggle and its count.

`make cs` is now clean, with 85 sniffs still active — checked, because an empty
report looks the same whether nothing is wrong or everything got muted.
2026-09-22 18:20:45 +03:00

378 lines
19 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="XC_VM PSR-12"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/squizlabs/php_codesniffer/phpcs.xsd">
<description>
PSR-12 strict coding standard
Run via `make cs` (report) / `make cs-fix` (auto-fix, = phpcbf).
</description>
<!-- Analyzed set mirrors the old cs-fixer Finder (paths passed on the CLI by
the Makefile; these are the exclusions). -->
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/Infrastructure/Tmdb/lib/*</exclude-pattern>
<exclude-pattern>*/tmp/*</exclude-pattern>
<exclude-pattern>*/backups/*</exclude-pattern>
<exclude-pattern>*/Public/Views/*</exclude-pattern>
<exclude-pattern>*/Modules/*/views/*</exclude-pattern>
<!-- Analyse PHP only. phpcbf's default extension list also covers js/css
(legacy tokenizers), which would otherwise reformat those files. -->
<arg name="extensions" value="php"/>
<!-- Indentation is a real tab (rendered 4 wide), not PSR-12's 4 spaces. -->
<arg name="tab-width" value="4"/>
<!-- Code MUST follow PSR-12, EXCEPT brace placement: this project uses
K&R / one-true-brace (opening brace on the SAME line), not PSR-12's
Allman placement. The Allman-enforcing sniffs are excluded here and the
K&R sniffs are added at the end of this ruleset. -->
<rule ref="PSR12">
<exclude name="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
<exclude name="PSR2.Classes.ClassDeclaration.OpenBraceNewLine"/>
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
<!-- Multi-line function declarations also keep the brace on the same
line (K&R), so drop PSR-12's "brace on new line" for them. -->
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine"/>
<!-- ── Temporarily disabled PSR-family sniffs (technical-debt ratchet) ──
These come from the PSR12 parent, so they can only be switched off
here with <exclude>. To ENABLE one: DELETE its exclude line, run
`make cs`, fix the fallout, commit. (…N) = current violation count. -->
<exclude name="PSR1.Methods.CamelCapsMethodName"/> <!-- 40: legacy snake_case methods -->
<exclude name="PSR1.Classes.ClassDeclaration"/> <!-- 2: legacy non-namespaced (XC_Bootstrap) -->
<exclude name="PSR2.Classes.PropertyDeclaration.Underscore"/> <!-- 2: legacy _property names -->
<exclude name="PSR2.Methods.MethodDeclaration.Underscore"/> <!-- 12: legacy _method names -->
<exclude name="PSR2.ControlStructures.SwitchDeclaration.TerminatingComment"/> <!-- 6: add `// no break` -->
<exclude name="PSR12.Files.FileHeader.IncorrectOrder"/> <!-- 29: header declare/namespace/use order -->
<exclude name="Squiz.Classes.ValidClassName"/> <!-- 1: legacy class name -->
<exclude name="PSR1.Files.SideEffects"/> <!-- 22: declares symbols AND runs code -->
<!-- Line length (3480 warnings across 284 of 557 analysed files). Muted
for REPORT NOISE only: it is a warning, and ignore_warnings_on_exit
below already keeps it from failing the run. NOT part of the ratchet
above: Generic.Files.LineLength has no fixer (it only calls
addWarning), so neither phpcbf nor PHP-CS-Fixer nor Rector can wrap
these lines — re-enabling it would mean splitting them by hand. The
one sniff that could help, PEAR.Functions.FunctionCallSignature, is
permanently disabled below because it cannot converge under tabs. -->
<exclude name="Generic.Files.LineLength"/>
<!-- ── PERMANENTLY disabled — DO NOT ENABLE ──
Space-alignment sniff that cannot converge under tab indentation:
LineIndent counts SPACES ("expected 12, found 8" on 3 tabs) and
FirstExpressionLine/CloseParenthesisLine force the expanded PSR-12
layout, so phpcbf oscillates → FAILED TO FIX. The tab-safe
equivalent PEAR.ControlStructures.MultiLineCondition is enabled
below and enforces the same multi-line `if` layout. See 689663d4. -->
<exclude name="PSR12.ControlStructures.ControlStructureSpacing"/>
</rule>
<!-- Indentation MUST use tabs (one tab per level), not PSR-12's 4 spaces. -->
<rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/>
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="indent" value="4"/>
<property name="tabIndent" value="true"/>
</properties>
</rule>
<!-- Generic rules -->
<!-- All values in multiline arrays must be indented with 4 spaces. -->
<rule ref="Generic.Arrays.ArrayIndent"/>
<!-- The short array syntax MUST be used to define arrays. -->
<rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
<!-- There MUST NOT be duplicate class names. -->
<rule ref="Generic.Classes.DuplicateClassName"/>
<!-- The final keyword on methods MUST be omitted in final classes. -->
<rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier"/>
<!-- Detects unnecessary overridden methods that simply call their parent. -->
<rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>
<!-- There MUST be one whitespace after a type casting operator. -->
<rule ref="Generic.Formatting.SpaceAfterCast"/>
<!-- Checks the cyclomatic complexity (McCabe) for functions.
DISABLED — MaxExceeded(201 errors) + TooHigh(190 warnings). Complexity is
already ratcheted by the CRAP gate (.claude/quartermaster/crap.json,
ceiling 6 against main), which blocks NEW complexity per function; this
sniff only restated the existing backlog. Uncomment to surface it again,
then refactor the fallout. -->
<!--
<rule ref="Generic.Metrics.CyclomaticComplexity">
<exclude name="Generic.Metrics.CyclomaticComplexity.MaxExceeded"/>
</rule>
-->
<!-- Checks the nesting level for methods.
DISABLED — MaxExceeded(2 errors) + TooHigh(84 warnings). Same reasoning as
the complexity sniff above; uncomment to enforce. -->
<!--
<rule ref="Generic.Metrics.NestingLevel">
<exclude name="Generic.Metrics.NestingLevel.MaxExceeded"/>
</rule>
-->
<!-- Checks that abstract classes are prefixed by Abstract.
DISABLED (2) — uncomment to enable. -->
<!-- <rule ref="Generic.NamingConventions.AbstractClassNamePrefix"/> -->
<!-- Ensures method and functions are named correctly.
DISABLED (187) — legacy snake_case function names; renames break
callers. Uncomment to enable. -->
<!-- <rule ref="Generic.NamingConventions.CamelCapsFunctionName"/> -->
<!-- Checks that interfaces are suffixed by Interface.
DISABLED (1) — uncomment to enable. -->
<!-- <rule ref="Generic.NamingConventions.InterfaceNameSuffix"/> -->
<!-- Checks that traits are suffixed by Trait.
DISABLED (1) — uncomment to enable. -->
<!-- <rule ref="Generic.NamingConventions.TraitNameSuffix"/> -->
<!-- The backtick operator MUST NOT be used. -->
<rule ref="Generic.PHP.BacktickOperator"/>
<!-- Deprecated PHP functions MUST be avoided.
DISABLED (1) — uncomment to enable. -->
<!-- <rule ref="Generic.PHP.DeprecatedFunctions"/> -->
<!-- The PHP `goto` language construct SHOULD NOT be used. -->
<rule ref="Generic.PHP.DiscourageGoto"/>
<!-- Alias functions SHOULD NOT be used. -->
<rule ref="Generic.PHP.ForbiddenFunctions">
<properties>
<property name="forbiddenFunctions" type="array">
<element key="chop" value="rtrim"/>
<element key="close" value="closedir"/>
<element key="compact" value="null"/>
<element key="delete" value="unset"/>
<element key="doubleval" value="floatval"/>
<element key="extract" value="null"/>
<element key="fputs" value="fwrite"/>
<element key="ini_alter" value="ini_set"/>
<element key="is_double" value="is_float"/>
<element key="is_integer" value="is_int"/>
<element key="is_long" value="is_int"/>
<element key="is_real" value="is_float"/>
<element key="join" value="implode"/>
<element key="key_exists" value="array_key_exists"/>
<element key="pos" value="current"/>
<element key="settype" value="null"/>
<element key="show_source" value="highlight_file"/>
<element key="sizeof" value="count"/>
<element key="strchr" value="strstr"/>
</property>
</properties>
</rule>
<!-- Throws an error or warning when any code prefixed with an asperand is encountered.
DISABLED (473) — uncomment to enable. Not a style fix: each `@` is either
deliberate (@unlink on a maybe-missing file) or masking a real error, so
they have to be judged one at a time, with a test per behaviour change. -->
<!-- <rule ref="Generic.PHP.NoSilencedErrors"/> -->
<!-- Checks that the `strict_types` has been declared. -->
<!-- <rule ref="Generic.PHP.RequireStrictTypes"/> -->
<!-- The constant `PHP_SAPI` SHOULD be used instead of the `php_sapi_name()` function.
DISABLED (7) — uncomment to enable (mechanical: php_sapi_name() → PHP_SAPI). -->
<!-- <rule ref="Generic.PHP.SAPIUsage"/> -->
<!-- Checks that two strings are not concatenated together; suggests using one string instead.
DISABLED (41) — uncomment to enable. -->
<!-- <rule ref="Generic.Strings.UnnecessaryStringConcat"/> -->
<!-- Check & fix whitespace on the inside of arbitrary parentheses. -->
<rule ref="Generic.WhiteSpace.ArbitraryParenthesesSpacing"/>
<!-- Verifies spacing between the spread operator and the variable/function call it applies to. -->
<rule ref="Generic.WhiteSpace.SpreadOperatorSpacingAfter"/>
<!-- PEAR rules -->
<!-- Verifies that control statements conform to their coding standards. -->
<rule ref="PEAR.ControlStructures.ControlSignature"/>
<!-- Ensure multi-line `if` conditions are defined correctly. Tab-safe
replacement for the disabled PSR12 ControlStructureSpacing (see the
PSR12 exclude block above). -->
<rule ref="PEAR.ControlStructures.MultiLineCondition"/>
<!-- If an assignment goes over two lines, ensure the equal sign is indented.
DISABLED (49) — uncomment to enable. -->
<!-- <rule ref="PEAR.Formatting.MultiLineAssignment"/> -->
<!-- Ensure single and multi-line function declarations are defined correctly. -->
<rule ref="PEAR.Functions.FunctionDeclaration">
<!-- K&R: opening brace stays on the same line, incl. multi-line signatures. -->
<exclude name="PEAR.Functions.FunctionDeclaration.BraceOnSameLine"/>
</rule>
<!-- Checks that object operators are indented correctly. -->
<rule ref="PEAR.WhiteSpace.ObjectOperatorIndent"/>
<!-- Checks that the closing braces of scopes are aligned correctly. -->
<rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/>
<!-- Squiz rules -->
<!-- Checks the declaration of the class and its inheritance is correct. -->
<rule ref="Squiz.Classes.ClassDeclaration">
<!-- K&R: class opening brace on the SAME line (see Generic.Classes.OpeningBraceSameLine). -->
<exclude name="Squiz.Classes.ClassDeclaration.OpenBraceNewLine"/>
</rule>
<!-- The file name MUST match the case of the terminating class name.
DISABLED (1) — uncomment to enable. -->
<!-- <rule ref="Squiz.Classes.ClassFileName"/> -->
<!-- For self-reference a class lower-case `self::` MUST be used
without spaces around the scope resolution operator. -->
<rule ref="Squiz.Classes.SelfMemberReference"/>
<!-- The `&&` and `||` operators SHOULD be used instead of `and` and `or`. -->
<rule ref="Squiz.Operators.ValidLogicalOperators"/>
<!-- The `global` keyword MUST NOT be used.
DISABLED (478) — architectural `global $db` → DatabaseAware migration;
not a quick style fix. Uncomment to enable. -->
<!-- <rule ref="Squiz.PHP.GlobalKeyword"/> -->
<!-- PHP function calls MUST be in lowercase. -->
<rule ref="Squiz.PHP.LowercasePHPFunctions"/>
<!-- Non executable code MUST be removed. -->
<rule ref="Squiz.PHP.NonExecutableCode"/>
<!-- The pseudo-variable `$this` MUST NOT be called inside a static method or function. -->
<rule ref="Squiz.Scope.StaticThisUsage"/>
<!-- Makes sure there are no spaces around the concatenation operator. -->
<rule ref="Squiz.Strings.ConcatenationSpacing">
<properties>
<property name="spacing" value="1" />
<!-- Don't collapse indentation into a single space on multi-line
concatenations (the `.` at the start of an indented continuation
line) — that fights the indent sniff and prevents phpcbf from
converging. -->
<property name="ignoreNewlines" value="true" />
</properties>
</rule>
<!-- Checks the separation between functions and methods. -->
<rule ref="Squiz.WhiteSpace.FunctionSpacing">
<properties>
<property name="spacing" value="1" />
<property name="spacingBeforeFirst" value="0" />
<property name="spacingAfterLast" value="0" />
</properties>
</rule>
<!-- There MUST NOT be any white space around the object operator UNLESS multilines are used. -->
<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
<!-- Verifies that class members are spaced correctly. -->
<rule ref="Squiz.WhiteSpace.MemberVarSpacing">
<properties>
<property name="spacing" value="1" />
<property name="spacingBeforeFirst" value="0" />
</properties>
</rule>
<!-- Ensure there is no whitespace before/after an object operator. -->
<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">
<properties>
<property name="ignoreNewlines" value="true"/>
</properties>
</rule>
<!-- Verifies that operators have valid spacing surrounding them. -->
<rule ref="Squiz.WhiteSpace.OperatorSpacing">
<properties>
<property name="ignoreNewlines" value="true"/>
</properties>
</rule>
<!-- There MUST NOT be a space before a semicolon. Redundant semicolons SHOULD be avoided. -->
<rule ref="Squiz.WhiteSpace.SemicolonSpacing"/>
<!-- ══════════════════════════════════════════════════════════════════
PERMANENTLY disabled — DO NOT ENABLE (not part of the ratchet).
Space-alignment sniffs that align multi-line continuations with SPACES
relative to a tab-indented base. phpcbf inserts the spaces,
Generic.WhiteSpace.DisallowSpaceIndent strips them back, and the fixer
never converges → FAILED TO FIX. Multi-line call-argument alignment has
no tab-safe fixer, so this stays off (multi-line `if` layout IS enforced,
via PEAR.ControlStructures.MultiLineCondition above). -->
<!-- <rule ref="PEAR.Functions.FunctionCallSignature"/> -->
<!-- SlevomatCodingStandard.TypeHints.ParameterTypeHint — DO NOT ENABLE yet.
As a FIXER it auto-added native param types from @param docblocks that
crash on null at runtime (the "null given" footgun — see TYPE_AUDIT.md).
Keep off until that audit is worked through; then uncomment. -->
<!--
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint">
<properties>
<property name="enableObjectTypeHint" value="true"/>
</properties>
</rule>
-->
<!-- ── K&R / one-true-brace style (overrides PSR-12 Allman) ──────────
Opening brace on the SAME line as the declaration, for classes and
for functions/methods/closures. Both sniffs are phpcbf-fixable. -->
<rule ref="Generic.Classes.OpeningBraceSameLine"/>
<rule ref="Generic.Functions.OpeningFunctionBraceKernighanRitchie">
<properties>
<property name="checkClosures" value="true"/>
</properties>
</rule>
<!-- ══════════════════════════════════════════════════════════════════
Technical-debt ratchet — how to gradually tighten this ruleset.
Sniffs that legacy code still violates are DISABLED so `make cs` stays
green and can act as a baseline. Enable ONE at a time: flip its toggle,
run `make cs`, fix the fallout, run `make cs-fix` (confirm it converges,
no FAILED TO FIX), commit. Do NOT add new violations under a disabled
rule. Each disabled rule is a single-line toggle:
• Own `<rule ref>` commented out above → UNCOMMENT it:
NoSilencedErrors(473), CamelCapsFunctionName(187),
CyclomaticComplexity(201 err + 190 warn), NestingLevel(2 + 84),
MultiLineAssignment(49), UnnecessaryStringConcat(41), SAPIUsage(7),
AbstractClassNamePrefix(2), InterfaceNameSuffix(1), TraitNameSuffix(1),
DeprecatedFunctions(1), Squiz.Classes.ClassFileName(1),
Squiz.PHP.GlobalKeyword(478).
• <exclude> in the PSR12 block above → DELETE the exclude line.
(Sniffs inherited from the PSR12 parent CANNOT be commented out —
<exclude> is the only switch for them.)
CamelCapsMethodName(40), FileHeader.IncorrectOrder(29),
PSR1.Files.SideEffects(22),
MethodDeclaration.Underscore(12), SwitchDeclaration.TerminatingComment(6),
PSR1.Classes.ClassDeclaration(2), PropertyDeclaration.Underscore(2),
Squiz.Classes.ValidClassName(1), Generic.Files.LineLength(3480 — has
no fixer, see its own note; not really part of this ratchet).
Suggested order (cheapest / lowest-risk first): SAPIUsage,
DeprecatedFunctions, SwitchDeclaration.TerminatingComment,
MultiLineAssignment, UnnecessaryStringConcat, FileHeader.IncorrectOrder,
the small naming/rename sniffs, then the underscore renames. Leave the
architectural ones (GlobalKeyword, Cyclomatic/Nesting, CamelCaps names)
for dedicated refactors. See the "PERMANENTLY disabled" blocks for the
two that must stay off.
Warnings (line length, cyclomatic "too high", silenced errors, …) are
reported but do NOT fail the run:
══════════════════════════════════════════════════════════════════════ -->
<config name="ignore_warnings_on_exit" value="1"/>
</ruleset>