diff --git a/phpcs-custom-sniffs/CustomSniffs/Sniffs/Commenting/SpecTagSniff.php b/phpcs-custom-sniffs/CustomSniffs/Sniffs/Commenting/SpecTagSniff.php index ae6ad7ee..60e75383 100644 --- a/phpcs-custom-sniffs/CustomSniffs/Sniffs/Commenting/SpecTagSniff.php +++ b/phpcs-custom-sniffs/CustomSniffs/Sniffs/Commenting/SpecTagSniff.php @@ -3,10 +3,25 @@ * Warn when a PHP class or public method lacks an @spec PHPDoc tag. * * ConductionNL ADR-003 (Backend rules) mandates that every class and public - * method MUST have one or more @spec PHPDoc tags linking back to the OpenSpec - * change that caused the code to exist: + * method MUST have one or more @spec PHPDoc tags linking back to the + * requirement the code exists to satisfy: * - * @spec openspec/changes/{change-name}/tasks.md#task-N + * @spec openspec/specs/{capability}/spec.md#requirement-{slug} + * + * POINT AT THE CANONICAL SPEC, NOT AT A CHANGE DIRECTORY. + * + * This guidance used to read `openspec/changes/{change-name}/tasks.md#task-N`, + * and tags written to it dangle by construction: `openspec/changes//` is + * temporary — archiving moves it to `openspec/changes/archive/-/`, + * and renaming or dropping a change removes the target outright. Gate-46 + * (spec-anchor-existence) then reports the tag, and the developer who wrote it + * had followed this sniff's own instruction. Measured on portaliq 2026-08-08: + * 100 unresolved targets, with 260 of its 385 live tags pointing into a change + * directory. The cross-repo measurement is in ConductionNL/.github#228. + * + * An `openspec/changes/...` target is still ACCEPTED — this sniff only checks + * that a tag is PRESENT, and gate-46 resolves archived paths — but it is no + * longer what this sniff tells you to write. * * This sniff emits warnings (not errors) so that CI surfaces the gap without * blocking merges while teams backfill coverage. Tests files and magic @@ -130,7 +145,7 @@ private function processClass(File $phpcsFile, int $stackPtr): void return; } - $message = 'Class %s is missing @spec PHPDoc tag — link back to openspec/changes/{name}/tasks.md#task-N'; + $message = 'Class %s is missing @spec PHPDoc tag — link back to openspec/specs/{capability}/spec.md#requirement-{slug}, not a change dir'; $phpcsFile->addWarning($message, $stackPtr, 'MissingClassSpec', [$className]); }//end processClass() @@ -179,7 +194,7 @@ private function processFunction(File $phpcsFile, int $stackPtr): void return; } - $message = 'Public method %s::%s() is missing @spec PHPDoc tag'; + $message = 'Public method %s::%s() is missing @spec PHPDoc tag — link back to openspec/specs/{capability}/spec.md#requirement-{slug}'; $phpcsFile->addWarning($message, $stackPtr, 'MissingMethodSpec', [$className, $methodName]); }//end processFunction()