---
id: OBPI-0.0.27-05-citation-contract
parent: ADR-0.0.27
item: 5
lane: Heavy
status: Completed
---

# OBPI-0.0.27-05-citation-contract: Citation Contract

## ADR Item

- **Source ADR:** `docs/design/adr/foundation/ADR-0.0.27-exemplar-corpus-doctrine/ADR-0.0.27-exemplar-corpus-doctrine.md`
- **Checklist Item:** #5 — "Citation contract specifying how downstream foundation ADRs cite the corpus (percentile + absolute-number pairing for portability across refresh)"

**Status:** Draft

## Objective

Specify the canonical citation form by which downstream foundation ADRs (0.0.28 / 0.0.29 / 0.0.30) reference the distilled-characteristics document, codify the percentile + absolute-number pairing requirement so that boundaries remain portable across corpus refresh, and provide the parser surface that OBPI-07's link-integrity validator consumes.

## Lane

**Heavy** — Citation contract is a binding doctrinal surface consumed by three downstream foundation ADRs and the link-integrity validator. Foundation-kind brief-level Gate 5 attestation.

## Allowed Paths

- `.gzkit/rules/complexity-doctrine.md` — extension only: add the "Citation contract" section formalizing the citation tuple, percentile + absolute pairing, and refresh-portability rule (rule-version bump per `.gzkit/rules/skill-surface-sync.md`)
- `src/gzkit/complexity/**/citation.py` — citation tuple parser + portability checker (consumed by OBPI-07)
- `src/gzkit/schemas/**/complexity_citation.json` — JSON Schema for the citation tuple
- `tests/complexity/**/test_citation.py` — REQ-derived assertions on parser, schema, portability rule
- `docs/design/adr/foundation/ADR-0.0.27-exemplar-corpus-doctrine/**` — brief evidence updates only

> Vendor mirrors at `.claude/rules/complexity-doctrine.md`, `.agents/rules/complexity-doctrine.md`, and `.github/instructions/complexity-doctrine.md` are regenerated by `gz agent sync control-surfaces` after the canonical `.gzkit/rules/complexity-doctrine.md` lands; never edit them directly per `.gzkit/rules/skill-surface-sync.md`.

## Denied Paths

- `data/exemplar_corpus.json` — corpus is OBPI-02
- `src/gzkit/complexity/measurement.py` — measurement is OBPI-03
- `docs/governance/complexity/distilled-characteristics-*.md` — distillation outputs are OBPI-04
- `.gzkit/skills/gz-complexity-distill/**` — skill is OBPI-06
- `src/gzkit/governance/trust_audits.py` — link validator is OBPI-07
- ADR-0.0.28 / 0.0.29 / 0.0.30 files — those ADRs cite this contract in their own briefs, not here
- Any path not listed in Allowed Paths

## Requirements (FAIL-CLOSED)

1. REQUIREMENT: The "Citation contract" section in `.gzkit/rules/complexity-doctrine.md` defines the canonical citation tuple as `(distilled_characteristics_path, section_anchor, corpus_revision)` and forbids citation of raw distributions or the corpus directly.
2. REQUIREMENT: The section codifies the percentile + absolute-number pairing rule: every cited boundary appears as both a percentile-of-corpus AND the absolute-number-at-that-percentile (e.g. "p90 = CC 12"), so that downstream ADRs remain readable across corpus refresh even when absolute numbers shift.
3. REQUIREMENT: The section codifies the corpus-refresh portability rule: when a citing ADR references `(file, anchor, corpus_revision=N)` and a new distillation lands at `corpus_revision=N+1`, the citation remains valid until the citing ADR is amended; the link-integrity validator (OBPI-07) flags out-of-date references but does not auto-rewrite them.
4. REQUIREMENT: `src/gzkit/complexity/citation.py` exposes `parse_citation(text: str) -> Citation` and `is_portable(citation: Citation, current_revision: int) -> bool` (Pydantic frozen `Citation` model) consumed by OBPI-07.
5. REQUIREMENT: The citation tuple JSON Schema at `src/gzkit/schemas/complexity_citation.json` is `extra="forbid"` equivalent and validates: `distilled_characteristics_path` is a relative path under `docs/governance/complexity/`; `section_anchor` is a slugified anchor string; `corpus_revision` is a positive integer.
6. REQUIREMENT: Tests cover: parser accepts canonical tuple shape; parser rejects citations that omit any of the three fields; portability returns true within current revision; portability returns false when revision is older than the supported window (parameterized in the rule); rule body parsing detects the citation contract section; vendor-mirror sync produces empty diff. Each test decorated with `@covers(REQ-0.0.27-05-NN)`.
7. REQUIREMENT: The rule-version marker in `.gzkit/rules/complexity-doctrine.md` is bumped to reflect this OBPI's amendment (e.g. `0.1.0` → `0.2.0`); both the body-level `<!-- rule-version: ... -->` HTML comment and the visible block quote update together.
8. REQUIREMENT: TDD discipline; `tempfile`-backed fixtures.
9. REQUIREMENT: NEVER include the operator's personal email in rule body, schema, code, or fixtures.

