# Project export: ChangeProof

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: Turn every external requirement into an approved, implemented, and verifiable business change—with complete source-to-evidence traceability.
- Devpost: https://devpost.com/software/changeproof
- GitHub: https://github.com/SalilBhasinOfficial/changeproof
- Video: https://www.youtube.com/embed/HuAMkzpiXjk?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Salil Bhasin (54 commits)

## Devpost submission (written by the team)

### Inspiration

When a regulation changes, finding the new sentence is only the beginning. Teams must still identify every affected policy, procedure, control, system, test, and owner—and prove that the resulting changes are complete and approved. ChangeProof began with a fictional lender responding to an RBI complaint-handling requirement changing from 30 days to 21 days. We wanted an evidence-backed change workflow rather than another report, spreadsheet, or disconnected set of tickets.

### What it does

ChangeProof converts an external obligation into a cited, reviewable, and tested organizational change package. It extracts the exact source quote, computes the affected workspace spans with evidence for every graph edge, and proposes coordinated changes across policies, procedures, controls, application logic, schedulers, interfaces, and tests. A reviewer can reject one impact with a rationale, inspect the revised plan while retaining the superseded version, and approve only the exact reviewed snapshot. ChangeProof then applies the approved package in an isolated workspace, runs verification, searches for obsolete requirements, and produces a hash-bound proof certificate containing citations, diffs, decisions, results, residuals, and exceptions. GPT-5.6 performs schema-constrained obligation extraction and coordinated redline drafting when an API key is configured. Model identity, prompt and schema versions, response hashes, token usage, and estimated cost are bound into the manifest. A deterministic offline fallback preserves the complete golden path with synthetic data and no credentials.

### How we built it

Codex accelerated repository analysis, architecture, implementation, synthetic fixture design, tests, adversarial review, and release rehearsal. Human decisions set the fictional-lender scope, evidence standard, approval gates, safety boundaries, and product direction. The product uses Python standard-library runtime components, SQLite, SHA-256 content bindings, strict JSON schemas, a computed workspace scanner, and a responsive reviewer UI. GPT-5.6 is integrated through the OpenAI Responses API. The repository has 61 passing tests and an optional private AWS deployment overlay; a clean clone still runs the full offline workflow without private infrastructure or package installation.

### Challenges we ran into

Our first impact list was fixture-driven, and our first patching approach relied on global replacement. A skeptical reviewer could reasonably see a rehearsed fixture rather than an analysis engine. We replaced both with computed workspace discovery, exact spans, per-edge evidence, and span-targeted patches. We also upgraded model metadata into tamper-evident, hash-bound proof links and built a genuine reject–revise–approve lifecycle. Every rejected plan remains viewable, every revision receives a new snapshot hash, and stale approvals fail.

### Accomplishments we're proud of

Computed an eight-artifact blast radius from one cited obligation. Integrated GPT-5.6 with deterministic validation and offline fallback. Delivered a demonstrable human rejection, revision, approval, application, and verification workflow. Made cost-effective governance AI auditable through token, cache, execution-mode, estimated-cost, and cost-avoidance evidence. Pointed ChangeProof at ChangeProof: the self-compliance milestone passed 51 tests and 11/11 automated controls while disclosing two exceptions rather than hiding them. Kept the complete judge path portable, synthetic, and independent of private infrastructure. Published a processed, public 173-second Build Week demonstration video.

### What we learned

Traceability must be structural, not explanatory prose added after generation. Every conclusion needs a source span, impact rationale, decision record, and stable hash. Human approval must bind to the exact content reviewed, and rejected plans must remain visible. Model identity, prompt and schema versions, usage, cost, and exceptions belong in the same evidence chain as the business change.

### What's next

We will expand the scanner and framework catalog beyond the demonstration, add enterprise identity and workflow integrations, and gather broader real-world cost and accuracy evidence. The core direction remains the same: turn any external obligation into a human-governed, verifiable organizational change—without pretending that AI replaces legal judgment or accountable approval.

## README (from the GitHub repository)

# ChangeProof

**Turn every external requirement into a verified internal change.**

ChangeProof is a governed B2B change-management agent. It converts a new regulation, contract clause, security requirement, audit finding, or internal policy decision into a cited and reviewable change package spanning policies, controls, procedures, software, tests, owners, and verification evidence.

