Skip to content

PR Gate shadow capacity

The capacity probe is a diagnostic prerequisite for the future PR Gate shadow reconciler. It does not authorize a merge, change any required check, or create a daily reconciliation root. Its only result is an immutable UNVERIFIED receipt.

What the workflow does

PR Gate shadow capacity can run only through workflow_dispatch on the default branch. It checks out that exact trusted revision with no persisted credential, uses read-only contents, actions, and pull-requests permissions, and never checks out a pull-request head. The workflow authenticates its own provider run/attempt before it reads history.

The probe then performs two independent observations of the same fixed, closed 14-day UTC-second interval. Each observation includes producer and auditor runs, every observed attempt, complete Jobs and artifact inventories, authenticated audit-receipt archives, and an exact producer lookup for each receipt. Git requests, API body bytes, ZIP archive bytes, redirects, and wall time share hard parent limits. A missing, moved, non-terminal, changed, or ambiguous provider record blocks the diagnostic rather than being interpreted as an empty result.

The observation implementation is itself source-bound: its static manifest, the diagnostic CLI and workflow, Git commit/tree/blob objects, SHA-256 values, regular-file modes, and the local default-branch checkout must all agree before history is scanned. The manifest's own immutable blob digest is included in the published bundle digest, so a source change requires a fresh capacity receipt.

Refreshing the source manifest after a release bump

The manifest also includes pyproject.toml and uv.lock. After an intentional version or dependency change, regenerate their hashes from the reviewed working tree before committing. From the repository root, this producer validates every existing entry and Git mode, then updates only the content hashes. It does not add paths, change modes, relax verification, or produce a capacity receipt.

uv run --frozen python - <<'PY'
import hashlib
import subprocess
from pathlib import Path

import yaml

from dpone.services.ci.shadow_observation_bundle import entries_from_manifest

root = Path.cwd().resolve()
manifest = root / ".agents/policy/ci-shadow-reconciliation-observation-bundle-v1.yml"
original = manifest.read_text(encoding="utf-8")
entries = entries_from_manifest(yaml.safe_load(original))
updated = original
for entry in entries:
    source = root / entry.path
    if source.resolve() != source or not source.is_file():
        raise ValueError(f"Not a regular, confined source file: {entry.path}")
    tracked = subprocess.check_output(
        ["git", "ls-files", "--stage", "-z", "--", entry.path], text=True
    ).split("\0")
    if len(tracked) != 2 or tracked[-1] != "":
        raise ValueError(f"Expected one tracked entry: {entry.path}")
    metadata, tracked_path = tracked[0].split("\t", 1)
    mode, _, stage = metadata.split()
    local_mode = "100755" if source.stat().st_mode & 0o111 else "100644"
    if tracked_path != entry.path or mode != entry.mode or local_mode != mode or stage != "0":
        raise ValueError(f"Git path, mode or merge stage mismatch: {entry.path}")
    digest = "sha256:" + hashlib.sha256(source.read_bytes()).hexdigest()
    block = (
        f"  - path: {entry.path}\n"
        f'    mode: "{entry.mode}"\n'
        f'    blob_sha256: "{entry.blob_sha256}"'
    )
    if updated.count(block) != 1:
        raise ValueError(f"Unexpected manifest formatting: {entry.path}")
    updated = updated.replace(block, block.replace(entry.blob_sha256, digest), 1)
refreshed = entries_from_manifest(yaml.safe_load(updated))
if [(e.path, e.mode) for e in refreshed] != [(e.path, e.mode) for e in entries]:
    raise ValueError("Source inventory changed")
if updated != original:
    manifest.write_text(updated, encoding="utf-8")
print(f"Validated {len(refreshed)} source entries; review the manifest diff.")
PY
uv run --frozen pytest tests/test_ci_shadow_pr4c_observation_bundle_verifier.py -q

Commit the reviewed source changes and manifest together. The .agents/ change requires a fresh agent-governance artifact and PR receipt through normal CI. Historical capacity receipts remain unchanged and do not certify the new bundle; run a new authenticated diagnostic only when fresh capacity evidence is needed.

Reading the receipt

The artifact filename is pr-gate-shadow-reconciliation-capacity-<run-id>-<attempt>.json. It is create-only and retained for 90 days. The upload is intentionally archived as a ZIP so the provider artifact size and digest authenticate the actual transport bytes; the sole capacity JSON member is separately bounded and hashed before strict JSON parsing. Auditor receipts observed by the probe follow the same ZIP-then-payload rule. Do not compare provider digest metadata directly with extracted JSON bytes.

RECONCILIATION_CAPACITY_CALIBRATION_ONLY means the two snapshots matched and usage was no more than half the parent limits. It is still UNVERIFIED: it only permits the next implementation phase after fresh evidence and the separate public-fork lifecycle canary. RECONCILIATION_PR4C_IMPLEMENTATION_BLOCKED means the evidence was incomplete, differed, crossed a hard limit, or exceeded the half-limit safety threshold.

The workflow is expected to end red after a receipt is uploaded, because a diagnostic receipt is deliberately never a pass. Download the exact artifact for its run and attempt; never edit or overwrite an earlier receipt.

For copyable dispatch, inspection, evidence-boundary, and recovery steps, use the capacity runbook. The request policy is 3,000 hard requests and 1,500 qualifying requests; byte and wall-time thresholds remain unchanged.

Recovery

Symptom Meaning Safe action
No artifact Source authentication, checkout, bundle binding, or persistence failed before evidence could be created. Fix the trusted default-branch implementation and dispatch a new run.
...IMPLEMENTATION_BLOCKED Observation was incomplete, unequal, stale, or over budget. Inspect counters and source identity; do not raise a limit without an approved parent amendment.
Artifact/archive mismatch Metadata does not bind the fetched ZIP or its sole payload. Treat the receipt as unusable and run a fresh authenticated attempt.
Old receipt Capacity evidence expires for approval after 24 hours. Dispatch a fresh default-branch probe.

Historical receipts use capacity.v1. The amended workflow emits capacity.v2; keep V1 for historical validation and use only V2 for the amended prerequisite.