> STOP-on-BLOCKERS: if OBPI-04 has not produced the first distilled-characteristics document, STOP — the citation contract has no concrete artifact to bind against.

## Discovery Checklist

**Prerequisites**

- [x] OBPI-0.0.27-01 `attested_completed` — `.gzkit/rules/complexity-doctrine.md` (rule-version `0.1.0`) carries the existing "Citation Contract (binding)" prose section this OBPI extends; the rule-version bump discipline (`<!-- rule-version: ... -->` body comment + visible block quote) is anchored in `.gzkit/rules/skill-surface-sync.md` § Surface layout.
- [x] OBPI-0.0.27-04 `attested_completed` — `docs/governance/complexity/distilled-characteristics-2026-05-04.md` (frontmatter `corpus_revision: 1`) is the first concrete distilled-characteristics artifact this citation contract binds against; the `radon_cc p90 = 7` boundary is the worked example referenced in the percentile + absolute pairing rule.
- [x] AGENTS.md § Lane & Kind & Sensitivity Attestation Matrix — foundation + heavy → brief-level Gate 5 walkthrough required regardless of lane; `_requires_human_obpi_attestation` returns True via the foundation branch.
- [x] AGENTS.md § Attestation — citation discipline is the same shape as ARB receipt-ID discipline (claims without observable evidence are post-hoc reasoning pathways). Both surfaces require the cited identifier (receipt ID / citation tuple) to resolve mechanically.
- [x] `.gzkit/rules/skill-surface-sync.md` — rule-version bump discipline (minor bump for governance-rule extension) and body-level marker convention; vendor mirrors regenerated by `gz agent sync control-surfaces`, never edited directly.

**Existing Code**

- [x] `src/gzkit/complexity/__init__.py` — package surface for the new `citation` module to import alongside `measurement`, `baseline`, `aggregator`, `distillation`.
- [x] `src/gzkit/schemas/` — directory housing canonical JSON Schemas (e.g. `exemplar_corpus.json`, `complexity_baseline.json`); the new `complexity_citation.json` lands here under the same Draft 2020-12 + `additionalProperties: false` discipline.
- [x] `tests/complexity/__init__.py` and sibling `test_distillation.py` — established test-module pattern for the OBPI-0.0.27 cluster; `@covers("REQ-X.Y.Z-NN-MM")` decorator imported from `gzkit.traceability` is the REQ → @covers parity surface.
- [x] `data/behave_coverage_waivers.json` — `adr-0.0.27-foundation-bdd-deferred` rationale slug already established for OBPI-01 and OBPI-02; this OBPI registers the same rationale because BDD coverage for the citation contract lands at OBPI-07's CLI surface (`gz validate --complexity-doctrine-links`).
- [x] `src/gzkit/traceability.covers` — `@covers("REQ-X.Y.Z-NN-MM")` decorator validates against the brief's Acceptance Criteria; consumed by `gz covers OBPI-... --json` parity gate at Stage 3 Phase 1b.

## Quality Gates

### Gate 1: ADR
- [ ] Intent recorded; parent checklist item quoted

### Gate 2: TDD
- [ ] RGR cycle; tests pass with `@covers`

### Code Quality
- [ ] Lint/type clean

### Gate 3: Docs (Heavy)
- [ ] mkdocs --strict clean (rule body renders)

### Gate 4: BDD (Heavy)
- [ ] BDD waiver registered: rule + parser scope; downstream-citation BDD lands at OBPI-07's link validator

### Gate 5: Human (Heavy + Foundation)
- [ ] TTY + `ATTEST` confirmation

## Verification

```bash
uv run gz lint
uv run gz typecheck
uv run gz test
uv run gz validate --advisory-scorecard
uv run gz validate --documents --surfaces
uv run gz agent sync control-surfaces  # diff empty
uv run gz arb step --name unittest -- uv run -m unittest tests/complexity/test_citation.py -v
```