The initial project is being built for the **OpenAI Build Week 2026 — Work & Productivity** category.

## Product promise

Most compliance tools tell a team what changed. ChangeProof completes the change—and proves it.

```text
external obligation
    -> cited structured requirement
    -> organizational impact graph
    -> coordinated document and code changes
    -> human approval
    -> tests and residual-risk checks
    -> immutable evidence package
```

## Initial demonstration

A fictional Indian lender receives an RBI circular reducing its complaint-response deadline from 30 days to 21 days. ChangeProof identifies every affected policy, SOP, control, service constant, scheduler, UI label, and test; produces coordinated redlines and patches; incorporates reviewer feedback; runs verification; and generates a source-to-change proof manifest.

## Documentation

- [Research and recommendation](docs/RESEARCH_AND_RECOMMENDATION.md)
- [Product specification](docs/PRODUCT_SPEC.md)
- [Architecture](docs/ARCHITECTURE.md)
- [Build Week execution plan](docs/BUILD_WEEK_PLAN.md)
- [Delivery checklist](docs/PROJECT_CHECKLIST.md)
- [Capital adequacy reference scenario](docs/CAPITAL_ADEQUACY_SCENARIO.md)
- [Submission checklist](docs/SUBMISSION_CHECKLIST.md)
- [Prior-work boundary](docs/PRIOR_WORK_BOUNDARY.md)
- [Self-compliance obligations register](docs/self-compliance/OBLIGATIONS_REGISTER.md)
- [Security policy](SECURITY.md) and [privacy boundary](docs/PRIVACY.md)

## Status

The deterministic offline vertical slice is implemented. It loads the synthetic
lender workspace, computes cited artifact impacts and governed proposal history, applies only
approved revisions to an isolated workspace, runs a real regression check and
residual scan, and writes a hash-addressed proof record. A local reviewer UI
binds approval to the exact displayed eight-artifact change plan.

Impact discovery is runtime analysis, not fixture lookup: ChangeProof scans the
workspace for obligation-relevant deadline spans and structural references,
records file/line/column evidence per edge, and constructs the impact graph. The
checked-in `impacts.json` is used only by tests as the expected-result oracle.
Offline edits target those evidenced offsets; unrelated occurrences are untouched.

## Judge path — three commands

```bash
git clone https://github.com/SalilBhasinOfficial/changeproof.git
cd changeproof
PYTHONPATH=src python3 -m changeproof review --workspace /tmp/changeproof-review --database /tmp/changeproof-review.sqlite3
```

Open `http://127.0.0.1:8000/`. No package installation, API key, BBB service or
private data is required. Inspect the highlighted obligation and computed graph,
reject one impact with rationale, inspect the revised/superseded plan, then
approve the current plan to reach the proof certificate.

## Run the CLI golden path

Requires Python 3.11 or newer. The demo runtime uses only the standard library.
The workspace must be absent or empty.

```bash
PYTHONPATH=src python3 -m changeproof demo \
  --workspace /tmp/changeproof-demo \
  --database /tmp/changeproof-demo.sqlite3 \
  --approve-as "$USER"
```

The command exits non-zero if the executable check fails or an obsolete `30`
reference remains in the isolated workspace. `--approve-as` is the explicit
human authorization recorded before applying changes to that workspace; it
does not authorize production changes. Evidence is written to
`/tmp/changeproof-demo/proof_manifest.json`.

To run the reviewer flow from an existing checkout:

```bash
PYTHONPATH=src python3 -m changeproof review \
  --workspace /tmp/changeproof-review \
  --database /tmp/changeproof-review.sqlite3
```

Open `http://127.0.0.1:8000/`, inspect the cited obligation and eight diffs,
then enter a reviewer identity to authorize that exact plan. This applies only
to the isolated workspace and redirects to the resulting proof certificate.

Each impact can instead be rejected with reviewer identity and rationale. The
review agent produces a revised proposal and new snapshot hash; the rejected
snapshot remains viewable and is persisted as a rejected proposal revision.
Only the latest exact snapshot can subsequently be approved.

Run the repository tests with:

```bash
python3 -m pytest -q
```

