Appearance
date: 2026-06-04 tags: [mutation, pest, pcov, pest-mutate-ignore, conventions] status: graduated graduated_to: CLAUDE.md (Mutation Testing Policy)
Mutants on declaration lines are un-killable — pcov never marks them executed
Symptom — RemoveArrayItem/IncrementInteger/RemoveStringCast mutants on const RECENCY_DAYS = 30, $fillable, $hidden, $attributes, casts() returns, and #[MaxTokens(1024)] attributes survived as UNCOVERED even though their behaviour is asserted (e.g. a test pins newer_than:30d, another caps maxResults at 5, AgentConfigTest asserts MaxTokens via reflection).
Root cause — pcov records coverage for executed statements. Class-constant / property / PHP-attribute declarations are resolved at class-load, not executed as statements, so pcov never marks those lines covered → pest-mutate can't attribute any killing test to them → they can never be killed, regardless of how well the value is tested.
Fix — reasoned // @pest-mutate-ignore (own line directly above the statement; reason on the line above that) on the declaration. One annotation before a multi-line const/array suppresses every per-element mutant. Repo precedent: NotificationLog, User, PushSubscription. Examples this session: GmailEnricher NOISE/RECENCY_DAYS, every model $fillable, all agents' #[MaxTokens].
Guard — graduated into CLAUDE.md Mutation Testing Policy: when a mutant sits on a const/property/attribute declaration line, ignore-with-reason is correct (not a test gap) — don't contort production code to make it killable.
Correction (2026-06-13) — this entry's symptom listed "casts() returns" as un-killable; that's wrong for the casts() method (which this project uses). A method body executes at hydration, so its mutants ARE killable via a strict-type assertion. Only the $casts property form is un-killable. See 2026-06-13-casts-method-mutants-are-killable.md.