## Acceptance Criteria

- [ ] REQ-0.0.27-05-01: Given the rule body, when the "Citation contract" section is parsed, then the canonical tuple `(distilled_characteristics_path, section_anchor, corpus_revision)` is named and the prohibition on raw-distribution citation is explicit.
- [ ] REQ-0.0.27-05-02: Given the rule body, when the "Percentile + absolute pairing" rule is parsed, then both forms are required for every cited boundary.
- [ ] REQ-0.0.27-05-03: Given a citation tuple in canonical form, when `parse_citation` runs, then a frozen `Citation` model is returned.
- [ ] REQ-0.0.27-05-04: Given a citation missing any of the three fields, when `parse_citation` runs, then a `ValidationError` is raised.
- [ ] REQ-0.0.27-05-05: Given a citation with `corpus_revision=N` and a current revision `N`, when `is_portable` runs, then it returns true; given `corpus_revision` older than the supported window, it returns false.
- [ ] REQ-0.0.27-05-06: Given the rule file, when the rule-version marker is parsed, then the body comment and the visible block quote agree on the bumped version.
- [ ] REQ-0.0.27-05-07: Given a clean working tree, when `uv run gz agent sync control-surfaces` runs, then all four mirrors produce identical content and the post-sync diff is empty.

## Completion Checklist

- [ ] Gate 1: Intent recorded
- [ ] Gate 2: RGR cycle; tests pass with `@covers`
- [ ] Code Quality: lint/type clean
- [ ] Gate 3: mkdocs --strict clean
- [ ] Gate 4: BDD waiver registered
- [ ] Gate 5: TTY + `ATTEST` captured

## Evidence

### Gate 1 (ADR)
- [ ] Intent and scope recorded

### Gate 2 (TDD — Red-Green-Refactor)
```text
# Paste RGR observations + final unittest output
```

### Code Quality
```text
# Paste lint/typecheck output
```

### Gate 3 (Docs)
```text
# Paste mkdocs --strict output
```

### Gate 4 (BDD)
```text
# Waiver: data/behave_coverage_waivers.json — OBPI-0.0.27-05
```

### Gate 5 (Human)
```text
# Record attestation text + receipt IDs
```

### Value Narrative

<!-- Problem before: downstream foundation ADRs would cite numeric thresholds in narrative form, exposing them to silent drift across corpus refresh. Capability now: a canonical citation tuple with percentile + absolute pairing makes references portable across refresh, and the parser surface gives OBPI-07's link validator a mechanical check against the rule. -->

### Key Proof


REQ → @covers parity gate is the canonical evidence — the brief lists 7 acceptance-criteria REQs, every one is reachable from a `@covers` decorator on a passing unittest:

```bash
$ uv run gz covers OBPI-0.0.27-05-citation-contract --json --output /tmp/covers.json
$ uv run python -c "import sys, json; sys.stdout.reconfigure(encoding='utf-8'); print(json.dumps(json.load(open('/tmp/covers.json'))['summary'], indent=2))"
{
  "identifier": "OBPI-0.0.27-05-citation-contract",
  "total_reqs": 7,
  "covered_reqs": 7,
  "uncovered_reqs": 0,
  "coverage_percent": 100.0
}
```

Stage 3 ARB receipts (canonical attestation provenance per AGENTS.md § Attestation):

- Tests: `arb-step-unittest-f373e30485574755ad57178cd569c864` (14/14 pass)
- Lint: `arb-ruff-d2ef77b772234bd6adc42eeb735e4e23` (clean)
- Typecheck: `arb-step-typecheck-d9d8794ab9cc468eb2f54dfe3ec20612` (clean)
- Docs: `arb-step-mkdocs-3d4ca5419aa64a2fb905be24ec9e55d3` (mkdocs --strict clean)

Rule-version bump diff hunk (the load-bearing canonical signal that the doctrine extension landed at the canonical surface; vendor mirrors regenerated):

```diff
-<!-- rule-version: 0.1.0 -->
+<!-- rule-version: 0.2.0 -->
-> **Rule version:** `0.1.0` — authored under OBPI-0.0.27-01 to codify …
+> **Rule version:** `0.2.0` — bumped under OBPI-0.0.27-05 to formalize the
+> citation tuple `(distilled_characteristics_path, section_anchor,
+> corpus_revision)`, codify the percentile + absolute-number pairing rule,
+> and name the refresh-portability rule the link-integrity validator
+> (OBPI-0.0.27-07) consumes. …
```