On a host whose system `python3` is older than 3.11, create an isolated Python
3.12 environment with `uv` and run the same commands through it:

```bash
uv venv --python 3.12
uv sync --extra dev
uv run python -m pytest -q
```

The offline demo itself remains dependency-free. The optional AWS evidence sink
uses the separately declared `hosted` extra:

```bash
uv sync --extra dev --extra hosted
```

## ChangeProof on ChangeProof

Before any video, screenshot or hosted demo, ChangeProof scans this repository and
its hosting configuration against the cited M-SC controls:

```bash
PYTHONPATH=src python3 -m changeproof self-check --repo .
```

The command writes an ignored, locally generated manifest to
`.changeproof/self_compliance_proof.json`. It identifies frameworks checked,
file-hash evidence for each automated control and disclosed exceptions. This is a
self-assessment—not legal advice, certification, a penetration test, SOC 2 report
or independent audit. Public hosting and live uploads remain blocked.

## Build Week implementation boundary

Before July 13, the repository contained product research, architecture and
submission-planning documentation. The runnable Python package, synthetic lender
fixture, reviewer UI, governed approval flow, integrity checks, executable tests
and proof manifest were created during Build Week. Pre-existing BBB concepts
informed the design, but the demo neither imports nor requires BBB code or data.

Codex accelerated repository analysis, implementation, deterministic fixture and
test creation, adversarial review, documentation and end-to-end verification.
The entrant retained the product decisions: the single fictional-lender scope,
human approval boundary, evidence requirements, local-first architecture and
final acceptance of every change.

### Multi-agent Codex build

The primary Sol session decomposed and reviewed the architecture and final
integration. Terra implemented the exact-plan governance boundary; Luna built
integrity validation and adversarial tamper coverage. The primary session then
integrated, tested and accepted each increment. This mirrors ChangeProof itself:
specialized proposals, explicit boundaries, independent verification and a
human-controlled final decision. The dated record is in
[`docs/build-week/PROVENANCE.md`](docs/build-week/PROVENANCE.md).

## GPT-5.6 integration

When `OPENAI_API_KEY` is configured, ChangeProof uses the OpenAI Responses API
and `gpt-5.6-luna` for schema-constrained obligation extraction. It rejects any
citation that is not copied byte-for-byte from the source and any deadline not
supported by that quote. Model, call time, response ID, prompt/schema/source and
validated-response hashes are preserved in the proof lineage.

The proof manifest promotes extraction and drafting into first-class model
evidence records. Each record binds the phase, actual model or deterministic
provider, prompt version, schema version and validated response hash under its
own canonical SHA-256; the manifest also binds the combined evidence chain.

GPT-5.6 Terra also drafts a complete replacement proposal for each of the eight
artifacts. ChangeProof binds every proposal to a known fixture ID and path,
requires exact coverage, validates JSON/Python syntax and the 30-to-21 change,
then displays locally generated diffs. These r

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 63 recognized source files, 382 KB.
- Python (language) — detected in the code
- AI coding agent: Codex — evidence: config files committed to the repository

## Codebase structure (from repository index)

### Files (77 of 77)

```
.env.example
.gitignore
AGENTS.md
config/self_compliance_obligations.json
docs/ARCHITECTURE.md
docs/BUILD_WEEK_PLAN.md
docs/build-week/DEVPOST_ADDITIONAL_INFO.md
docs/build-week/DEVPOST_GUIDELINES.md
docs/build-week/DEVPOST_INTRODUCTION.md
docs/build-week/DEVPOST_PROJECT_PAGE.md
docs/build-week/DEVPOST_UPDATES_QUEUE.md
docs/build-week/M4_READINESS.md
docs/build-week/media/devpost-gallery/README.md
docs/build-week/MODEL_FEEDBACK.md
docs/build-week/PROVENANCE.md
docs/build-week/SESSION_FEEDBACK.md
docs/build-week/VIDEO_ACCEPTANCE.md
docs/build-week/VIDEO_SCRIPT.md
docs/CAPITAL_ADEQUACY_SCENARIO.md
docs/hosting/HOSTING_PLAN.json
docs/hosting/JUDGE_ACCESS_PLAN.md
docs/PRIOR_WORK_BOUNDARY.md
docs/PRIVACY.md
docs/PRODUCT_SPEC.md
docs/PROJECT_CHECKLIST.md
docs/RESEARCH_AND_RECOMMENDATION.md
docs/security/THREAT_MODEL.md
docs/self-compliance/OBLIGATIONS_REGISTER.md
docs/SUBMISSION_CHECKLIST.md
examples/fictional_lender/artifacts/backend/settings.py
examples/fictional_lender/artifacts/controls/complaint_control.json
examples/fictional_lender/artifacts/dashboard/labels.json
examples/fictional_lender/artifacts/operations/complaint_sop.md
examples/fictional_lender/artifacts/ownership/complaints.json
examples/fictional_lender/artifacts/policy/customer_complaints.md
examples/fictional_lender/artifacts/scheduler/escalation.json
examples/fictional_lender/artifacts/tests/test_complaint_sla.py
examples/fictional_lender/impacts.json
examples/fictional_lender/manifest.json
examples/fictional_lender/source/rbi_complaint_direction.txt
LICENSE
pyproject.toml
README.md
SECURITY.md
src/changeproof/__init__.py
src/changeproof/__main__.py
src/changeproof/ai.py
src/changeproof/batch.py
src/changeproof/compliance.py
src/changeproof/cost.py
src/changeproof/db.py
src/changeproof/discovery.py
src/changeproof/fixtures.py
src/changeproof/governance.py
src/changeproof/hosted.py
src/changeproof/integrity.py
src/changeproof/models.py
src/changeproof/repository.py
src/changeproof/review.py
src/changeproof/verifier.py
src/changeproof/workflow.py
tests/conftest.py
tests/test_adversarial.py
tests/test_ai.py
tests/test_compliance.py
tests/test_cost.py
tests/test_discovery.py
tests/test_fixtures.py
tests/test_governance.py
tests/test_hosted.py
tests/test_integrity.py
tests/test_models.py
tests/test_repository.py
tests/test_review.py
tests/test_verifier.py
tests/test_workflow.py
uv.lock
```

### Dependencies

- pyproject.toml: boto3@>=1.35,<2, pytest@>=8,<10

### Recent commits (newest first)

- docs: record final Devpost preflight
- docs: sharpen model feedback and formatting
- docs: add tier-specific model feedback
- docs: record session feedback and bug register
- docs: add Devpost additional info draft
- docs: normalize Devpost introduction wrapping
- docs: add verified Devpost screenshot gallery
- docs: sharpen Devpost project story
- docs: add Devpost introduction draft
- docs: record CLI feedback and public video
- docs: record public judge access
- chore: license and record release evidence
- build: validate AWS CPU release environment
- chore: ignore local secret directory
- docs: reconcile final submission gates
- docs: record final Priya demo master
- docs: add paced video v2 production assets
- docs: record final clean-clone rehearsal
- docs: validate narrated judge demo and hosting gate
- feat: ship enterprise mobile change control room

## Key source files (fetched from GitHub, selected and truncated for size)

### SECURITY.md

```markdown
# Security Policy

ChangeProof is pre-release demonstration software. The built-in reviewer is
localhost-only and uses synthetic data. Do not expose it publicly or process live
regulatory, customer, employee, secret, or production data.

## Supported surface

Only the current default branch is maintained. Report a suspected vulnerability
privately to the repository owner; do not place secrets, exploit details, customer
data, or credentials in a public issue. A public security contact will be added
before hosting or release. Until then, public hosting is prohibited.

## Security invariants

- Model output is untrusted and remains a proposal until explicit human approval.
- Citations, artifact paths, schemas, patches and proof payloads are validated and
  hash-bound before use.
- Application is confined to a new isolated workspace; symlinks and traversal are
  rejected.
- The API key is read from the environment, sent only to the fixed OpenAI HTTPS
  endpoint and never written to the database or proof.
- The offline deterministic path must remain complete and testable.

## Release checks

Run `python3 -m pytest -q`, `python3 -m compileall -q src tests`, the self-compliance
check, a tracked-file secret scan and a true fresh-clone rehearsal. Record actual
results in `docs/build-week/PROVENANCE.md`; never claim a control that was not run.

```

### AGENTS.md

```markdown
# AGENTS.md

## Project

ChangeProof turns external obligations into cited, reviewable, tested organizational changes.

## Product constraints

- Preserve source-to-change lineage for every recommendation.
- Never invent a citation, impacted artifact, approval, or verification result.
- Require explicit human approval before modifying authoritative artifacts.
- Never deploy to production or contact external parties automatically.
- Treat compliance output as decision support, not legal advice.
- Keep the Build Week golden path runnable with synthetic data and no private BBB infrastructure.

## Engineering conventions

- Keep user-facing answers short and to the point by default. Use only the detail needed to answer the request unless the user explicitly asks for depth.
- Prefer a small, testable vertical slice over broad platform work.
- Use UTC-aware timestamps.
- Keep secrets out of Git and provide `.env.example` for configuration.
- Add deterministic fixtures for the demonstration scenario.
- Record which functionality existed before and after the Build Week submission period.
- Maintain setup and judging instructions as the implementation evolves.

## Project ground rules

- Build one complete fictional-lender workflow before adding scenarios, integrations, roles, or dashboards.
- Treat every generated conclusion as a proposal until its source span, impact rationale, and reviewer state are visible.
- Keep the source document, impacted artifacts, diffs, approvals, verification output, and proof manifest connected by stable IDs or hashes.
- Use deterministic local fixtures for all demonstration data; never imply access to live regulatory, customer, or production systems.
- Make authoritative-artifact changes only in the isolated demo workspace and only after an explicit recorded approval.
- Do not claim a test, citation, impact, approval, deployment, or product capability unless it was actually produced in the working demo.
- Prefer a legible, reliable end-to-end flow over generalized AI, retrieval, graph, or SaaS infrastructure.
- Update `docs/PROJECT_CHECKLIST.md` and the BBB MLMS `project:changeproof` task register at each milestone with UTC time, commit, verification, and blocker.

## Devpost plugin cadence

- The Devpost Hackathons plugin is a planning and submission helper; the live Devpost rules remain authoritative.
- At project start, use `start-hackathon` and `hackathon-map` to confirm the flow and deadline.
- At each milestone and before any public claim, use `review-hackathon-rules` and `resources` to recheck requirements, credits, and submission expectations.
- Use `build-scope`, `build-prd`, `build-spec`, and `build-checklist` only to sharpen the approved golden path; do not let them expand scope.
- Use `build-project` while implementing the vertical slice. `find-hackathon` is unnecessary after OpenAI Build Week is selected.
- Use `prepare-submission` only after the demo is working. Use `submit-project` only after a final human re
[truncated — 2279 more characters]
```

### pyproject.toml

```
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "changeproof"
version = "0.1.0"
description = "Cited, reviewable, tested organizational change"
requires-python = ">=3.11"

[project.optional-dependencies]
dev = ["pytest>=8,<10"]
hosted = ["boto3>=1.35,<2"]

[tool.pytest.ini_options]
pythonpath = ["src"]
testpaths = ["tests"]

[tool.setuptools.packages.find]
where = ["src"]

```

### tests/conftest.py

```python
import pytest


@pytest.fixture(autouse=True)
def deterministic_openai_environment(monkeypatch):
    """Unit tests never spend API credits or depend on developer credentials."""
    monkeypatch.delenv("OPENAI_API_KEY", raising=False)
    monkeypatch.delenv("CHANGEPROOF_OPENAI_MODEL", raising=False)

```

### tests/test_models.py

```python
from datetime import datetime

import pytest

from changeproof.models import SourceDocument, content_hash, stable_id


def test_hash_and_id_are_deterministic() -> None:
    value = {"b": 2, "a": 1}
    assert content_hash(value) == content_hash({"a": 1, "b": 2})
    assert stable_id("src", value) == stable_id("src", {"a": 1, "b": 2})


def test_record_requires_utc_aware_time_and_valid_hash() -> None:
    with pytest.raises(ValueError, match="timezone-aware"):
        SourceDocument(
            id="src_1", title="Rule", jurisdiction="IN",
            content_sha256="a" * 64, created_at=datetime(2026, 7, 15),
        )
    with pytest.raises(ValueError, match="SHA-256"):
        SourceDocument(
            id="src_1", title="Rule", jurisdiction="IN", content_sha256="nope",
        )


def test_record_is_frozen() -> None:
    record = SourceDocument(
        id="src_1", title="Rule", jurisdiction="IN", content_sha256="a" * 64,
    )
    with pytest.raises(Exception):
        record.title = "Changed"  # type: ignore[misc]

```

