Ticket Coverage Guardrails
Score a component on the share of its recent pull requests that referenced an issue-tracker ticket. Evaluated on the default branch, so change-management coverage counts toward initiative and domain scores instead of only appearing on individual pull requests.
ticket-coverage to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/ticket-coverage@v1.0.5
Included Guardrails
This policy includes 1 guardrail that enforce standards for your security and compliance.
ticket-coverage
Asserts that at least min_percentage of the component's pull requests in the
trailing window referenced a ticket, reading .vcs.ticket_coverage from the
ticket-coverage collector.
Skips when there is no coverage data yet, and when the window contains no pull
requests at all — a component with no recent change should not be reported as
failing a change-management control.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
min_percentage
|
Optional |
80
|
Minimum percentage of pull requests in the window that must reference a ticket. |
Documentation
View on GitHubTicket Coverage Guardrails
Score a component on the share of its recent pull requests that referenced a ticket.
Overview
Change-management controls usually ask whether an individual change linked a ticket. This
guardrail asks the complementary question — whether the component links tickets consistently —
and it is evaluated on the default branch rather than per pull request. That placement is what
makes it count: every Lunar rollup reads default-branch state only, so per-PR ticket results
never reach an initiative score. Pair it with the per-PR ticket guardrails, which gate the
individual change.
Policies
This plugin provides the following policies (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
ticket-coverage |
Requires that at least min_percentage of the component's pull requests in the trailing window referenced a ticket |
Recent changes are landing without a linked ticket often enough to fall below the threshold |
Required Data
This policy reads from the following Component JSON paths:
| Path | Written by | Description |
|---|---|---|
.vcs.ticket_coverage.percentage |
ticket-coverage collector |
Share of pull requests in the window that referenced a ticket |
.vcs.ticket_coverage.prs_total |
ticket-coverage collector |
Pull requests recorded in the window |
.vcs.ticket_coverage.prs_with_ticket |
ticket-coverage collector |
How many of those carried a ticket |
.vcs.ticket_coverage.window_days |
ticket-coverage collector |
Length of the trailing window, used in the failure message |
Installation
policies:
- uses: github://earthly/lunar-lib/policies/ticket-coverage@main
enforcement: score
with:
min_percentage: "80"
Scoring rather than blocking is the intended default. The metric describes a trend across many changes, so it is a poor fit for gating any single merge — the pull request that trips the threshold is rarely the one at fault.
Examples
Passing Example
{
"vcs": {
"ticket_coverage": {
"window_days": 30,
"prs_total": 24,
"prs_with_ticket": 21,
"percentage": 87.5
}
}
}
87.5% is at or above the default 80% threshold, so the check passes.
Failing Example
{
"vcs": {
"ticket_coverage": {
"window_days": 30,
"prs_total": 20,
"prs_with_ticket": 11,
"percentage": 55.0
}
}
}
Only 55.0% of PRs in the last 30d referenced a ticket (11/20); minimum is 80.0%.
Remediation
Link a ticket on every pull request — the reference is read from the pull request title or
description by the ticket collector in use. Adding the per-PR ticket guardrails at
report-pr or block-pr fixes the intake, and this percentage then recovers as the trailing
window rolls forward.
Two results are deliberately not failures. The check skips when no coverage data has been
collected yet, and when the window contains no pull requests at all — a component that has not
changed recently has not violated a change-management control. If a component skips
persistently, its release cadence is likely longer than window_days; widen the window rather
than reading the skip as a gap.
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.