### Implementation Summary


- Files created: `src/gzkit/complexity/citation.py` (frozen `Citation` Pydantic model + `parse_citation` + `is_portable` with `DEFAULT_SUPPORTED_WINDOW=2`); `src/gzkit/schemas/complexity_citation.json` (Draft 2020-12, `additionalProperties: false`, mirrors the Pydantic constraints); `tests/complexity/test_citation.py` (14 unittest cases across 8 classes; all 7 AC REQs decorated with `@covers`).
- Files modified: `.gzkit/rules/complexity-doctrine.md` (Citation Contract section extended with canonical-tuple subsection, percentile + absolute pairing rule with the landed `radon_cc p90 = 7` worked example, refresh-portability rule naming OBPI-0.0.27-07's flag-not-rewrite verdict; rule-version bumped 0.1.0 → 0.2.0 in body marker and visible block quote); `.claude/rules/complexity-doctrine.md` and `.github/instructions/complexity_doctrine.instructions.md` (regenerated by `gz agent sync control-surfaces`); `data/behave_coverage_waivers.json` (OBPI-0.0.27-05 registered against `adr-0.0.27-foundation-bdd-deferred` rationale); brief Allowed Paths cleaned of vendor mirrors and switched to parent-dir globs (pre-implementation brief fix to clear plan-audit gaps surfaced by GHI #393).
- Tests added: 14 unittest cases under 8 behavior-named test classes (per `.gzkit/rules/tests.md` § eval-awareness corollary); REQ → @covers parity 7/7 (100%) verified via `uv run gz covers OBPI-0.0.27-05-citation-contract --json`.
- Date completed: 2026-05-04.
- Attestation status: operator attested via `attest completed` in Stage 4 walkthrough; relayed through `--attestor-present` co-presence proxy with active pipeline marker satisfying GHI #292 gate.
- Defects noted: GHI #399 filed for the pipeline-active marker leak (Stage 5 of prior runs left orphan `.pipeline-active-OBPI-0.0.25-02/03.json` markers that blocked this pipeline launch); not in OBPI-05's scope. Brief authoring imprecision noted: brief originally listed `.agents/rules/complexity-doctrine.md` as an Allowed Path mirror but `.gzkit/rules/skill-surface-sync.md` § Surface layout names only `.claude/rules/` and `.github/instructions/` as the rule-mirror surfaces — corrected by removing the `.agents/rules/` reference during the pre-implementation brief edit.

### Closing Argument

<!-- One paragraph: why the percentile + absolute pairing is the load-bearing portability invariant (corpus refresh shifts absolute numbers but preserves percentile semantics), why a parser-backed citation closes the silent-drift class at the OBPI-07 layer, and why citation discipline is the same shape as ARB receipt-ID discipline (claims without observable evidence are post-hoc reasoning pathways). -->

## Tracked Defects

_No defects tracked._

## Human Attestation

- Attestor: `Jeffry Babb`
- Attestation: attest completed — foundation+heavy citation contract closed: src/gzkit/complexity/citation.py lands the frozen Pydantic Citation(distilled_characteristics_path, section_anchor, corpus_revision) model with parse_citation and is_portable (DEFAULT_SUPPORTED_WINDOW=2); src/gzkit/schemas/complexity_citation.json mirrors it under additionalProperties=false; .gzkit/rules/complexity-doctrine.md Citation Contract section formalizes the canonical tuple, the percentile + absolute pairing rule (worked example: radon_cc p90 = 7 from the landed 2026-05-04 distilled-characteristics document), and the refresh-portability rule naming OBPI-0.0.27-07 flag-not-rewrite verdict; rule-version bumped 0.1.0 -> 0.2.0 in body marker and visible block quote; .claude/rules/ + .github/instructions/ regenerated by gz agent sync control-surfaces; data/behave_coverage_waivers.json registers OBPI-0.0.27-05 against adr-0.0.27-foundation-bdd-deferred (CLI BDD lands at OBPI-07). 14 unittest cases pass; REQ -> @covers parity 7/7 (100%). ARB receipts: arb-ruff-d2ef77b772234bd6adc42eeb735e4e23, arb-step-typecheck-d9d8794ab9cc468eb2f54dfe3ec20612, arb-step-unittest-f373e30485574755ad57178cd569c864, arb-step-mkdocs-3d4ca5419aa64a2fb905be24ec9e55d3.
- Date: 2026-05-05

---

**Brief Status:** Completed

**Date Completed:** 2026-05-05

**Evidence Hash:** -