### tests/test_verifier.py

```python
import sys

from changeproof.verifier import run_command, scan_residuals, verify_workspace


def test_residual_scan_reports_path_line_and_hash(tmp_path):
    (tmp_path / "policy.txt").write_text("deadline is 30 days\n", encoding="utf-8")
    matches = scan_residuals(tmp_path)
    assert [(match.path, match.line) for match in matches] == [("policy.txt", 1)]
    assert len(matches[0].line_sha256) == 64


def test_command_records_actual_success_and_failure(tmp_path):
    success = run_command(tmp_path, [sys.executable, "-c", "print('verified')"])
    failure = run_command(tmp_path, [sys.executable, "-c", "raise SystemExit(7)"])
    assert success.passed and success.exit_code == 0 and success.stdout == "verified\n"
    assert not failure.passed and failure.exit_code == 7
    assert len(success.stdout_sha256) == len(success.stderr_sha256) == 64
    assert success.started_at_utc.endswith("+00:00")


def test_workspace_pass_requires_test_success_and_no_residual(tmp_path):
    clean = verify_workspace(tmp_path, [sys.executable, "-c", "pass"])
    assert clean["passed"] is True
    (tmp_path / "stale.txt").write_text("old 30 day rule", encoding="utf-8")
    stale = verify_workspace(tmp_path, [sys.executable, "-c", "pass"])
    assert stale["passed"] is False

```

### tests/test_fixtures.py

```python
import json
from pathlib import Path

import pytest

from changeproof.discovery import discover_impacts, discover_obligation, load_expected_impacts
from changeproof.fixtures import FixtureIntegrityError, load_fixture


FIXTURE = Path(__file__).parents[1] / "examples" / "fictional_lender"


def test_computed_impacts_match_checked_in_oracle():
    load_fixture(FIXTURE)
    oracle = load_expected_impacts(FIXTURE)
    obligation = discover_obligation(FIXTURE)
    computed = discover_impacts(FIXTURE, obligation)
    assert len(computed) == 8
    assert len({item.artifact_id for item in computed}) == 8
    assert {(item.path, item.kind) for item in computed} == {
        (item["path"], item["kind"]) for item in oracle["impacts"]
    }
    assert obligation.path == oracle["citation"]["path"]
    assert obligation.quote == oracle["citation"]["quote"]
    assert all(item.evidence and item.rationale and item.dependency for item in computed)
    assert {item.kind for item in computed} == {
        "policy", "operations_sop", "control_register", "backend_sla_constant",
        "escalation_scheduler", "dashboard_label", "regression_test", "ownership_metadata",
    }


def test_fixture_detects_tampering(tmp_path):
    import shutil
    copied = tmp_path / "fixture"
    shutil.copytree(FIXTURE, copied)
    path = copied / "artifacts/policy/customer_complaints.md"
    path.write_text(path.read_text() + "tampered")
    with pytest.raises(FixtureIntegrityError):
        load_fixture(copied)

```

### tests/test_compliance.py

```python
import json
from pathlib import Path

import pytest

from changeproof.compliance import run_self_check, write_self_check
from changeproof.integrity import IntegrityError, verify_compliance_structure


ROOT = Path(__file__).parents[1]


def test_changeproof_runs_on_itself_and_binds_evidence(tmp_path):
    output = tmp_path / "self-proof.json"
    proof = write_self_check(ROOT, output)
    assert proof["overall_status"] == "passed_with_disclosed_exceptions"
    assert len(proof["control_results"]) == 12
    assert all(item["status"] == "passed" for item in proof["control_results"])
    assert all(item["evidence"] for item in proof["control_results"])
    assert json.loads(output.read_text(encoding="utf-8"))["proof_payload_sha256"] == proof["proof_payload_sha256"]


def test_self_check_detects_missing_control_marker(tmp_path):
    import shutil
    copied = tmp_path / "repo"
    shutil.copytree(ROOT, copied, ignore=shutil.ignore_patterns(".git", ".changeproof", "__pycache__"))
    policy = copied / "SECURITY.md"
    policy.unlink()
    proof = run_self_check(copied)
    result = next(item for item in proof["control_results"] if item["control_id"] == "SSDF-SECURITY-POLICY")
    assert result["status"] == "failed"
    assert proof["overall_status"] == "failed"


def test_compliance_structure_rejects_unknown_framework():
    with pytest.raises(IntegrityError, match="unchecked framework"):
        verify_compliance_structure({
            "frameworks_checked": [{"id": "known"}],
            "control_results": [{"control_id": "C1", "framework_id": "unknown", "status": "passed", "evidence": []}],
            "exceptions": [],
        })

```

