Skip to content

fix(phpcs): stop the SpecTagSniff instructing the pattern gate-46 rejects - #71

Merged
rubenvdlinde merged 1 commit into
developmentfrom
fix/spec-tag-sniff-canonical-target
Aug 8, 2026
Merged

fix(phpcs): stop the SpecTagSniff instructing the pattern gate-46 rejects#71
rubenvdlinde merged 1 commit into
developmentfrom
fix/spec-tag-sniff-canonical-target

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Two tools in the same pipeline gave OPPOSITE instructions about where an
@spec tag should point, and following the one that runs FIRST manufactured
findings for the one that runs SECOND.

SpecTagSniff runs as a blocking PHP Quality (phpcs) job and told every
developer, in its file docblock and in its own warning text:

@spec openspec/changes/{change-name}/tasks.md#task-N

A change directory is temporary by definition — completing a change moves it
to openspec/changes/archive/<date>-<name>/, and renaming or dropping one
removes the target outright. Every tag written to that instruction dangles
from that moment on, and gate-46 (spec-anchor-existence) reports it. The
developer who wrote the tag had followed this sniff's own advice.

Measured on portaliq: 100 unresolved gate-46 targets, and 260 of its 385 live
tags pointing into a change directory. The sniff ships identically in 20
ConductionNL repos, so grinding the tags without fixing the sniff regenerates
them at the rate changes are archived.

This changes the docblock example and BOTH warning messages to the canonical
form gate-46 and the project rule agree on:

@spec openspec/specs/{capability}/spec.md#requirement-{slug}

The method-level message previously carried no guidance at all, so a developer
reading it had only the class message to copy from; it now names the same
canonical shape.

Behaviour is unchanged: severity stays WARNING (verified via phpcs — an
untagged class and public method still report 0 errors / 2 warnings, and a
tagged file still reports nothing), and an openspec/changes/... target is
still accepted, since this sniff only checks that a tag is PRESENT.

No @spec tags are repointed here — this repo's existing tags are untouched.

Refs ConductionNL/.github#228

…ects

Two tools in the same pipeline gave OPPOSITE instructions about where an
`@spec` tag should point, and following the one that runs FIRST manufactured
findings for the one that runs SECOND.

`SpecTagSniff` runs as a blocking `PHP Quality (phpcs)` job and told every
developer, in its file docblock and in its own warning text:

    @SPEC openspec/changes/{change-name}/tasks.md#task-N

A change directory is temporary by definition — completing a change moves it
to `openspec/changes/archive/<date>-<name>/`, and renaming or dropping one
removes the target outright. Every tag written to that instruction dangles
from that moment on, and gate-46 (spec-anchor-existence) reports it. The
developer who wrote the tag had followed this sniff's own advice.

Measured on portaliq: 100 unresolved gate-46 targets, and 260 of its 385 live
tags pointing into a change directory. The sniff ships identically in 20
ConductionNL repos, so grinding the tags without fixing the sniff regenerates
them at the rate changes are archived.

This changes the docblock example and BOTH warning messages to the canonical
form gate-46 and the project rule agree on:

    @SPEC openspec/specs/{capability}/spec.md#requirement-{slug}

The method-level message previously carried no guidance at all, so a developer
reading it had only the class message to copy from; it now names the same
canonical shape.

Behaviour is unchanged: severity stays WARNING (verified via phpcs — an
untagged class and public method still report 0 errors / 2 warnings, and a
tagged file still reports nothing), and an `openspec/changes/...` target is
still accepted, since this sniff only checks that a tag is PRESENT.

No `@spec` tags are repointed here — this repo's existing tags are untouched.

Refs ConductionNL/.github#228
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/launchpad @ 9fd250a

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 102/102
npm ✅ 548/548
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-08 14:03 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde

Copy link
Copy Markdown
Contributor Author

Merging with --admin over pre-existing red. Evidence, so this is auditable rather than asserted:

This PR changes exactly one filephpcs-custom-sniffs/CustomSniffs/Sniffs/Commenting/SpecTagSniff.php — and only a docblock and two warning-message string literals inside it. git status --porcelain on the branch shows that one path and nothing else.

That file is not in any failing job's scope. This repo's phpcs.xml declares <file>lib</file>, so phpcs never lints the sniff directory itself. Gate-46 and gate-16 scope lib + src. The changed file is in neither.

The sniff still works. Verified by running real phpcs with the modified sniff: an untagged class and public method report 0 errors / 2 warnings (severity unchanged — still WARNING, not ERROR), and a file whose class and method both carry @spec reports nothing. Both controls run, so the check is shown able to fail before its pass is trusted.

The failing checks are unrelated to this diff: Newman / Playwright / test:l10n / Security (composer) / hydra-gates coverage-enforcement. None reads a phpcs sniff. Quality Report is a pure aggregator of the others and is never independent debt.

Merging to development, which project rules authorise. Not touching beta or main.

@rubenvdlinde
rubenvdlinde merged commit 5749883 into development Aug 8, 2026
27 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/spec-tag-sniff-canonical-target branch August 14, 2026 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant