# Downstream Sync Contract

> For maintainers of projects that auto-sync from ATR — Microsoft Agent
> Governance Toolkit, Cisco AI Defense skill-scanner, MISP taxonomies +
> galaxy, OWASP Agent-Security-Regression-Harness, FINOS Common Cloud
> Controls, and any future consumer.

This doc spells out what ATR commits to and what we recommend the
downstream sync filter.

## The contract

ATR commits to:

1. **No silent breaking changes to existing rule IDs.** A rule's `id`
   field (e.g. `ATR-2026-00440`) is permanent. We never reuse an id
   for a different attack family.
2. **No silent removal of stable rules.** A rule marked `maturity: stable`
   only transitions to `deprecated` (still loadable, with a warning) —
   never directly to gone. Deprecation comes with a `superseded_by`
   pointer to the replacement rule.
3. **Six-check pre-merge quality gate.** Every rule in `rules/` has
   passed: metadata, own-TP-must-match, benign-skill-corpus 0 FP,
   research-mention 0 FP, cross-rule no-conflict, per-PR cap.
   See [QUALITY-GATE.md](QUALITY-GATE.md).
4. **Public FP reporting channel.** Anyone can open a
   [false-positive report issue](../.github/ISSUE_TEMPLATE/false-positive.yml)
   on a misfiring rule. Confirmed FPs auto-demote the rule from
   `stable` → `test` until tightened.
5. **Honest maturity tagging.** Rules generated by automation (CVE
   collector, TC crystallisation, red-team probe pipeline) start at
   `maturity: experimental`. Promotion to `stable` requires explicit
   maintainer review + 30+ days in main + 0 FP reports + ≥1
   confirmed in-the-wild match.

## What we recommend downstream consumers do

### Filter by `maturity: stable` for production paths

This is the single most important recommendation. ATR's auto-sync
workflows pull every rule under `rules/`, including `experimental` and
`test` tier rules. Production traffic should only see `stable`.

**Example filter in your sync script (TypeScript):**

```typescript
import { loadAllRules } from "agent-threat-rules";

const all = await loadAllRules();
const productionRules = all.filter((r) => r.maturity === "stable");
const stagingRules = all.filter((r) => r.maturity === "test");
// experimental rules: pull them only if you have a shadow / canary path
```

**Example filter in Python:**

```python
import yaml, glob

production_rules = [
    yaml.safe_load(open(f))
    for f in glob.glob('rules/**/*.yaml', recursive=True)
    if yaml.safe_load(open(f)).get('maturity') == 'stable'
]
```

### Run rules through your own shadow path first

Even after our gate passes, your traffic is different from ours. We
benchmark against 432 benign SKILL.md samples and 55 research-mention
samples; you have your own corpus that we never see. A rule that's
clean for us may FP on your specific customer data.

Recommended deployment pattern:

1. **Day 0:** Sync new rule with `maturity: stable`. Ship in
   **shadow mode** — log matches but don't surface to users.
2. **Day 7:** Audit the shadow log. Sample any unexpected matches.
3. **Day 14:** If shadow log is clean, flip to alert / deny.
4. **Day 14+:** If a customer reports FP, file an FP-report issue
   on ATR. We tighten the rule and you re-sync.

### Use the confidence score

Every ATR match returns a `confidence` field (0.0–1.0). High-confidence
matches are safer for auto-deny; lower confidence is better suited to
alert + human triage.

Suggested thresholds:

| Action                 | Recommended min confidence |
| ---------------------- | -------------------------- |
| Auto-deny / auto-block | ≥ 0.9                      |
| Alert + log            | ≥ 0.7                      |
| Shadow log only        | ≥ 0.5                      |

These are starting points. Tune to your environment.

### Pin to a release tag, don't track `main`

Auto-sync workflows that track `main` pick up brand-new rules within
minutes. For production sync, pin to a numbered release
(`v2.1.3`, `v2.2.0`) and bump on a cadence you control. Releases get
a CHANGELOG entry highlighting any rules that landed since the last
release.

### Honour the deprecation signal

When a rule moves to `maturity: deprecated`, the YAML retains a
`superseded_by: ATR-2026-NNNNN` field pointing to the replacement.
Your sync script should:

1. Continue loading the deprecated rule for backwards compatibility.
2. Log a warning the first time it fires after the version that
   deprecated it.
3. Plan migration to `superseded_by` within the next release cycle.

## Filing FP reports

If a rule fires on legitimate content in your environment:

1. Open a [false-positive report issue](https://github.com/Agent-Threat-Rule/agent-threat-rules/issues/new?template=false-positive.yml).
2. Include: rule ID, the exact content that triggered, ATR version,
   your detection pipeline (AGT / skill-scanner / direct npm).
3. We acknowledge within 24h (per [security.txt](https://agentthreatrule.org/.well-known/security.txt))
   and tighten the rule within 7 days for stable-tier rules.

If you're a downstream maintainer and want a private channel for
sensitive FP samples (customer-specific patterns), email
`security@agentthreatrule.org`.

## Current consumers and their sync workflows

| Consumer                       | Sync method                                            | Filter                                                         | Frequency            |
| ------------------------------ | ------------------------------------------------------ | -------------------------------------------------------------- | -------------------- |
| Microsoft AGT                  | Weekly workflow (`microsoft/agent-governance-toolkit`) | currently: all rules. Recommended: `maturity != experimental`. | Weekly Mondays       |
| Cisco AI Defense skill-scanner | PR-driven manual sync                                  | 314 rule pack as of v2.1.0                                     | On release tags      |
| MISP taxonomies                | Tag-mapped, snapshot via PR                            | All published rule IDs                                         | On release tags      |
| MISP galaxy                    | Cluster mapping                                        | All categories + severity                                      | On release tags      |
| OWASP A-S-R-H                  | Regression fixtures cite ATR rule IDs                  | n/a — fixtures pin to specific rules                           | Per fixture revision |

If you maintain a consumer not in this table, open a PR adding a row.
We track the contract per consumer so we can warn before any change
that would affect you.

## What we'd love downstream to do (open offer)

If you can wire **telemetry feedback** back to ATR — even just a
weekly count per rule of "fired N times, of which M were dismissed
as FP by the operator" — we can use that signal to auto-promote /
demote maturity tiers. This closes the loop: rules that work in your
production env get promoted faster; rules with even a few real-world
FPs get demoted before they hit anyone else.

Schema is documented at `docs/telemetry-spec.md` (stub — to be
written when the first consumer commits to implementing it).
