diff --git a/.github/projects/active/metrics-agent/phase-2-continuation-2026-09-04.md b/.github/projects/active/metrics-agent/phase-2-continuation-2026-09-04.md index 78d621680b..b616af0287 100644 --- a/.github/projects/active/metrics-agent/phase-2-continuation-2026-09-04.md +++ b/.github/projects/active/metrics-agent/phase-2-continuation-2026-09-04.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![actions-minute-savings-watch](https://github.com/lightspeedwp/.github/actions/workflows/actions-minute-savings-watch.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/actions-minute-savings-watch.yml) [![allocate-pr-issue-to-milestone](https://github.com/lightspeedwp/.github/actions/workflows/allocate-pr-issue-to-milestone.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/allocate-pr-issue-to-milestone.yml) [![awesome-github-site](https://github.com/lightspeedwp/.github/actions/workflows/awesome-github-site.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/awesome-github-site.yml) diff --git a/.github/reports/audits/2026-09-14-label-audit/change-requests/label-update-request.md b/.github/reports/audits/2026-09-14-label-audit/change-requests/label-update-request.md index 1ddeaee87b..0fd2e598ea 100644 --- a/.github/reports/audits/2026-09-14-label-audit/change-requests/label-update-request.md +++ b/.github/reports/audits/2026-09-14-label-audit/change-requests/label-update-request.md @@ -4,14 +4,14 @@ ## Chore Summary -Approve the mapping that Stage 2 (the `.github/labels.yml` configuration PR, T059) and later stages apply. It covers 471 source labels and ends with 66 distinct targets. The type family ends at exactly 25. +Approve the mapping that Stage 2 (the `.github/labels.yml` configuration PR, T059) and later stages apply. It covers 472 source labels and ends with 69 distinct targets. The type family ends at exactly 25. Nothing changes until @ashleyshaw records a dated decision on this issue. Each repository's deletion has its own later gate (the deletion gate issue, T049). ## Decisions needed 1. **Spec-listed rules (no judgement).** The FR-011 prefix renames, the 32 FR-012 merges, the FR-015 re-prefixes and the team-scope labels follow the spec as written. -2. **Proposed by this mapping (spec is silent).** The 48 merges and 9 gap entries below are judgement calls. Approve, or replace the target in a comment. +2. **Proposed by this mapping (spec is silent).** The 39 merges and 14 gap entries below are judgement calls. Approve, or replace the target in a comment. ## Linked Stories/Tasks @@ -56,7 +56,7 @@ Nothing changes until @ashleyshaw records a dated decision on this issue. Each r | `type/feature` | `type:feature` | 0 | FR-016 | Same name as type:feature apart from case or separator (1 public repository, 0 counted items (lower bound)). | | `type/refactor` | `type:refactor` | 0 | FR-016 | Same name as type:refactor apart from case or separator (1 public repository, 0 counted items (lower bound)). | -### merge (76) +### merge (80) | Source | Target | Items | Rule | Notes | | --- | --- | ---: | --- | --- | @@ -96,6 +96,9 @@ Nothing changes until @ashleyshaw records a dated decision on this issue. Each r | `type:build-ci` | `type:ci` | 1 | FR-014 | Proposed (not listed in FR-012): Linear-only duplicate; FR-019 renames the Build & CI type to CI. Needed so the type family ends at exactly 25. | | `type:code-refactor` | `type:refactor` | 3 | FR-014 | Proposed (not listed in FR-012): Linear-only duplicate; FR-019 renames the Code Refactor type to Refactor. Needed so the type family ends at exactly 25. | | `type:documentation` | `type:docs` | 1 | FR-014 | Proposed (not listed in FR-012): Linear-only duplicate of type:docs. Needed so the type family ends at exactly 25. | +| `bug` | `type:bug` | 2 | FR-012 | Earlier bare-label mapping (#2523) names type:bug; labels.yml allows only the canonical label families, so this Linear label is merged, not imported (2 Linear issues). | +| `epic` | `type:epic` | 2 | FR-012 | Earlier bare-label mapping (#2523) names type:epic; labels.yml allows only the canonical label families, so this Linear label is merged, not imported (2 Linear issues). | +| `security` | `type:security` | 11 | FR-012 | Earlier bare-label mapping (#2523) names type:security; labels.yml allows only the canonical label families, so this Linear label is merged, not imported (11 Linear issues). | | `a11y` | `type:a11y` | 0 | FR-016 | Earlier bare-label mapping (#2523) names type:a11y, which resolves to type:a11y (1 public repository, 0 counted items (lower bound)). | | `A11y` | `type:a11y` | 0 | FR-016 | Earlier bare-label mapping (#2523) names type:a11y, which resolves to type:a11y (1 public repository, 0 counted items (lower bound)). | | `accessibility` | `type:a11y` | 0 | FR-016 | Earlier bare-label mapping (#2523) names type:a11y, which resolves to type:a11y (1 public repository, 0 counted items (lower bound)). | @@ -128,6 +131,7 @@ Nothing changes until @ashleyshaw records a dated decision on this issue. Each r | `Performance` | `type:performance` | 0 | FR-016 | Earlier bare-label mapping (#2523) names type:performance, which resolves to type:performance (1 public repository, 0 counted items (lower bound)). | | `refactor` | `type:refactor` | 0 | FR-016 | Earlier bare-label mapping (#2523) names type:refactor, which resolves to type:refactor (2 public repositories, 0 counted items (lower bound)). | | `release` | `type:release` | 0 | FR-016 | Earlier bare-label mapping (#2523) names type:release, which resolves to type:release (1 public repository, 0 counted items (lower bound)). | +| `Security` | `type:security` | 0 | FR-016 | Same name as security apart from case or separator, which resolves to type:security (1 public repository, 0 counted items (lower bound)). | | `status: completed` | `status:done` | 0 | FR-016 | Same name as status:completed apart from case or separator, which resolves to status:done (1 public repository, 0 counted items (lower bound)). | | `Task` | `type:task` | 0 | FR-016 | Earlier bare-label mapping (#2523) names type:task, which resolves to type:task (1 public repository, 0 counted items (lower bound)). | | `test` | `type:test` | 0 | FR-016 | Earlier bare-label mapping (#2523) names type:test, which resolves to type:test (3 public repositories, 0 counted items (lower bound)). | @@ -165,61 +169,53 @@ Nothing changes until @ashleyshaw records a dated decision on this issue. Each r | `area:jobs` | retire | 2 | FR-012 | Project-specific; moved to a Linear team, not imported. | | `area:monorepo` | retire | 1 | FR-012 | Project-specific; moved to a Linear team, not imported. | -### import (49) +### import (41) | Source | Target | Items | Rule | Notes | | --- | --- | ---: | --- | --- | -| `area:builds` | retire | 424 | FR-012 | Requested in #3554. | -| `area:monitoring` | retire | 8 | FR-012 | Requested in #3554. | -| `area:observability` | retire | 3 | FR-012 | Requested in #3554. | -| `area:workflows` | retire | 12 | FR-012 | Requested in #3554. | -| `meta:needs-approval` | retire | 3 | FR-012, FR-021 | Requested in #3554. | -| `CI/CD` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `Hosting` | retire | 13 | FR-012 | Proposed: applied to 13 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `aiops:instructions` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `aiops:tools` | retire | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `area:api` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:auth` | retire | 6 | FR-012 | Proposed: applied to 6 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:backend` | retire | 24 | FR-012 | Proposed: applied to 24 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:changelog` | retire | 7 | FR-012 | Proposed: applied to 7 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:communication` | retire | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:db` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:extension` | retire | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:frontend` | retire | 22 | FR-012 | Proposed: applied to 22 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:hosting` | retire | 6 | FR-012 | Proposed: applied to 6 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:labels` | retire | 56 | FR-012 | Proposed: applied to 56 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3757. | -| `area:mcp` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:migration` | retire | 7 | FR-012 | Proposed: applied to 7 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:projects` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:reports` | retire | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:specification` | retire | 40 | FR-012 | Proposed: applied to 40 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:templates` | retire | 11 | FR-012 | Proposed: applied to 11 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:website` | retire | 106 | FR-012 | Proposed: applied to 106 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `bug` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834. | -| `ci-runner-audit-2026-07-20` | retire | 13 | FR-012 | Proposed: applied to 13 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `comp:query-loop` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `comp:readme-mermaid` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `epic` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `harvest-parity` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `master-ci-red` | retire | 8 | FR-012 | Proposed: applied to 8 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834. | -| `meta:aiops` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. | -| `meta:audit` | retire | 42 | FR-012 | Proposed: applied to 42 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:dependabot-security` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:enhancement` | retire | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:incident-report` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:infrastructure-blocker` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:needs-audit` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. | -| `meta:needs-triage` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. | -| `meta:refactor-rules` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:release-plan` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:tech-debt` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:tracking` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `security` | retire | 11 | FR-012 | Proposed: applied to 11 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834. | -| `status:needs-analysis` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `status:needs-cleanup` | retire | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `status:needs-template-fix` | retire | 207 | FR-012 | Proposed: applied to 207 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | - -### retire (57) +| `area:builds` | new label | 424 | FR-012 | Requested in #3554. Colour `BFD4F2`; description "Build configuration, tooling, packaging, and artefact generation; use `area:ci` for CI pipeline execution and checks.". | +| `area:monitoring` | new label | 8 | FR-012 | Requested in #3554. Colour `006B75`; description "Operational checks, health monitoring, alerts, and failure detection; use `area:observability` for diagnostic telemetry and dashboards.". | +| `area:observability` | new label | 3 | FR-012 | Requested in #3554. Colour `006B75`; description "Logs, metrics, traces, and dashboards used to understand and diagnose system behaviour; use `area:monitoring` for checks and alerts.". | +| `area:workflows` | new label | 12 | FR-012 | Requested in #3554. Colour `0F448A`; description "Cross-cutting automated or operational workflow design and orchestration; use `area:automation` for scripts and automation implementation.". | +| `meta:needs-approval` | new label | 3 | FR-012, FR-021 | Requested in #3554. Colour `57606A`; description "Explicit decision or sign-off required before the specified work proceeds; remove once the decision and approver are recorded.". | +| `aiops:instructions` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. Colour `0052CC`; description "AI instruction docs". | +| `aiops:tools` | new label | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. Colour `BFD4F2`; description "Tool/plugin manifests". | +| `area:api` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Application programming interface work". | +| `area:auth` | new label | 6 | FR-012 | Proposed: applied to 6 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Authentication and authorisation work". | +| `area:backend` | new label | 24 | FR-012 | Proposed: applied to 24 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Backend application work". | +| `area:changelog` | new label | 7 | FR-012 | Proposed: applied to 7 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Changelog management". | +| `area:communication` | new label | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Communication and notifications". | +| `area:db` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Database work". | +| `area:extension` | new label | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Extension development and maintenance". | +| `area:frontend` | new label | 22 | FR-012 | Proposed: applied to 22 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Frontend application work". | +| `area:hosting` | new label | 6 | FR-012 | Proposed: applied to 6 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Hosting configuration and operations". | +| `area:labels` | new label | 56 | FR-012 | Requested in #3757: colour and description as in the request, because the colour strategy has no rule for this label (FR-012, R16). Applied to 56 Linear issues; the Linear label is updated to match. Colour `EDEDED`; description "Label governance and routing". | +| `area:mcp` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Model Context Protocol integrations". | +| `area:migration` | new label | 7 | FR-012 | Proposed: applied to 7 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Data, content, or system migration work". | +| `area:projects` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Project planning and management". | +| `area:reports` | new label | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Creating, presenting, or maintaining reports". | +| `area:specification` | new label | 40 | FR-012 | Proposed: applied to 40 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Technical specifications and requirements". | +| `area:templates` | new label | 11 | FR-012 | Proposed: applied to 11 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Reusable project and content templates". | +| `area:website` | new label | 106 | FR-012 | Proposed: applied to 106 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Website implementation and maintenance work". | +| `comp:query-loop` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Query Loop block". | +| `comp:readme-mermaid` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Mermaid diagrams in README files". | +| `meta:aiops` | new label | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. Colour `57606A`; description "Imported from Linear (1 issues); description to be written at approval.". | +| `meta:audit` | new label | 42 | FR-012 | Proposed: applied to 42 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Housekeeping metadata for audit work and findings". | +| `meta:dependabot-security` | new label | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Dependabot update appears security-related and eligible for guarded automation". | +| `meta:enhancement` | new label | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Housekeeping metadata for proposed enhancements". | +| `meta:incident-report` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Incident report tracking". | +| `meta:infrastructure-blocker` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Infrastructure dependency is blocking progress". | +| `meta:needs-audit` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. Colour `57606A`; description "Imported from Linear (2 issues); description to be written at approval.". | +| `meta:needs-triage` | new label | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. Colour `57606A`; description "Imported from Linear (1 issues); description to be written at approval.". | +| `meta:refactor-rules` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Rules for refactoring work". | +| `meta:release-plan` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Release planning and coordination". | +| `meta:tech-debt` | new label | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Technical debt tracking". | +| `meta:tracking` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Work requiring ongoing tracking and follow-up". | +| `status:needs-analysis` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `BFD4F2`; description "Analysis required before proceeding". | +| `status:needs-cleanup` | new label | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `BFD4F2`; description "Requires cleanup before proceeding". | +| `status:needs-template-fix` | new label | 207 | FR-012 | Proposed: applied to 207 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `BFD4F2`; description "Issue template requires correction". | + +### retire (62) | Source | Target | Items | Rule | Notes | | --- | --- | ---: | --- | --- | @@ -228,6 +224,8 @@ Nothing changes until @ashleyshaw records a dated decision on this issue. Each r | `openspec:status` | retire | 0 | FR-011 | Used in files but not defined in labels.yml. Proposed retirement: a namespace prefix used in examples (openspec:status/production), not a label. | | `openspec:tracking` | retire | 0 | FR-011 | Used in files but not defined in labels.yml. Proposed retirement: no spec status label matches tracking. | | `openspec:unknown` | retire | 0 | FR-011 | Used in files but not defined in labels.yml. Proposed retirement: a placeholder value, not a label. | +| `CI/CD` | retire | 1 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; the closest label is area:ci (1 Linear issue). | +| `Hosting` | retire | 13 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; the closest label is area:hosting (13 Linear issues). | | `agent-audit` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | | `aiops:agents` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | | `aiops:chat-modes` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | @@ -236,8 +234,11 @@ Nothing changes until @ashleyshaw records a dated decision on this issue. Each r | `aiops:prompts` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | | `area:linting` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | | `area:onboarding` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | +| `ci-runner-audit-2026-07-20` | retire | 13 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (13 Linear issues). | | `documentation` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | +| `harvest-parity` | retire | 2 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (2 Linear issues). | | `important` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | +| `master-ci-red` | retire | 8 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (8 Linear issues). | | `meta:analysis` | retire | 0 | FR-012 | Linear-only with zero issues; retire, not import. | | `migrate:area:automation` | retire | 162 | FR-012 | migrate:* labels are never imported; retired in Linear (kept as a per-repository migrate_to source in the FR-016 dry run). | | `migrate:area:ci` | retire | 109 | FR-012 | migrate:* labels are never imported; retired in Linear (kept as a per-repository migrate_to source in the FR-016 dry run). | @@ -294,6 +295,11 @@ Nothing changes until @ashleyshaw records a dated decision on this issue. Each r | `openspec:tracking` | retire | 0 | FR-011 | Used in files but not defined in labels.yml. Proposed retirement: no spec status label matches tracking. | | `openspec:unknown` | retire | 0 | FR-011 | Used in files but not defined in labels.yml. Proposed retirement: a placeholder value, not a label. | | `spec:001` | `spec-id:001` | 0 | FR-011 | Spec numbers move to spec-id:NNN so spec:* holds only status labels. | +| `CI/CD` | retire | 1 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; the closest label is area:ci (1 Linear issue). | +| `Hosting` | retire | 13 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; the closest label is area:hosting (13 Linear issues). | +| `ci-runner-audit-2026-07-20` | retire | 13 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (13 Linear issues). | +| `harvest-parity` | retire | 2 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (2 Linear issues). | +| `master-ci-red` | retire | 8 | FR-012 | Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (8 Linear issues). | ## Proposed beyond the spec @@ -303,50 +309,41 @@ Nothing changes until @ashleyshaw records a dated decision on this issue. Each r | `type:build-ci` | `type:ci` | 1 | FR-014 | Proposed (not listed in FR-012): Linear-only duplicate; FR-019 renames the Build & CI type to CI. Needed so the type family ends at exactly 25. | | `type:code-refactor` | `type:refactor` | 3 | FR-014 | Proposed (not listed in FR-012): Linear-only duplicate; FR-019 renames the Code Refactor type to Refactor. Needed so the type family ends at exactly 25. | | `type:documentation` | `type:docs` | 1 | FR-014 | Proposed (not listed in FR-012): Linear-only duplicate of type:docs. Needed so the type family ends at exactly 25. | -| `CI/CD` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `Hosting` | retire | 13 | FR-012 | Proposed: applied to 13 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `aiops:instructions` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `aiops:tools` | retire | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `area:api` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:auth` | retire | 6 | FR-012 | Proposed: applied to 6 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:backend` | retire | 24 | FR-012 | Proposed: applied to 24 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:changelog` | retire | 7 | FR-012 | Proposed: applied to 7 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:communication` | retire | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:db` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:extension` | retire | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:frontend` | retire | 22 | FR-012 | Proposed: applied to 22 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:hosting` | retire | 6 | FR-012 | Proposed: applied to 6 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:labels` | retire | 56 | FR-012 | Proposed: applied to 56 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3757. | -| `area:mcp` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:migration` | retire | 7 | FR-012 | Proposed: applied to 7 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:projects` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:reports` | retire | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:specification` | retire | 40 | FR-012 | Proposed: applied to 40 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:templates` | retire | 11 | FR-012 | Proposed: applied to 11 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `area:website` | retire | 106 | FR-012 | Proposed: applied to 106 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `bug` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834. | -| `ci-runner-audit-2026-07-20` | retire | 13 | FR-012 | Proposed: applied to 13 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `comp:query-loop` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `comp:readme-mermaid` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `epic` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `harvest-parity` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. | -| `master-ci-red` | retire | 8 | FR-012 | Proposed: applied to 8 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834. | -| `meta:aiops` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. | -| `meta:audit` | retire | 42 | FR-012 | Proposed: applied to 42 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:dependabot-security` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:enhancement` | retire | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:incident-report` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:infrastructure-blocker` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:needs-audit` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. | -| `meta:needs-triage` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. | -| `meta:refactor-rules` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:release-plan` | retire | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:tech-debt` | retire | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `meta:tracking` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `security` | retire | 11 | FR-012 | Proposed: applied to 11 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834. | -| `status:needs-analysis` | retire | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `status:needs-cleanup` | retire | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | -| `status:needs-template-fix` | retire | 207 | FR-012 | Proposed: applied to 207 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. | +| `aiops:instructions` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. Colour `0052CC`; description "AI instruction docs". | +| `aiops:tools` | new label | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834. Colour `BFD4F2`; description "Tool/plugin manifests". | +| `area:api` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Application programming interface work". | +| `area:auth` | new label | 6 | FR-012 | Proposed: applied to 6 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Authentication and authorisation work". | +| `area:backend` | new label | 24 | FR-012 | Proposed: applied to 24 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Backend application work". | +| `area:changelog` | new label | 7 | FR-012 | Proposed: applied to 7 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Changelog management". | +| `area:communication` | new label | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Communication and notifications". | +| `area:db` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Database work". | +| `area:extension` | new label | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Extension development and maintenance". | +| `area:frontend` | new label | 22 | FR-012 | Proposed: applied to 22 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Frontend application work". | +| `area:hosting` | new label | 6 | FR-012 | Proposed: applied to 6 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Hosting configuration and operations". | +| `area:mcp` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Model Context Protocol integrations". | +| `area:migration` | new label | 7 | FR-012 | Proposed: applied to 7 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Data, content, or system migration work". | +| `area:projects` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Project planning and management". | +| `area:reports` | new label | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Creating, presenting, or maintaining reports". | +| `area:specification` | new label | 40 | FR-012 | Proposed: applied to 40 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Technical specifications and requirements". | +| `area:templates` | new label | 11 | FR-012 | Proposed: applied to 11 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Reusable project and content templates". | +| `area:website` | new label | 106 | FR-012 | Proposed: applied to 106 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Website implementation and maintenance work". | +| `comp:query-loop` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Query Loop block". | +| `comp:readme-mermaid` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `C5DEF5`; description "Mermaid diagrams in README files". | +| `meta:aiops` | new label | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. Colour `57606A`; description "Imported from Linear (1 issues); description to be written at approval.". | +| `meta:audit` | new label | 42 | FR-012 | Proposed: applied to 42 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Housekeeping metadata for audit work and findings". | +| `meta:dependabot-security` | new label | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Dependabot update appears security-related and eligible for guarded automation". | +| `meta:enhancement` | new label | 4 | FR-012 | Proposed: applied to 4 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Housekeeping metadata for proposed enhancements". | +| `meta:incident-report` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Incident report tracking". | +| `meta:infrastructure-blocker` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Infrastructure dependency is blocking progress". | +| `meta:needs-audit` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. Colour `57606A`; description "Imported from Linear (2 issues); description to be written at approval.". | +| `meta:needs-triage` | new label | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is a placeholder. Check both at approval. Change request #3834. Colour `57606A`; description "Imported from Linear (1 issues); description to be written at approval.". | +| `meta:refactor-rules` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Rules for refactoring work". | +| `meta:release-plan` | new label | 2 | FR-012 | Proposed: applied to 2 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Release planning and coordination". | +| `meta:tech-debt` | new label | 1 | FR-012 | Proposed: applied to 1 Linear issue. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Technical debt tracking". | +| `meta:tracking` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `57606A`; description "Work requiring ongoing tracking and follow-up". | +| `status:needs-analysis` | new label | 3 | FR-012 | Proposed: applied to 3 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `BFD4F2`; description "Analysis required before proceeding". | +| `status:needs-cleanup` | new label | 5 | FR-012 | Proposed: applied to 5 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `BFD4F2`; description "Requires cleanup before proceeding". | +| `status:needs-template-fix` | new label | 207 | FR-012 | Proposed: applied to 207 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3834. Colour `BFD4F2`; description "Issue template requires correction". | ## Where the FR-015 labels live @@ -356,7 +353,7 @@ FR-015 calls its eight type labels "Linear-only". Checked on 2026-10-06, all eig Source: the weekly label drift check run of 2026-10-04 (283 repositories read, 59 skipped as archived or forks), kept in `evidence/github-label-coverage.json`. It lists 446 labels that exist in public repositories but not in `labels.yml`, and counts 57 more that exist only in private repositories and are not named here. -Every one of them now has a row (296 new rows for 446 names, the rest were already approved or mapped): 247 retire, 40 merge, 9 rename. A name that differs only in case or separator is renamed, the earlier bare-label mapping (#2523) is followed through the current renames, and every other label is retired with a stated reason. Run against the real tool, all 374 labels outside the approved set in `lightspeedwp/.github` have a row. +Every one of them now has a row (297 new rows for 446 names, the rest were already approved or mapped): 247 retire, 41 merge, 9 rename. A name that differs only in case or separator is renamed, the earlier bare-label mapping (#2523) is followed through the current renames, and every other label is retired with a stated reason. Run against the real tool, all 374 labels outside the approved set in `lightspeedwp/.github` have a row. 20 labels carry known items and have no target that the spec or the label documents define, so the tool lists them under `needs_decision` per repository, as FR-016 requires, until a target is chosen: `area:monorepo`, `agent-audit`, `migrate:openspec:status/implementation`, `migrate:openspec:status/planning`, `migrate:openspec:status/production`, `migrate:openspec:status/testing`, `migrate:type:compatibility`, `ag-p14`, `ag-phase`, `bug-fix`, `code-quality`, `error-handling`, `logging`, `migrate:type:enhancement`, `phase-1-critical`, `phase-2-medium`, `phase-3-polish`, `phase:1`, `reliability`, `reviewer`. The item counts are a lower bound, because the drift report caps counted rows. @@ -370,10 +367,11 @@ The 2026-10-06 drift run reports the 85 active public repositories only and summ ## Platform checks (Linear documentation, read 2026-10-06) -- Linear merges labels natively and rescopes them between workspace and team ([Issue labels](https://linear.app/docs/labels)), so each `merge` row is a supported operation. +- Linear lets duplicate labels be merged into one and rescopes labels between workspace and team ([Issue labels](https://linear.app/docs/labels)). The page does not say whether a merge works across a team label and a workspace label, so a `merge` row between the two is not confirmed as a native operation; see the team-scoped labels below. - Deleting a label removes it from every issue and cannot be undone; archiving keeps it on past issues and blocks new use. This matches the spec: Linear labels are retired (archived), never deleted. - Only one label from a label group can sit on an issue. A live read-only check on 2026-10-06 found no label groups in the workspace, so the type labels are flat and Linear does not enforce one type per issue. The "exactly one `type:*` per issue" rule must be enforced and verified by the consolidation tool (T064, T069), not assumed from Linear. -- The same check confirmed that `type: feature`, `type:build-ci` and `type:code-refactor` are team-scoped (GIT team, 1, 1 and 3 issues in the export) and `type:documentation` is workspace-scoped. Team and workspace labels can both be merged. Counts are from the Stage 1 export and have since moved, so Stage 5 re-reads live counts before it writes. +- The same check confirmed that `type: feature`, `type:build-ci` and `type:code-refactor` are team-scoped (GIT team, 1, 1 and 3 issues in the export) and `type:documentation` is workspace-scoped. Counts are from the Stage 1 export and have since moved, so Stage 5 re-reads live counts before it writes. +- Some labels in a `merge` row are team-scoped, so the merge target and source can sit in different scopes. `security` (merged into `type:security`, 11 issues) is three team labels, in the GIT, INF and LS teams (0, 4 and 7 issues in the export). Stage 5 relabels issue by issue by label ID and scope (T069a), which does not depend on a native merge across scopes. A native merge is used only if a test on a throwaway pair of labels shows it works. Converting the team labels to a workspace label is not used, because it would keep an unprefixed `security` label. - The GitHub issue sync is bidirectional and includes labels ([GitHub Issues Sync](https://linear.app/changelog/2023-12-14-github-issues-sync)). That is why the spec turns the sync off from Stage 3 to Stage 5 (T071, T083). - Issue label management can be limited to team owners ([Teams](https://linear.app/docs/teams)), which is how T071 restricts label creation. diff --git a/.github/reports/audits/2026-09-14-label-audit/evidence/linear-labels.json b/.github/reports/audits/2026-09-14-label-audit/evidence/linear-labels.json index 8cb805141a..8f91716ea3 100644 --- a/.github/reports/audits/2026-09-14-label-audit/evidence/linear-labels.json +++ b/.github/reports/audits/2026-09-14-label-audit/evidence/linear-labels.json @@ -4350,33 +4350,31 @@ }, { "concept_label": null, - "notes": "Proposed: applied to 1 Linear issue. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834.", - "change_request": 3834, + "notes": "Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; the closest label is area:ci (1 Linear issue).", + "change_request": null, "source": "CI/CD", "systems": [ "linear" ], - "action": "import", + "action": "retire", "target": null, "issue_count": 1, "requirement": "FR-012", - "color": "10B981", - "description": "Continuous integration and deployment infrastructure" + "gap": true }, { "concept_label": null, - "notes": "Proposed: applied to 13 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834.", - "change_request": 3834, + "notes": "Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; the closest label is area:hosting (13 Linear issues).", + "change_request": null, "source": "Hosting", "systems": [ "linear" ], - "action": "import", + "action": "retire", "target": null, "issue_count": 13, "requirement": "FR-012", - "color": "F59E0B", - "description": "Hosting environment, servers, and infrastructure" + "gap": true }, { "concept_label": null, @@ -4627,7 +4625,7 @@ }, { "concept_label": null, - "notes": "Proposed: applied to 56 Linear issues. Colour is the family default; description is Linear's own. Check both at approval. Change request #3757.", + "notes": "Requested in #3757: colour and description as in the request, because the colour strategy has no rule for this label (FR-012, R16). Applied to 56 Linear issues; the Linear label is updated to match.", "change_request": 3757, "source": "area:labels", "systems": [ @@ -4638,8 +4636,8 @@ "target": null, "issue_count": 56, "requirement": "FR-012", - "color": "C5DEF5", - "description": "Label taxonomy and governance" + "color": "EDEDED", + "description": "Label governance and routing" }, { "concept_label": null, @@ -4779,34 +4777,31 @@ }, { "concept_label": null, - "notes": "Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834.", - "change_request": 3834, + "notes": "Earlier bare-label mapping (#2523) names type:bug; labels.yml allows only the canonical label families, so this Linear label is merged, not imported (2 Linear issues).", + "change_request": null, "source": "bug", "systems": [ "github", "linear" ], - "action": "import", - "target": null, + "action": "merge", + "target": "type:bug", "issue_count": 2, - "requirement": "FR-012", - "color": "EDEDED", - "description": "Imported from Linear (2 issues); description to be written at approval." + "requirement": "FR-012" }, { "concept_label": null, - "notes": "Proposed: applied to 13 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834.", - "change_request": 3834, + "notes": "Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (13 Linear issues).", + "change_request": null, "source": "ci-runner-audit-2026-07-20", "systems": [ "linear" ], - "action": "import", + "action": "retire", "target": null, "issue_count": 13, "requirement": "FR-012", - "color": "B60205", - "description": "Self-hosted CI runner security audit, 2026-07-20" + "gap": true }, { "concept_label": null, @@ -4855,34 +4850,31 @@ }, { "concept_label": null, - "notes": "Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834.", - "change_request": 3834, + "notes": "Earlier bare-label mapping (#2523) names type:epic; labels.yml allows only the canonical label families, so this Linear label is merged, not imported (2 Linear issues).", + "change_request": null, "source": "epic", "systems": [ "github", "linear" ], - "action": "import", - "target": null, + "action": "merge", + "target": "type:epic", "issue_count": 2, - "requirement": "FR-012", - "color": "3FB950", - "description": "Large multi-scope initiative" + "requirement": "FR-012" }, { "concept_label": null, - "notes": "Proposed: applied to 2 Linear issues. Colour is the Linear label's own; description is Linear's own. Check both at approval. Change request #3834.", - "change_request": 3834, + "notes": "Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (2 Linear issues).", + "change_request": null, "source": "harvest-parity", "systems": [ "linear" ], - "action": "import", + "action": "retire", "target": null, "issue_count": 2, "requirement": "FR-012", - "color": "0E8A16", - "description": "Closing a gap against Harvest before the subscription ends" + "gap": true }, { "concept_label": null, @@ -4900,18 +4892,17 @@ }, { "concept_label": null, - "notes": "Proposed: applied to 8 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834.", - "change_request": 3834, + "notes": "Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; no approved label matches it (8 Linear issues).", + "change_request": null, "source": "master-ci-red", "systems": [ "linear" ], - "action": "import", + "action": "retire", "target": null, "issue_count": 8, "requirement": "FR-012", - "color": "EDEDED", - "description": "Imported from Linear (8 issues); description to be written at approval." + "gap": true }, { "concept_label": null, @@ -5569,19 +5560,17 @@ }, { "concept_label": null, - "notes": "Proposed: applied to 11 Linear issues. Colour is the Linear label's own; description is a placeholder. Check both at approval. Change request #3834.", - "change_request": 3834, + "notes": "Earlier bare-label mapping (#2523) names type:security; labels.yml allows only the canonical label families, so this Linear label is merged, not imported (11 Linear issues).", + "change_request": null, "source": "security", "systems": [ "github", "linear" ], - "action": "import", - "target": null, + "action": "merge", + "target": "type:security", "issue_count": 11, - "requirement": "FR-012", - "color": "EDEDED", - "description": "Imported from Linear (11 issues); description to be written at approval." + "requirement": "FR-012" }, { "concept_label": null, @@ -7854,6 +7843,19 @@ "action": "retire", "target": null }, + { + "concept_label": null, + "notes": "Same name as security apart from case or separator, which resolves to type:security (1 public repository, 0 counted items (lower bound)).", + "change_request": null, + "source": "Security", + "systems": [ + "github" + ], + "issue_count": 0, + "requirement": "FR-016", + "action": "merge", + "target": "type:security" + }, { "concept_label": null, "notes": "Proposed retirement: no counterpart in the proposed label set (1 public repository, 0 counted items (lower bound)). Items found at run time are listed under needs_decision until a target is chosen.", diff --git a/.github/specs/003-changelog-quality-audit/contracts/metrics-api.contract.md b/.github/specs/003-changelog-quality-audit/contracts/metrics-api.contract.md index 0fd3ceb197..87cf9031fb 100644 --- a/.github/specs/003-changelog-quality-audit/contracts/metrics-api.contract.md +++ b/.github/specs/003-changelog-quality-audit/contracts/metrics-api.contract.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/003-changelog-quality-audit/contracts/validation-rule.contract.md b/.github/specs/003-changelog-quality-audit/contracts/validation-rule.contract.md index d41a66d2b7..a084239292 100644 --- a/.github/specs/003-changelog-quality-audit/contracts/validation-rule.contract.md +++ b/.github/specs/003-changelog-quality-audit/contracts/validation-rule.contract.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/003-changelog-quality-audit/data-model.md b/.github/specs/003-changelog-quality-audit/data-model.md index b37e5cb9b3..d2bf2d2e37 100644 --- a/.github/specs/003-changelog-quality-audit/data-model.md +++ b/.github/specs/003-changelog-quality-audit/data-model.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/003-changelog-quality-audit/plan.md b/.github/specs/003-changelog-quality-audit/plan.md index 827cb69be6..0d5c96d332 100644 --- a/.github/specs/003-changelog-quality-audit/plan.md +++ b/.github/specs/003-changelog-quality-audit/plan.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/003-changelog-quality-audit/quickstart.md b/.github/specs/003-changelog-quality-audit/quickstart.md index 7e8f56d084..a624aec83e 100644 --- a/.github/specs/003-changelog-quality-audit/quickstart.md +++ b/.github/specs/003-changelog-quality-audit/quickstart.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/003-changelog-quality-audit/research.md b/.github/specs/003-changelog-quality-audit/research.md index c2a041702f..83dcc9172d 100644 --- a/.github/specs/003-changelog-quality-audit/research.md +++ b/.github/specs/003-changelog-quality-audit/research.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/005-requirements-quality-checklist/checklists/requirements.md b/.github/specs/005-requirements-quality-checklist/checklists/requirements.md index a2f624f7f8..4358fd3fcf 100644 --- a/.github/specs/005-requirements-quality-checklist/checklists/requirements.md +++ b/.github/specs/005-requirements-quality-checklist/checklists/requirements.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/005-requirements-quality-checklist/contracts/checklist-interface.contract.md b/.github/specs/005-requirements-quality-checklist/contracts/checklist-interface.contract.md index 517dbb8daa..cf1a498db5 100644 --- a/.github/specs/005-requirements-quality-checklist/contracts/checklist-interface.contract.md +++ b/.github/specs/005-requirements-quality-checklist/contracts/checklist-interface.contract.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/005-requirements-quality-checklist/data-model.md b/.github/specs/005-requirements-quality-checklist/data-model.md index a26f4f6b03..94f7a5da2b 100644 --- a/.github/specs/005-requirements-quality-checklist/data-model.md +++ b/.github/specs/005-requirements-quality-checklist/data-model.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/005-requirements-quality-checklist/plan.md b/.github/specs/005-requirements-quality-checklist/plan.md index d6f78d822b..08d0facfd7 100644 --- a/.github/specs/005-requirements-quality-checklist/plan.md +++ b/.github/specs/005-requirements-quality-checklist/plan.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/005-requirements-quality-checklist/quickstart.md b/.github/specs/005-requirements-quality-checklist/quickstart.md index 8878b0d17f..472f587a6d 100644 --- a/.github/specs/005-requirements-quality-checklist/quickstart.md +++ b/.github/specs/005-requirements-quality-checklist/quickstart.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/005-requirements-quality-checklist/research.md b/.github/specs/005-requirements-quality-checklist/research.md index 775136c8f5..7eb911f553 100644 --- a/.github/specs/005-requirements-quality-checklist/research.md +++ b/.github/specs/005-requirements-quality-checklist/research.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) [![documentation](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/documentation.yml) diff --git a/.github/specs/008-label-audit-consolidation/checklists/requirements.md b/.github/specs/008-label-audit-consolidation/checklists/requirements.md index 002f8dac79..9e03783a74 100644 --- a/.github/specs/008-label-audit-consolidation/checklists/requirements.md +++ b/.github/specs/008-label-audit-consolidation/checklists/requirements.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/.github/specs/008-label-audit-consolidation/contracts/audit-report-schema.md b/.github/specs/008-label-audit-consolidation/contracts/audit-report-schema.md index f18b0ee661..61a878ab99 100644 --- a/.github/specs/008-label-audit-consolidation/contracts/audit-report-schema.md +++ b/.github/specs/008-label-audit-consolidation/contracts/audit-report-schema.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/.github/specs/008-label-audit-consolidation/contracts/label-inventory-schema.md b/.github/specs/008-label-audit-consolidation/contracts/label-inventory-schema.md index 254a350f23..ef251393df 100644 --- a/.github/specs/008-label-audit-consolidation/contracts/label-inventory-schema.md +++ b/.github/specs/008-label-audit-consolidation/contracts/label-inventory-schema.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/.github/specs/008-label-audit-consolidation/contracts/label-mapping-schema.md b/.github/specs/008-label-audit-consolidation/contracts/label-mapping-schema.md index 55237ae65b..4c59eda19d 100644 --- a/.github/specs/008-label-audit-consolidation/contracts/label-mapping-schema.md +++ b/.github/specs/008-label-audit-consolidation/contracts/label-mapping-schema.md @@ -80,6 +80,8 @@ Defines `evidence/linear-labels.json` and the mapping table attached to the `[LA 7. No mapping merges `area:observability` into `area:monitoring` (both are imported), and `area:agents`, `area:instructions` and `area:prompts` map to their `aiops:*` labels. 8. Every non-canonical `openspec:` name found in files has an entry with `gap: true`, mapped to one of the 9 `spec:*` labels or retired (FR-011). 9. No `spec:*` target is a spec number; spec numbers use `spec-id:NNN`. +10. Every `import` cites, in `change_request`, the issue number of the request that approves it (constitution Principle II). +11. Every `import` uses a canonical label family, because `validate-labeling-configs.cjs` rejects any other name in `labels.yml`. The families are the ones in `scripts/validation/lib/label-families.cjs`, which that validator and the mapping both read: the families `labels.yml` carries today plus `aiops:`, `spec:` and `spec-id:`, which the Stage 2 change introduces (FR-011). A Linear label outside them, such as an unprefixed name or `other:example`, is handled in this order: with no issues it is retired as FR-012 says for any unused Linear-only label (no gap entry); otherwise it is merged where the earlier bare-label mapping (#2523) names a target; otherwise it is recorded as a `gap: true` retire entry for a decision. *Have questions? Ping us on GitHub! 🐙 Made with 💚 by LightSpeedWP* [Contact](https://lightspeedwp.agency/contact) diff --git a/.github/specs/008-label-audit-consolidation/data-model.md b/.github/specs/008-label-audit-consolidation/data-model.md index 33cd2f7ce6..818b6b853a 100644 --- a/.github/specs/008-label-audit-consolidation/data-model.md +++ b/.github/specs/008-label-audit-consolidation/data-model.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/.github/specs/008-label-audit-consolidation/plan.md b/.github/specs/008-label-audit-consolidation/plan.md index 290a7cc269..ee00ec7f1b 100644 --- a/.github/specs/008-label-audit-consolidation/plan.md +++ b/.github/specs/008-label-audit-consolidation/plan.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/.github/specs/008-label-audit-consolidation/quickstart.md b/.github/specs/008-label-audit-consolidation/quickstart.md index b1485d15b2..0d82466e47 100644 --- a/.github/specs/008-label-audit-consolidation/quickstart.md +++ b/.github/specs/008-label-audit-consolidation/quickstart.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/.github/specs/008-label-audit-consolidation/research.md b/.github/specs/008-label-audit-consolidation/research.md index e8898cbec6..77a8b692c3 100644 --- a/.github/specs/008-label-audit-consolidation/research.md +++ b/.github/specs/008-label-audit-consolidation/research.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/.github/specs/008-label-audit-consolidation/spec.md b/.github/specs/008-label-audit-consolidation/spec.md index 6aa6b96f47..84fc2bf4a9 100644 --- a/.github/specs/008-label-audit-consolidation/spec.md +++ b/.github/specs/008-label-audit-consolidation/spec.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/.github/specs/008-label-audit-consolidation/tasks.md b/.github/specs/008-label-audit-consolidation/tasks.md index 568a9d877d..0fcd3eced0 100644 --- a/.github/specs/008-label-audit-consolidation/tasks.md +++ b/.github/specs/008-label-audit-consolidation/tasks.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-management](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-management.yml) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1af0eca4e9..d13f0c2d7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Label Churn Stopped** — The labeler no longer removes the default priority and review labels the labeling agent adds. ([PR #3840](https://github.com/lightspeedwp/.github/pull/3840)) - **One Type on Docs Bot Pull Requests** — The automated documentation regeneration and maintenance pull requests no longer get a second, non-canonical `type:documentation` label. ([PR #3839](https://github.com/lightspeedwp/.github/pull/3839)) - **Security Updates Unblocked** — The lockfile moves `smol-toml` to 1.9.0, and a new override moves `katex` to 0.19, which `mermaid` and its tools do not yet allow. ([PR #3850](https://github.com/lightspeedwp/.github/pull/3850)) +- **Encoded Badge Labels** — The documentation generator now encodes spaces in the shields.io badge labels it writes, so regenerated pages no longer carry broken badges. ([PR #3854](https://github.com/lightspeedwp/.github/pull/3854)) +- **Badge Check Catches Closed-Early Links** — The badge URL check now also finds labels cut short by a closing angle bracket, and 240 such badges in 24 pages are repaired. ([PR #3854](https://github.com/lightspeedwp/.github/pull/3854)) - **Phase Progression Follows Real Links** — A closing keyword in a code sample no longer moves an issue to another phase; only issues GitHub renders as links in the pull request body do. ([#3824](https://github.com/lightspeedwp/.github/issues/3824)) - **Changelog Validator Clears Undici and Busboy Alerts** — Its `@actions` parents move to core 2 and github 8, so the tree resolves undici 6.29.0 with no `@fastify/busboy` copy left. (#3806) - **Skill Instructions Match Their References** — Twelve skill files no longer offer status labels, options or gates that their own reference files do not define, so agents follow instructions that exist. (#3716) diff --git a/scripts/agents/branding.agent.js b/scripts/agents/branding.agent.js index d0000e1345..d2ea412277 100644 --- a/scripts/agents/branding.agent.js +++ b/scripts/agents/branding.agent.js @@ -302,11 +302,17 @@ function generateMetadataBadges(frontMatter) { * destination still terminates it, so the value must be encoded at generation * time rather than at render time. * + * shields.io also reads a single `-` as the separator between label, message and + * colour, and `_` as a space, so a literal hyphen is written `--` and a literal + * underscore `__` (a licence such as `CC-BY-4.0` would otherwise split into + * three fields). `encodeURIComponent` leaves both characters unchanged. Keep this + * in step with `encodeBadgeSegment` in includes/badges.js. + * * @param {string} segment Raw label or status text. * @returns {string} Segment safe to interpolate into a shields.io path. */ function encodeBadgeSegment(segment) { - return encodeURIComponent(segment).replace(/%3A/gi, ':'); + return encodeURIComponent(segment).replace(/-/g, '--').replace(/_/g, '__').replace(/%3A/gi, ':'); } /** @@ -419,4 +425,5 @@ export { updateReadmeBadges, updateBadgesInReadme, loadBadgeSchema, + encodeBadgeSegment, }; diff --git a/scripts/agents/includes/__tests__/badges-encoding.test.js b/scripts/agents/includes/__tests__/badges-encoding.test.js new file mode 100644 index 0000000000..5f7950fa10 --- /dev/null +++ b/scripts/agents/includes/__tests__/badges-encoding.test.js @@ -0,0 +1,97 @@ +/** + * Badge URL encoding in includes/badges.js: labels with spaces or colons must + * never reach the shields.io URL raw. + */ +const { resolveBadge, encodeBadgeSegment } = require('../badges.js'); + +const defs = { + workflow: { + docs: { label: 'Docs Validation' }, + colon: { label: 'Badges: Documentation Update', success_text: 'All Good' }, + plain: { label: 'Checks' }, + }, + meta: { license: { label: 'License' } }, +}; + +describe('encodeBadgeSegment', () => { + it('encodes spaces and keeps colons readable', () => { + expect(encodeBadgeSegment('Docs Validation')).toBe('Docs%20Validation'); + expect(encodeBadgeSegment('Badges: Documentation Update')).toBe( + 'Badges:%20Documentation%20Update' + ); + }); + + it('leaves a plain word unchanged', () => { + expect(encodeBadgeSegment('Checks')).toBe('Checks'); + }); + + // shields.io reads a single "-" as the label/message/colour separator and "_" as + // a space, so literal ones are doubled. + it('doubles a literal hyphen', () => { + expect(encodeBadgeSegment('pre-release')).toBe('pre--release'); + expect(encodeBadgeSegment('CC-BY-4.0')).toBe('CC--BY--4.0'); + }); + + it('doubles a literal underscore', () => { + expect(encodeBadgeSegment('snake_case')).toBe('snake__case'); + }); + + it('handles spaces, hyphens, underscores and colons together', () => { + expect(encodeBadgeSegment('Build: pre-release_1 ok')).toBe('Build:%20pre--release__1%20ok'); + }); +}); + +describe('both badge generators encode the same way', () => { + const branding = require('../../branding.agent.js'); + const samples = [ + 'Docs Validation', + 'Badges: Health Check', + 'pre-release', + 'CC-BY-4.0', + 'snake_case', + 'Checks', + ]; + + it.each(samples)('agrees on %s', (sample) => { + expect(branding.encodeBadgeSegment(sample)).toBe(encodeBadgeSegment(sample)); + }); +}); + +describe('resolveBadge', () => { + it('encodes a workflow label that contains a space', () => { + expect(resolveBadge('workflow.docs', defs, {})).toBe( + '![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg)' + ); + }); + + it('encodes the colon label and a custom status text', () => { + expect(resolveBadge('workflow.colon', defs, {})).toBe( + '![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-All%20Good-success.svg)' + ); + }); + + it('leaves a plain label alone', () => { + expect(resolveBadge('workflow.plain', defs, {})).toBe( + '![Checks](https://img.shields.io/badge/Checks-OK-success.svg)' + ); + }); + + it('encodes a licence value', () => { + expect(resolveBadge('meta.license', defs, { license: 'cc by 4.0' })).toBe( + '![License](https://img.shields.io/badge/license-CC%20BY%204.0-blue.svg)' + ); + }); + + it('keeps a hyphenated licence in one field', () => { + expect(resolveBadge('meta.license', defs, { license: 'cc-by-4.0' })).toBe( + '![License](https://img.shields.io/badge/license-CC--BY--4.0-blue.svg)' + ); + }); + + it('never puts a raw space in the badge URL', () => { + for (const ref of ['workflow.docs', 'workflow.colon', 'workflow.plain']) { + const url = /\((https:[^)]*)\)/.exec(resolveBadge(ref, defs, {}))[1]; + expect(url).not.toMatch(/\s/); + } + }); +}); diff --git a/scripts/agents/includes/badges.js b/scripts/agents/includes/badges.js index 02c3134bed..09435231f3 100644 --- a/scripts/agents/includes/badges.js +++ b/scripts/agents/includes/badges.js @@ -108,6 +108,30 @@ function generateMetadataBadges(frontMatter) { return badges; } +/** + * Percent-encode a badge URL path segment. + * + * shields.io labels legitimately contain spaces and colons ("Badges: + * Documentation Update"). Interpolated raw, the URL ends at the first space, so + * shields.io receives no label and the badge renders malformed. The value must + * be encoded at generation time: a bare space inside a `<...>` link destination + * still terminates it. Same rule as `encodeBadgeSegment` in branding.agent.js. + * + * shields.io also reads a single `-` as the separator between label, message and + * colour, and `_` as a space, so a literal hyphen is written `--` and a literal + * underscore `__` (a licence such as `CC-BY-4.0` would otherwise split into + * three fields). `encodeURIComponent` leaves both characters unchanged. + * + * @param {string} segment Raw label or status text. + * @returns {string} Segment safe to interpolate into a shields.io path. + */ +function encodeBadgeSegment(segment) { + return encodeURIComponent(segment) + .replace(/-/g, "--") + .replace(/_/g, "__") + .replace(/%3A/gi, ":"); +} + /** * Resolve a badge reference from schema */ @@ -131,7 +155,7 @@ function resolveBadge(badgeRef, badgeDefs, frontMatter) { if (badgeRef.startsWith("workflow.")) { const label = current.label || badgeRef; const successText = current.success_text || "OK"; - return `![${label}](https://img.shields.io/badge/${label}-${successText}-success.svg)`; + return `![${label}](https://img.shields.io/badge/${encodeBadgeSegment(label)}-${encodeBadgeSegment(successText)}-success.svg)`; } // Handle metadata badges @@ -141,7 +165,7 @@ function resolveBadge(badgeRef, badgeDefs, frontMatter) { frontMatter.license ) { const license = frontMatter.license.toUpperCase(); - return `![License](https://img.shields.io/badge/license-${license}-blue.svg)`; + return `![License](https://img.shields.io/badge/license-${encodeBadgeSegment(license)}-blue.svg)`; } return null; @@ -224,4 +248,6 @@ export { updateReadmeBadges, updateBadgesInReadme, loadBadgeSchema, + resolveBadge, + encodeBadgeSegment, }; diff --git a/scripts/automation/__tests__/label-mapping.test.js b/scripts/automation/__tests__/label-mapping.test.js index b6d1c59822..261d279e7c 100644 --- a/scripts/automation/__tests__/label-mapping.test.js +++ b/scripts/automation/__tests__/label-mapping.test.js @@ -5,6 +5,11 @@ const fs = require('fs'); const path = require('path'); const yaml = require('js-yaml'); const { buildMappings, validateMappings, shouldWrite } = require('../label-mapping.cjs'); +const { + LABEL_PREFIXES, + STAGE_2_PREFIXES, + hasLabelPrefix, +} = require('../../validation/lib/label-families.cjs'); const root = path.resolve(__dirname, '../../..'); const audit = path.join(root, '.github/reports/audits/2026-09-14-label-audit'); @@ -118,7 +123,8 @@ describe('label mapping', () => { it('gives every import a change request, and area:labels cites #3757', () => { const imports = build().mappings.filter((m) => m.action === 'import'); - expect(imports).toHaveLength(49); + // 49 before the 8 unprefixed names (3 merged, 5 open decisions) left the import list. + expect(imports).toHaveLength(41); for (const entry of imports) expect(Number.isInteger(entry.change_request)).toBe(true); expect(imports.find((m) => m.source === 'area:labels').change_request).toBe(3757); expect(imports.find((m) => m.source === 'area:builds').change_request).toBe(3554); @@ -163,6 +169,122 @@ describe('label mapping', () => { expect(rows.get('area:monorepo')).toMatchObject({ action: 'team-scope' }); }); + it('takes area:labels colour and description from its own request, #3757 (FR-012, R16)', () => { + const row = build().mappings.find((m) => m.source === 'area:labels'); + expect(row).toMatchObject({ + action: 'import', + color: 'EDEDED', + description: 'Label governance and routing', + change_request: 3757, + }); + expect(row.notes).toContain('#3757'); + }); + + it('imports only labels in a canonical family, because labels.yml cannot carry any other (rule 11)', () => { + const imports = build().mappings.filter((m) => m.action === 'import'); + expect(imports.length).toBeGreaterThan(0); + for (const entry of imports) { + expect(hasLabelPrefix(entry.source, [...LABEL_PREFIXES, ...STAGE_2_PREFIXES])).toBe(true); + } + }); + + it('does not import a prefixed label from a family the validator would reject', () => { + // `other:` looks prefixed, but validate-labeling-configs rejects it, so importing it would + // fail the configuration PR just as an unprefixed name does. + const extra = { + id: 'test-other-example', + name: 'other:example', + scope: 'workspace', + group: null, + is_group: false, + color: '#ededed', + description: 'A label in no canonical family', + retired_at: null, + issue_count: 3, + }; + const { mappings } = buildMappings({ + yml, + linear: [...linearFile.sources.labels, extra], + openspecInFiles, + specNumberLabels: ['spec:001'], + githubLive, + githubOnly, + bare, + }); + const row = mappings.find((m) => m.source === 'other:example'); + expect(row).toMatchObject({ action: 'retire', target: null, gap: true }); + expect(row.notes).toMatch(/does not use a canonical label family/); + expect(mappings.some((m) => m.action === 'import' && m.source === 'other:example')).toBe(false); + }); + + it('uses the same family list as the label-config validator', () => { + const validator = fs.readFileSync( + path.join(root, 'scripts/validation/validate-labeling-configs.cjs'), + 'utf8' + ); + expect(validator).toContain("require('./lib/label-families.cjs')"); + // No second copy of the list may creep back into the validator. + expect(validator).not.toMatch(/'ai-ops:'/); + }); + + it('merges bug, epic and security by the earlier bare-label mapping (#2523)', () => { + const rows = new Map(build().mappings.map((m) => [m.source, m])); + for (const [source, target] of [ + ['bug', 'type:bug'], + ['epic', 'type:epic'], + ['security', 'type:security'], + ]) { + expect(rows.get(source)).toMatchObject({ action: 'merge', target }); + expect(rows.get(source).systems).toContain('linear'); + } + }); + + it('records the five unprefixed Linear-only labels as open decisions, not as imports', () => { + const rows = new Map(build().mappings.map((m) => [m.source, m])); + const open = [ + 'Hosting', + 'CI/CD', + 'master-ci-red', + 'ci-runner-audit-2026-07-20', + 'harvest-parity', + ]; + for (const source of open) { + expect(rows.get(source)).toMatchObject({ action: 'retire', target: null, gap: true }); + expect(rows.get(source).notes).toMatch(/not decided/); + } + // A suggestion is only a hint to the approver. + expect(rows.get('Hosting').notes).toContain('area:hosting'); + expect(rows.get('CI/CD').notes).toContain('area:ci'); + expect(rows.get('harvest-parity').notes).toContain('no approved label matches'); + }); + + it('reports an import outside the canonical families (rule 11)', () => { + const { mappings, proposedNames } = build(); + const broken = [ + ...mappings, + { + source: 'other:example', + systems: ['linear'], + action: 'import', + target: null, + issue_count: 3, + requirement: 'FR-012', + color: 'EDEDED', + description: 'x', + change_request: 3834, + notes: 'Proposed.', + }, + ]; + expect(validateMappings(broken, proposedNames, yml, openspecInFiles)).toContain( + 'rule 11: import other:example does not use a canonical label family' + ); + // An unprefixed name is rejected by the same rule. + const unprefixed = [{ ...broken[broken.length - 1], source: 'hosting-only' }]; + expect( + validateMappings([...mappings, ...unprefixed], proposedNames, yml, openspecInFiles) + ).toContain('rule 11: import hosting-only does not use a canonical label family'); + }); + it('reports an import that cites no change request', () => { const { mappings, proposedNames } = build(); const broken = mappings.map((m) => diff --git a/scripts/automation/label-mapping.cjs b/scripts/automation/label-mapping.cjs index bb2a486d72..19e5e97b1f 100644 --- a/scripts/automation/label-mapping.cjs +++ b/scripts/automation/label-mapping.cjs @@ -25,9 +25,21 @@ const fs = require('node:fs'); const path = require('node:path'); +const { + LABEL_PREFIXES, + STAGE_2_PREFIXES, + hasLabelPrefix, +} = require('../validation/lib/label-families.cjs'); const EVIDENCE = '.github/reports/audits/2026-09-14-label-audit/evidence'; +/** + * Families an import may use: the ones `labels.yml` carries today plus the ones the Stage 2 + * change introduces (FR-011). One list shared with `validate-labeling-configs.cjs`, so the + * mapping cannot import a label that validator would then reject. + */ +const IMPORT_PREFIXES = [...LABEL_PREFIXES, ...STAGE_2_PREFIXES]; + /** FR-012 approved merges, source -> target. */ const MERGES = { 'area:ci-cd': 'area:ci', @@ -144,6 +156,26 @@ const TEAM_SCOPE = ['area:xero', 'area:flow', 'area:jobs', 'area:monorepo']; const IMPORT_CHANGE_REQUEST = 3834; const OWN_CHANGE_REQUESTS = { 'area:labels': 3757 }; +/** + * Colour and description of an import that has its own request. FR-012 (research R16): + * where `docs/LABEL_COLOR_STRATEGY.md` has no rule for the family, the colour in the + * approved request stands, so these win over the family default and over Linear's + * own description. The Linear label is then updated to match `labels.yml`. + * #3757 asks for `area:labels` with the values the label already has on GitHub. + */ +const OWN_REQUEST_VALUES = { + 'area:labels': { color: 'EDEDED', description: 'Label governance and routing' }, +}; + +/** + * Closest approved label for an unprefixed Linear-only label, named only to help the + * decision. No rule or document defines these, so none is applied. + */ +const UNPREFIXED_SUGGESTIONS = { + Hosting: 'area:hosting', + 'CI/CD': 'area:ci', +}; + /** The five imports of #3554, with the colours and descriptions set in FR-012. */ const ISSUE_3554 = { 'area:builds': { @@ -628,6 +660,53 @@ function buildMappings({ }); continue; } + // labels.yml allows only the canonical families (validate-labeling-configs), so a Linear + // label outside them cannot be imported as it is. The earlier bare-label mapping (#2523) + // names a type label for some of them; the rest are open decisions, recorded as a gap. + if (!hasLabelPrefix(name, IMPORT_PREFIXES)) { + const bareTarget = bare[name.toLowerCase()]; + if (bareTarget && inYml.has(bareTarget)) { + add({ + source: name, + systems: where(name), + action: 'merge', + target: bareTarget, + issue_count: issueCount, + requirement: 'FR-012', + notes: `Earlier bare-label mapping (#2523) names ${bareTarget}; labels.yml allows only the canonical label families, so this Linear label is merged, not imported (${issueCount} Linear issue${issueCount === 1 ? '' : 's'}).`, + }); + } else { + const suggestion = UNPREFIXED_SUGGESTIONS[name]; + add({ + source: name, + systems: where(name), + action: 'retire', + target: null, + issue_count: issueCount, + requirement: 'FR-012', + gap: true, + notes: `Open decision: this Linear label does not use a canonical label family, and labels.yml cannot carry it as it is. Retirement is proposed, not decided; ${suggestion ? `the closest label is ${suggestion}` : 'no approved label matches it'} (${issueCount} Linear issue${issueCount === 1 ? '' : 's'}).`, + }); + } + continue; + } + const ownRequest = OWN_REQUEST_VALUES[name]; + if (ownRequest) { + const request = OWN_CHANGE_REQUESTS[name]; + add({ + source: name, + systems: where(name), + action: 'import', + target: null, + issue_count: issueCount, + requirement: 'FR-012', + color: ownRequest.color, + description: ownRequest.description, + change_request: request, + notes: `Requested in #${request}: colour and description as in the request, because the colour strategy has no rule for this label (FR-012, R16). Applied to ${issueCount} Linear issue${issueCount === 1 ? '' : 's'}; the Linear label is updated to match.`, + }); + continue; + } const family = familyOf(name); const familyDefault = FAMILY_STRATEGY_COLOUR[family] || familyColour(yml, family); const ownColour = hex(label.color); @@ -744,6 +823,11 @@ function validateMappings(mappings, proposedNames, yml, openspecInFiles = []) { if (!Number.isInteger(m.change_request)) problems.push(`rule 10: import ${m.source} cites no change request`); } + // 11. Every import uses a canonical label family: validate-labeling-configs rejects any other name in labels.yml. + for (const m of mappings.filter((x) => x.action === 'import')) { + if (!hasLabelPrefix(m.source, IMPORT_PREFIXES)) + problems.push(`rule 11: import ${m.source} does not use a canonical label family`); + } // Each source appears once. const seen = new Set(); for (const m of mappings) { diff --git a/scripts/validation/__tests__/label-families.test.js b/scripts/validation/__tests__/label-families.test.js new file mode 100644 index 0000000000..2edfd20bbf --- /dev/null +++ b/scripts/validation/__tests__/label-families.test.js @@ -0,0 +1,39 @@ +const { LABEL_PREFIXES, STAGE_2_PREFIXES, hasLabelPrefix } = require('../lib/label-families.cjs'); + +describe('label families', () => { + it('accepts a label in a family labels.yml carries today', () => { + for (const name of ['area:ci', 'type:bug', 'meta:needs-approval', 'status:needs-review']) { + expect(hasLabelPrefix(name)).toBe(true); + } + }); + + it('rejects an unprefixed name and a family outside the list', () => { + for (const name of ['bug', 'Hosting', 'CI/CD', 'other:example', 'areas:ci']) { + expect(hasLabelPrefix(name)).toBe(false); + } + }); + + it('does not match a family prefix that is only part of a longer family name', () => { + expect(hasLabelPrefix('areaX:thing')).toBe(false); + expect(hasLabelPrefix('area')).toBe(false); + }); + + it('keeps the Stage 2 families out of the default list until labels.yml carries them', () => { + for (const prefix of STAGE_2_PREFIXES) { + expect(LABEL_PREFIXES).not.toContain(prefix); + expect(hasLabelPrefix(`${prefix}example`)).toBe(false); + expect(hasLabelPrefix(`${prefix}example`, [...LABEL_PREFIXES, ...STAGE_2_PREFIXES])).toBe( + true + ); + } + }); + + it('gives every family a trailing colon, so a prefix cannot match half a word', () => { + for (const prefix of [...LABEL_PREFIXES, ...STAGE_2_PREFIXES]) expect(prefix).toMatch(/:$/); + }); + + it('is not fooled by a non-string name', () => { + expect(hasLabelPrefix(undefined)).toBe(false); + expect(hasLabelPrefix(null)).toBe(false); + }); +}); diff --git a/scripts/validation/__tests__/validate-badge-urls.test.js b/scripts/validation/__tests__/validate-badge-urls.test.js index 9cb7a4eb51..5abf4fea2f 100644 --- a/scripts/validation/__tests__/validate-badge-urls.test.js +++ b/scripts/validation/__tests__/validate-badge-urls.test.js @@ -165,6 +165,155 @@ describe('validate-badge-urls', () => { }); }); + describe('titles that contain parentheses', () => { + // CommonMark allows `(` and `)` inside a quoted title. Matching up to the first + // `)` split the title, so a valid badge was reported and `--fix` rewrote part of + // the title into the URL. + const bareTitle = '![X](https://img.shields.io/badge/X-OK-green.svg "Build (main)")'; + const angleTitle = '![X]( "Build (main)")'; + + it('does not report a valid bare badge whose title has parentheses', () => { + expect(findBrokenBadges(bareTitle)).toHaveLength(0); + expect(repairContent(bareTitle)).toBe(bareTitle); + }); + + it('does not report a valid angle-bracket badge whose title has parentheses', () => { + expect(findBrokenBadges(angleTitle)).toHaveLength(0); + expect(repairContent(angleTitle)).toBe(angleTitle); + }); + + it('repairs a broken bare badge and keeps a title with parentheses intact', () => { + const broken = '![X](https://img.shields.io/badge/Docs Validation-OK-success.svg "Tip (x)")'; + expect(repairContent(broken)).toBe( + '![X](https://img.shields.io/badge/Docs%20Validation-OK-success.svg "Tip (x)")' + ); + }); + + it('repairs a broken angle-bracket badge and keeps a title with parentheses intact', () => { + const broken = + '![X]( Validation-OK-success.svg "Tip (x)")'; + expect(repairContent(broken)).toBe( + '![X](https://img.shields.io/badge/Docs%20Validation-OK-success.svg "Tip (x)")' + ); + }); + + it('still reports and repairs the next badge on the same line', () => { + const line = `${angleTitle} ${BROKE_SPACES}`; + expect(findBrokenBadges(line)).toHaveLength(1); + expect(repairContent(line)).toBe( + `${angleTitle} ![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg)` + ); + }); + }); + + describe('parenthesised titles and apostrophes', () => { + // CommonMark also allows a title in parentheses. A quote is a title only after + // whitespace; elsewhere it is an ordinary character, so `Don't Stop` stays a label. + const parenBare = '![X](https://img.shields.io/badge/X-OK-green.svg (Build))'; + const parenAngle = '![X]( (Build))'; + + it('does not report a valid badge with a parenthesised title', () => { + for (const line of [parenBare, parenAngle]) { + expect(findBrokenBadges(line)).toHaveLength(0); + expect(repairContent(line)).toBe(line); + } + }); + + it('repairs a broken angle-bracket badge and keeps a parenthesised title', () => { + const broken = '![X]( Validation-OK-success.svg (Tip))'; + expect(repairContent(broken)).toBe( + '![X](https://img.shields.io/badge/Docs%20Validation-OK-success.svg (Tip))' + ); + }); + + it('still finds and repairs a broken badge whose label has an apostrophe', () => { + const broken = "![Don't](https://img.shields.io/badge/Don't Stop-OK-success.svg)"; + expect(findBrokenBadges(broken)).toHaveLength(1); + expect(repairContent(broken)).toBe( + "![Don't](https://img.shields.io/badge/Don't%20Stop-OK-success.svg)" + ); + }); + + it('keeps the apostrophe and a quoted title when both are present', () => { + const broken = '![X](https://img.shields.io/badge/Don\'t Stop-OK-success.svg "Tip")'; + expect(repairContent(broken)).toBe( + '![X](https://img.shields.io/badge/Don\'t%20Stop-OK-success.svg "Tip")' + ); + }); + + it('leaves an already-encoded badge with an apostrophe alone', () => { + const ok = "![Don't](https://img.shields.io/badge/Don't%20Stop-OK-success.svg)"; + expect(findBrokenBadges(ok)).toHaveLength(0); + expect(repairContent(ok)).toBe(ok); + }); + + it('does not encode spaces that sit before a title into the URL', () => { + const broken = '![X](https://img.shields.io/badge/Docs Validation-OK-success.svg "Tip")'; + expect(repairContent(broken)).toBe( + '![X](https://img.shields.io/badge/Docs%20Validation-OK-success.svg "Tip")' + ); + }); + }); + + describe('escaped delimiters in titles', () => { + // A backslash escapes the next character in a CommonMark title, so an escaped closing + // delimiter does not end it. + const quoted = String.raw`![X](https://img.shields.io/badge/X-OK-green.svg "Say \"hi\"")`; + const quotedAngle = String.raw`![X]( "Say \"hi\"")`; + const paren = String.raw`![X](https://img.shields.io/badge/X-OK-green.svg (Build \) ok))`; + const parenAngle = String.raw`![X]( (Build \) ok))`; + const single = String.raw`![X](https://img.shields.io/badge/X-OK-green.svg 'It\'s fine')`; + + it('does not report or change a valid badge whose title has an escaped delimiter', () => { + for (const line of [quoted, quotedAngle, paren, parenAngle, single]) { + expect(findBrokenBadges(line)).toHaveLength(0); + expect(repairContent(line)).toBe(line); + } + }); + + it('repairs a broken bare badge and keeps an escaped-quote title intact', () => { + const broken = String.raw`![X](https://img.shields.io/badge/Docs Validation-OK-success.svg "Say \"hi\"")`; + expect(repairContent(broken)).toBe( + String.raw`![X](https://img.shields.io/badge/Docs%20Validation-OK-success.svg "Say \"hi\"")` + ); + }); + + it('repairs a broken angle-bracket badge and keeps an escaped-parenthesis title intact', () => { + const broken = String.raw`![X]( Validation-OK-success.svg (Tip \) x))`; + expect(repairContent(broken)).toBe( + String.raw`![X](https://img.shields.io/badge/Docs%20Validation-OK-success.svg (Tip \) x))` + ); + }); + + it('stays fast on a title made of backslashes', () => { + const line = `![x](https://img.shields.io/badge/X "${'\\\\ '.repeat(20000)}`; + const started = Date.now(); + findBrokenBadges(line); + repairContent(line); + expect(Date.now() - started).toBeLessThan(1000); + }); + }); + + describe('pathological input', () => { + // A long run of spaces with no closing parenthesis made an earlier version of the + // title pattern backtrack quadratically (about 30 seconds for 200,000 characters). + const run = ' '.repeat(100000); + const inputs = { + 'an unclosed bare image': `![x](https://img.shields.io/badge/X${run}y`, + 'an unclosed angle-bracket image': `![x](${run}y`, + 'a closed image with a long space run': `![x](https://img.shields.io/badge/X${run}y)`, + 'many quote openers': `![x](https://img.shields.io/badge/X ${'" '.repeat(20000)}`, + 'many parenthesis openers': `![x](https://img.shields.io/badge/X ${'( '.repeat(20000)}`, + }; + + it.each(Object.entries(inputs))('handles %s quickly', (_name, line) => { + const started = Date.now(); + findBrokenBadges(line); + repairContent(line); + expect(Date.now() - started).toBeLessThan(1000); + }); + }); + describe('nested fences', () => { // A four-backtick example may contain a three-backtick block. Toggling on // every fence-like line ends the block early and rewrites badge examples @@ -180,6 +329,73 @@ describe('validate-badge-urls', () => { }); }); + describe('angle-bracket form', () => { + // As emitted by the README regeneration of #3803: the `>` closes the link + // before the label ends, leaving "Validation-OK-success.svg" as stray text. + const ANGLE = + '![Docs Validation]( Validation-OK-success.svg)'; + const ANGLE_COLON = + '![Badges: Health Check](: Health Check-OK-success.svg)'; + const ANGLE_MULTI = + '![Main Branch Guard]( Branch Guard-OK-success.svg)'; + + it('reports a badge whose `>` closes before the label ends', () => { + for (const line of [ANGLE, ANGLE_COLON, ANGLE_MULTI]) { + expect(findBrokenBadges(line)).toHaveLength(1); + } + }); + + it('repairs the label with a joining %20', () => { + expect(repairContent(ANGLE)).toBe( + '![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg)' + ); + expect(repairContent(ANGLE_MULTI)).toBe( + '![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg)' + ); + }); + + it('joins a colon label without inserting a stray %20 before the colon', () => { + expect(repairContent(ANGLE_COLON)).toBe( + '![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg)' + ); + }); + + it('does not report a well-formed angle-bracket destination', () => { + const ok = '![Checks]()'; + expect(findBrokenBadges(ok)).toHaveLength(0); + expect(repairContent(ok)).toBe(ok); + }); + + it('does not report a valid angle-bracket destination that carries a title', () => { + const titled = '![X]( "Build status")'; + expect(findBrokenBadges(titled)).toHaveLength(0); + expect(repairContent(titled)).toBe(titled); + }); + + it('keeps a title while repairing a broken angle-bracket badge', () => { + const broken = '![D]( Validation-OK-success.svg "Tip")'; + expect(repairContent(broken)).toBe( + '![D](https://img.shields.io/badge/Docs%20Validation-OK-success.svg "Tip")' + ); + }); + + it('ignores the form inside a fenced block', () => { + expect(findBrokenBadges(['```md', ANGLE, '```'].join('\n'))).toHaveLength(0); + }); + + it('repairs a mix of both forms on separate lines and clears every finding', () => { + const content = [BROKE_SPACES, ANGLE, ANGLE_COLON].join('\n'); + expect(findBrokenBadges(content)).toHaveLength(3); + const repaired = repairContent(content); + expect(findBrokenBadges(repaired)).toHaveLength(0); + expect(repairContent(repaired)).toBe(repaired); + }); + + it('does not reset a shared regex position between lines', () => { + expect(findBrokenBadges([ANGLE, ANGLE, ANGLE].join('\n'))).toHaveLength(3); + }); + }); + describe('BROKEN_BADGE', () => { it('matches the bare-space form', () => { BROKEN_BADGE.lastIndex = 0; diff --git a/scripts/validation/lib/label-families.cjs b/scripts/validation/lib/label-families.cjs new file mode 100644 index 0000000000..b63ef49234 --- /dev/null +++ b/scripts/validation/lib/label-families.cjs @@ -0,0 +1,49 @@ +'use strict'; + +/** + * The label families `labels.yml` may carry, in one place. + * + * `validate-labeling-configs.cjs` rejects a label outside these families, and the spec 008 label + * mapping (`scripts/automation/label-mapping.cjs`) must not import a label the validator would + * then reject, so both read this list instead of keeping their own. + */ + +/** Families `labels.yml` may carry today. */ +const LABEL_PREFIXES = [ + 'status:', + 'priority:', + 'type:', + 'area:', + 'comp:', + 'lang:', + 'env:', + 'compat:', + 'cpt:', + 'ai-ops:', + 'contrib:', + 'discussion:', + 'release:', + 'meta:', + 'openspec:', +]; + +/** + * Families the Stage 2 configuration change introduces (FR-011: `ai-ops:` becomes `aiops:`, + * `openspec:` becomes `spec:`, and spec numbers move to `spec-id:`). The mapping imports and + * renames into these, so its check includes them. `labels.yml` itself does not carry them until + * that change merges, which is when T057a moves them into `LABEL_PREFIXES` and drops the old ones. + */ +const STAGE_2_PREFIXES = ['aiops:', 'spec:', 'spec-id:']; + +/** + * Whether a label name starts with one of the given families. + * + * @param {string} name Label name. + * @param {string[]} [prefixes] Families to accept; defaults to the ones `labels.yml` may carry today. + * @returns {boolean} + */ +function hasLabelPrefix(name, prefixes = LABEL_PREFIXES) { + return typeof name === 'string' && prefixes.some((prefix) => name.startsWith(prefix)); +} + +module.exports = { LABEL_PREFIXES, STAGE_2_PREFIXES, hasLabelPrefix }; diff --git a/scripts/validation/validate-badge-urls.cjs b/scripts/validation/validate-badge-urls.cjs index fb208a67f4..f4481b3d6e 100644 --- a/scripts/validation/validate-badge-urls.cjs +++ b/scripts/validation/validate-badge-urls.cjs @@ -36,15 +36,15 @@ const path = require('path'); /** * A shields.io image whose destination contains an unencoded space. * - * Scoped deliberately to the bare form `![alt](https://... Docs Validation-...)`, - * which is the only shape present in the repository (76,594 occurrences across - * 7,657 files at the time of writing). A second, rarer malformation wraps the - * destination in angle brackets and places the `>` mid-URL, as in + * This pattern is the bare form `![alt](https://... Docs Validation-...)`, the + * shape that made up the 76,594 occurrences across 7,657 files counted when this + * check was written. The second malformation wraps the destination in angle + * brackets and places the `>` mid-URL, as in * `![alt](: Documentation Update-OK-success.svg)`. - * That one is not matched here: the closing `>` sits inside the destination, so - * it needs a different pattern, and no file in the repository currently uses it. - * Adding it blind would mean guessing at a shape with no evidence to test - * against. + * It has its own pattern, `ANGLE_BADGE`, because the closing `>` sits inside the + * destination. It was left out at first for lack of an example; the README + * regeneration pull request #3803 produced ten real ones in + * `.github/agentic-workflows/README.md`, so it is matched now. * * Markdown permits an optional quoted title after the destination, as in * `![X](https://example.com/a.svg "Build status")`. A title is not part of the @@ -52,16 +52,97 @@ const path = require('path'); * `--fix` would percent-encode the title into the path and corrupt a valid * badge. * + * A title may itself contain parentheses (`"Build (main)"`), and CommonMark also + * allows a title written in parentheses (`(Build)`). So the text inside the image's + * parentheses is a destination followed by an optional title, never "anything up to + * the first `)`": stopping there split such a title in two, reported a valid badge + * and let `--fix` rewrite part of the title into the URL. + * + * A quote counts as a title only when whitespace comes before it and it closes the + * image. Everywhere else a quote is an ordinary character, so a label such as + * `Don't Stop` keeps its apostrophe and is still found and repaired. + * * Group 1 is the alt text, group 2 is everything inside the parentheses. The * destination and the optional title are separated explicitly by * `splitDestination` rather than by one more regex, because the two cases that * must not be reported — an already-encoded URL and a quoted title — are easier * to get right as steps than as nested groups. */ -const BROKEN_BADGE = /!\[([^\]]*)\]\(([^)]*)\)/gu; + +/** + * A quoted or parenthesised image title, as CommonMark writes it. A backslash escapes the next + * character, so `"Say \"hi\""` and `(Build \) ok)` are one title each, not a title cut short. + */ +const TITLE = String.raw`(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\((?:[^()\\]|\\.)*\))`; + +/** + * Everything between an image's parentheses after the opening `` or from its start: + * characters up to the closing `)`, where a space that begins the final title is not part of + * the run, then that optional title. + */ +const INNER = String.raw`(?:[^)\s]|\s(?!${TITLE}\s*\)))*(?:\s${TITLE}\s*)?`; + +const BROKEN_BADGE = new RegExp(String.raw`!\[([^\]]*)\]\((${INNER})\)`, 'gu'); + +/** + * An image whose destination opens with `` closes before the label ends. Group 1 is the alt text, group 2 the URL up to + * the `>`, group 3 everything after it inside the parentheses. A group 3 that is + * only a title is valid CommonMark (`![x]( "title")`) and not a defect. + */ +const ANGLE_BADGE = new RegExp( + String.raw`!\[([^\]]*)\]\(<(https:\/\/img\.shields\.io\/[^>\s]*)>(${INNER})\)`, + 'gu' +); + +/** + * A title at the very end of a string, preceded by whitespace. It starts at exactly one + * whitespace character, not `\s+`: a run of spaces would otherwise be rescanned from every + * position, which is quadratic. Callers trim the text before the match. + */ +const TRAILING_TITLE = new RegExp(String.raw`\s(${TITLE})\s*$`, 'u'); const SHIELDS_HOST = 'https://img.shields.io/'; +/** + * Split what follows the closing `>` into the leftover label text and an + * optional trailing quoted title. + * + * @param {string} tail Text between the `>` and the closing parenthesis. + * @returns {{body: string, title: string}} `body` is empty for a valid titled image. + */ +function splitAngleTail(tail) { + const titled = TRAILING_TITLE.exec(tail); + return titled + ? { body: tail.slice(0, titled.index), title: titled[1] } + : { body: tail, title: '' }; +} + +/** + * Whether an angle-bracket image has label text stranded after its `>`. + * + * @param {string} tail Text between the `>` and the closing parenthesis. + * @returns {boolean} + */ +function isBrokenAngleTail(tail) { + return splitAngleTail(tail).body.trim() !== ''; +} + +/** + * Rebuild one angle-bracket badge as a single encoded URL. + * + * The text after the `>` continues the label, so it is joined back on: with a + * `%20` when it starts with whitespace (`<.../Docs> Validation-...`), directly + * when it starts with a character such as a colon (`<.../Badges>: Documentation + * Update-...`). Every whitespace run becomes `%20`. The alt text is untouched. + */ +function repairAngleBadge(altText, head, tail) { + const { body, title } = splitAngleTail(tail); + const joiner = /^\s/u.test(body) ? '%20' : ''; + const encoded = body.trim().replace(/\s+/gu, '%20'); + return `![${altText}](${head}${joiner}${encoded}${title ? ` ${title}` : ''})`; +} + /** * Split the inside of an image into its destination and optional title. * @@ -81,9 +162,9 @@ function splitDestination(inner) { // Anchor on the shields host rather than on non-space characters: the // destination of a *broken* badge contains spaces by definition, so a // `\S+` prefix would never match it and the title would be swallowed. - const quoted = text.match(/^(https:\/\/img\.shields\.io\/.*?)\s+("[^"]*")$/u); - if (quoted) { - return { destination: quoted[1], title: quoted[2] }; + const titled = TRAILING_TITLE.exec(text); + if (titled && text.startsWith(SHIELDS_HOST)) { + return { destination: text.slice(0, titled.index).trimEnd(), title: titled[1] }; } return { destination: text, title: '' }; } @@ -167,6 +248,12 @@ function lineHasBrokenBadge(line) { return true; } } + ANGLE_BADGE.lastIndex = 0; + while ((match = ANGLE_BADGE.exec(line)) !== null) { + if (isBrokenAngleTail(match[3])) { + return true; + } + } return false; } @@ -215,7 +302,10 @@ function repairContent(content) { if (fence.consume(line)) { return line; } - return line.replace(BROKEN_BADGE, (match, altText, inner) => { + const angleRepaired = line.replace(ANGLE_BADGE, (match, altText, head, tail) => + isBrokenAngleTail(tail) ? repairAngleBadge(altText, head, tail) : match + ); + return angleRepaired.replace(BROKEN_BADGE, (match, altText, inner) => { const parsed = splitDestination(inner); return parsed && isBrokenBadgeDestination(parsed.destination) ? repairBadge(match, altText, inner) @@ -305,14 +395,16 @@ function main() { } console.error( - `[validate-badge-urls] ${total} badge URL(s) end at an unencoded space, so shields.io renders no label:\n${summary}\n` + + `[validate-badge-urls] ${total} badge URL(s) end at an unencoded space or close early inside angle brackets, so shields.io renders no label:\n${summary}\n` + 'Run `npm run validate:badge-urls:fix` to repair them.' ); process.exit(1); } module.exports = { + ANGLE_BADGE, BROKEN_BADGE, + isBrokenAngleTail, createFenceTracker, findBrokenBadges, isBrokenBadgeDestination, diff --git a/scripts/validation/validate-labeling-configs.cjs b/scripts/validation/validate-labeling-configs.cjs index 483cd35dcd..c3433b6a56 100644 --- a/scripts/validation/validate-labeling-configs.cjs +++ b/scripts/validation/validate-labeling-configs.cjs @@ -3,6 +3,7 @@ const fs = require('fs'); const path = require('path'); const yaml = require('js-yaml'); +const { LABEL_PREFIXES, hasLabelPrefix } = require('./lib/label-families.cjs'); function fail(message) { console.error(`[validate-labeling-configs] ${message}`); @@ -26,23 +27,7 @@ function collectLabelNames(labels) { } function assertLabelConfig(labels) { - const allowedPrefixes = [ - 'status:', - 'priority:', - 'type:', - 'area:', - 'comp:', - 'lang:', - 'env:', - 'compat:', - 'cpt:', - 'ai-ops:', - 'contrib:', - 'discussion:', - 'release:', - 'meta:', - 'openspec:', - ]; + const allowedPrefixes = LABEL_PREFIXES; if (!Array.isArray(labels)) { fail('.github/labels.yml must be an array'); @@ -52,8 +37,7 @@ function assertLabelConfig(labels) { if (!item || typeof item !== 'object' || typeof item.name !== 'string') { fail(`Invalid labels.yml entry at index ${index}`); } - const hasAllowedPrefix = allowedPrefixes.some((prefix) => item.name.startsWith(prefix)); - if (!hasAllowedPrefix) { + if (!hasLabelPrefix(item.name, allowedPrefixes)) { fail( `Label '${item.name}' must use a canonical family prefix (${allowedPrefixes.join(', ')})` ); diff --git a/skills/markdown-to-html/references/code-blocks-to-html.md b/skills/markdown-to-html/references/code-blocks-to-html.md index 4baa8cae78..b58ac2a64a 100644 --- a/skills/markdown-to-html/references/code-blocks-to-html.md +++ b/skills/markdown-to-html/references/code-blocks-to-html.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml) diff --git a/tests/README.md b/tests/README.md index 4f2e613499..7dd79480e5 100644 --- a/tests/README.md +++ b/tests/README.md @@ -2,18 +2,18 @@ ![Checks](https://img.shields.io/badge/Checks-OK-success.svg) -![Docs Validation]( Validation-OK-success.svg) +![Docs Validation](https://img.shields.io/badge/Docs%20Validation-OK-success.svg) ![GitLeaks](https://img.shields.io/badge/GitLeaks-OK-success.svg) -![Labeling Governance]( Governance-OK-success.svg) -![Main Branch Guard]( Branch Guard-OK-success.svg) -![Metadata Governance]( Governance-OK-success.svg) +![Labeling Governance](https://img.shields.io/badge/Labeling%20Governance-OK-success.svg) +![Main Branch Guard](https://img.shields.io/badge/Main%20Branch%20Guard-OK-success.svg) +![Metadata Governance](https://img.shields.io/badge/Metadata%20Governance-OK-success.svg) ![Release](https://img.shields.io/badge/Release-OK-success.svg) -![Template Enforcement]( Enforcement-OK-success.svg) -![Validate PR Template]( PR Template-OK-success.svg) -![Badges: Documentation Update](: Documentation Update-OK-success.svg) -![Badges: Health Check](: Health Check-OK-success.svg) -![Badges: README Status Maintenance](: README Status Maintenance-OK-success.svg) -![Badges: Workflow Inventory Audit](: Workflow Inventory Audit-OK-success.svg) +![Template Enforcement](https://img.shields.io/badge/Template%20Enforcement-OK-success.svg) +![Validate PR Template](https://img.shields.io/badge/Validate%20PR%20Template-OK-success.svg) +![Badges: Documentation Update](https://img.shields.io/badge/Badges:%20Documentation%20Update-OK-success.svg) +![Badges: Health Check](https://img.shields.io/badge/Badges:%20Health%20Check-OK-success.svg) +![Badges: README Status Maintenance](https://img.shields.io/badge/Badges:%20README%20Status%20Maintenance-OK-success.svg) +![Badges: Workflow Inventory Audit](https://img.shields.io/badge/Badges:%20Workflow%20Inventory%20Audit-OK-success.svg) [![branch-name-validation](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-name-validation.yml) [![branch-validation-metrics-aggregator](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/branch-validation-metrics-aggregator.yml) [![changelog-management](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml/badge.svg?branch=develop)](https://github.com/lightspeedwp/.github/actions/workflows/changelog-management.yml)