### tests/test_discovery.py

```python
from pathlib import Path

from changeproof.discovery import apply_span_edits, discover_impacts, discover_obligation


FIXTURE = Path(__file__).parents[1] / "examples" / "fictional_lender"


def test_scanner_builds_evidence_spans_and_structural_references():
    obligation = discover_obligation(FIXTURE)
    impacts = discover_impacts(FIXTURE, obligation)
    assert obligation.old_deadline_days == 30
    assert obligation.new_deadline_days == 21
    assert all(
        (FIXTURE / impact.path).read_text(encoding="utf-8")[
            impact.evidence[0].start_offset:impact.evidence[0].end_offset
        ] == "30"
        for impact in impacts
    )
    references = {reference for impact in impacts for reference in impact.references}
    assert references == {"backend SLA constant", "complaint control", "complaints policy"}


def test_scanner_ignores_unrelated_files_without_obligation_terms(tmp_path):
    root = tmp_path
    (root / "source").mkdir()
    (root / "artifacts/backend").mkdir(parents=True)
    (root / "source/direction.txt").write_text(
        "Complaints must close within 21 calendar days.\n"
        "This replaces the previous 30-calendar-day requirement.\n",
        encoding="utf-8",
    )
    (root / "artifacts/backend/unrelated.py").write_text("PORT = 30\n", encoding="utf-8")
    assert discover_impacts(root) == []


def test_span_edit_changes_only_evidenced_offsets():
    text = "complaint SLA is 30 days; account 130 remains."
    from changeproof.discovery import EvidenceSpan
    start = text.index("30")
    span = EvidenceSpan(start, start + 2, 1, start + 1, "30", text)
    assert apply_span_edits(text, [span], "21") == (
        "complaint SLA is 21 days; account 130 remains."
    )

```

### tests/test_repository.py

```python
import pytest

from changeproof.db import connect
from changeproof.models import Event, SourceDocument, content_hash
from changeproof.repository import ImmutableRecordError, Repository


def source() -> SourceDocument:
    body = {"title": "Synthetic RBI circular", "jurisdiction": "IN"}
    return SourceDocument(
        id="src_fixture", content_sha256=content_hash(body), **body,
    )


def test_add_get_list_and_count_round_trip() -> None:
    repository = Repository(connect())
    record = repository.add(source())
    assert repository.get(SourceDocument, record.id) == record
    assert repository.list(SourceDocument) == [record]
    assert repository.count(SourceDocument.kind) == 1


def test_duplicate_identity_cannot_overwrite() -> None:
    repository = Repository(connect())
    repository.add(source())
    with pytest.raises(ImmutableRecordError):
        repository.add(source())
    assert repository.get(SourceDocument, "src_fixture").title == "Synthetic RBI circular"


def test_events_are_ordered_and_sequence_is_unique_per_aggregate() -> None:
    repository = Repository(connect())
    event_2 = Event(
        id="evt_2", aggregate_id="pkg_1", event_type="reviewed", sequence=2,
        payload={}, content_sha256="b" * 64,
    )
    event_1 = Event(
        id="evt_1", aggregate_id="pkg_1", event_type="created", sequence=1,
        payload={}, content_sha256="a" * 64,
    )
    repository.add(event_2)
    repository.add(event_1)
    assert [event.sequence for event in repository.events("pkg_1")] == [1, 2]
    with pytest.raises(ImmutableRecordError):
        repository.add(Event(
            id="evt_other", aggregate_id="pkg_1", event_type="duplicate", sequence=2,
            payload={}, content_sha256="c" * 64,
        ))

```

[51 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]