Skip to content

feat(checkpoints): detect self-referencing class constants (PM-44) - #82

Merged
CybotTM merged 1 commit into
mainfrom
feat/retro-self-referencing-const-checkpoint
Jul 31, 2026
Merged

feat(checkpoints): detect self-referencing class constants (PM-44)#82
CybotTM merged 1 commit into
mainfrom
feat/retro-self-referencing-const-checkpoint

Conversation

@CybotTM

@CybotTM CybotTM commented Jul 30, 2026

Copy link
Copy Markdown
Member

Summary

Adds mechanical checkpoint PM-44 for const X = self::X — a fatal-at-load self-referencing constant that no static analyzer reports — plus the anti-pattern section describing the transform that produces it.

Came from

/retro session on 2026-07-30: 3bbf68c3-a30c-4e1e-af38-c97eaf711150
Finding: routed to checkpoint rather than prose because the pattern is a one-line regex — a gate that fails the build outranks a rule asking for care.

  • Symptom: Cannot declare self-referencing constant at runtime, after a scripted extraction of a repeated test payload into a constant. PHPStan level 10 passed the change; only the functional run caught it.
  • Cause: Blind replace-all of the literal also rewrote the constant's own declaration line, turning const SMALL_PAYLOAD = '{...}' into const SMALL_PAYLOAD = self::SMALL_PAYLOAD. The engine raises this only when the class is loaded, so analyzers cannot see it.
  • Required behavior: Exclude the declaration line when scripting literal-to-constant extraction, and verify by executing rather than analyzing.
  • Verification: checkpoints.yaml id PM-44.

Change

  • checkpoints.yaml: PM-44, mechanical, severity error
  • references/migration-strategies.md: anti-pattern section under "Anti-Patterns to Avoid", noting the hazard generalizes to any language's extract-to-constant transform

Note on the check's shape

The command enumerates existing source directories before grepping. My first version passed all four unconditionally, which is subtly broken: grep -q exits 2 when a directory is missing, and negating 2 yields 0 — the check would have silently passed on a real violation in any repo lacking one of src/, Classes/, tests/, Tests/. Existing PM-37/PM-39 avoid this by ending their pipelines in grep -q ., so no other checkpoint needed the same fix.

Test plan

  • validate-skill.sh — 0 errors; checkpoints.yaml parses and the command survives YAML escaping intact
  • Fires on the real pattern: const P = self::P → exit 1
  • Does not fire on a legitimate alias: const A = 'x'; const B = self::A; → exit 0
  • Detects violations under Tests/ as well as Classes/ → exit 1
  • Repo with no source directories → exit 0 (the case the first version got wrong)
  • End-to-end with the command read back out of the parsed YAML, not just as authored

Bulk-extracting a repeated literal into a constant — the usual php:S1192 fix —
also rewrites the line that declares the constant when run as a blind
replace-all, producing `const X = self::X`. That is fatal at class-load time
and PHPStan level 10 reports nothing, because the engine raises it only when
the class is actually loaded. A change set can pass every analyzer and still
be broken.

Adds PM-44 (mechanical) plus an anti-pattern section covering the two rules
that make the transform safe: exclude the declaration line, and verify by
executing rather than analyzing.

The check enumerates existing source directories before grepping. Passing
absent directories to `grep -q` makes it exit 2, and negating 2 yields 0 — the
check would have silently passed on a real violation in any repo lacking one
of src/, Classes/, tests/, Tests/.

Verified in both directions: exit 1 on `const P = self::P`, exit 0 on a
legitimate alias `const B = self::A` and on a repo with no source directories.

Found via /retro after the pattern reached a nr-vault test file and was caught
only by the functional run.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Copilot AI review requested due to automatic review settings July 30, 2026 19:54
@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

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

Scanned Files

None

@sonarqubecloud

Copy link
Copy Markdown

@github-actions github-actions Bot added documentation Improvements or additions to documentation skill labels Jul 30, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@CybotTM
CybotTM merged commit 1824a8a into main Jul 31, 2026
20 of 21 checks passed
@CybotTM
CybotTM deleted the feat/retro-self-referencing-const-checkpoint branch July 31, 2026 05:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation skill

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants