<!-- SPDX-License-Identifier: Apache-2.0
     https://www.apache.org/licenses/LICENSE-2.0 -->

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [security-tracker-stats.md (template)](#security-tracker-statsmd-template)
  - [YAML config path](#yaml-config-path)
  - [Default output path](#default-output-path)
  - [Cache directory](#cache-directory)
  - [Refresh cadence](#refresh-cadence)
  - [Rejected-without-tracker ledger](#rejected-without-tracker-ledger)
  - [Example overlay (`security-tracker-stats.yaml`)](#example-overlay-security-tracker-statsyaml)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

<!-- SPDX-License-Identifier: Apache-2.0
     https://www.apache.org/licenses/LICENSE-2.0 -->

# security-tracker-stats.md (template)

Per-project configuration consumed by the
[`security-tracker-stats-dashboard`](../../skills/security-tracker-stats-dashboard/SKILL.md)
skill. Copy this file into your project's `<project-config>/`
directory and edit the values below. Everything is optional — the
skill falls back to
[`tools/security-tracker-stats-dashboard/default-config.yaml`](../../tools/security-tracker-stats-dashboard/default-config.yaml)
when a key is unset.

## YAML config path

```yaml
tracker_stats_config: .apache-magpie-overrides/security-tracker-stats.yaml
```

The renderer reads its configuration from the YAML file pointed at by
the `TRACKER_STATS_CONFIG` env var. The skill resolves this from
`tracker_stats_config:` above (interpreting it relative to the
adopter repo root). Adopters who want the framework's defaults
verbatim can leave this unset; the skill will skip the overlay step.

The YAML schema is documented inline at
[`tools/security-tracker-stats-dashboard/default-config.yaml`](../../tools/security-tracker-stats-dashboard/default-config.yaml).

## Default output path

```yaml
tracker_stats_output: tmp/tracker_stats.html
```

The skill writes the rendered HTML to this path (relative to the
adopter repo root, or absolute) when the user does not pass an
explicit `<output-path>` argument. The
reference `<org>/<repo>` adopter uses `tmp/<project>_monthly.html`
(committed into `tmp/` as the canonical artefact for security-team
review).

## Cache directory

```yaml
tracker_stats_cache: /tmp/tracker-stats-cache
```

Where the fetch scripts persist their cache. Safe to delete (forces a
full re-fetch). The skill resolves this to the `TRACKER_STATS_CACHE`
env var.

## Refresh cadence

```yaml
tracker_stats_refresh_hours: 24
```

The skill considers the cache stale when `issues.json` is older than
this many hours, and proposes a refresh before re-rendering. Lower
this for fast-moving trackers; raise it for trackers where the
dashboard is reviewed weekly or monthly.

## Rejected-without-tracker ledger

```yaml
rejections_ledger_label: rejections-ledger
```

Lives in the renderer's YAML overlay (the file pointed at by
`tracker_stats_config:` above), not in `project.md`. Names the label
on the single open **ledger issue** that records reports the
`security-issue-import` skill rejected with a canned reply **without
creating a tracker** — see the *Rejected-without-tracker ledger* note
in [`project.md`](project.md) for the convention. The renderer
identifies any issue carrying this label as the ledger, excludes it
from all tracker classification, and parses its comments for the
`<!-- rejection v1 -->` / `<!-- rejection-backfill v1 count: N -->`
markers to produce a *rejected (no tracker)* count (a per-bucket area
series plus a `<dated> + <historical> = <total>` headline).

Set to `null` to disable the stat entirely (no ledger issue needed).
The ASF default is `rejections-ledger`, matching
`tracker.labels.rejections_ledger` in `project.md`. To turn the stat
on, create the open ledger issue, label it, and keep this knob
pointed at the same label.

## Example overlay (`security-tracker-stats.yaml`)

A minimal overlay that swaps to quarterly buckets and adds a
project-specific milestone:

```yaml
buckets: quarterly

rejections_ledger_label: rejections-ledger

milestones:
  - date: 2026-04-20
    label: skill adoption
  - date: 2026-09-01
    label: handover to PMC sec team
```

A bigger overlay that renames the scope labels for a non-ASF
adopter and removes the upstream-PR charts entirely (because fixes
land in many repos, not a single `<upstream>`):

```yaml
upstream_repo: null

scope_labels: [core, plugins, docs]

milestones: []

# Re-state the full categories list to align with the project's
# label conventions. The framework's default categories assume
# `needs triage`, `pr merged`, `fix released`, `announced - emails
# sent`, `cve allocated` — projects with different label vocabularies
# need to re-state predicates explicitly.
categories:
  - name: fixed_released
    color: "#2ca02c"
    predicate:
      any_of:
        - any_label: [released]
        - all_of:
            state: closed
            state_reason: COMPLETED
            any_label: [security-fix]
  - name: closed_other
    color: "#888888"
    predicate:
      state: closed
  - name: open_untriaged
    color: "#d62728"
    predicate:
      all_of:
        state: open
        any_of:
          - any_label: [needs triage]
          - no_scope_label: true
  - name: open_pr_merged
    color: "#e67e22"
    predicate:
      all_of:
        state: open
        any_label: [pr merged]
  - name: open_triaged
    color: "#f1c40f"
    predicate:
      state: open
```
