AGENTS.md@infrastructure/publishing/static_site · git:20261006.d465449 · 2026-10-06 · sha256 88793a2114bfe75d

AGENTS.md@infrastructure/publishing/static_site git:20261006.d465449A

Immutable. This exact content never changes and is served at /api/v1/blob/88793a2114bfe75d.

# `infrastructure/publishing/static_site/`

Deploy generated static sites to GitHub Pages, Cloudflare Pages, or Netlify.

## Public API

```python
from infrastructure.publishing.static_site import (
    SiteHosting,
    SiteDeployConfig,
    SiteDeployResult,
    GitHubPagesAdapter,
    CloudflarePagesAdapter,
    NetlifyAdapter,
    STATIC_SITE_ADAPTERS,
    get_adapter,
)
```

### `SiteHosting` enum

```python
class SiteHosting(str, Enum):
    GITHUB_PAGES = "github_pages"
    CLOUDFLARE_PAGES = "cloudflare_pages"
    NETLIFY = "netlify"
```

### `SiteDeployConfig`

| Field | Default | Notes |
| --- | --- | --- |
| `hosting` | required | `SiteHosting` value |
| `site_dir` | required | Local directory of built static files |
| `project_name` | required | Used as site / repo / project identifier |
| `dry_run` | `True` | No network calls when `True` |
| `branch` | `"gh-pages"` | GitHub Pages only |
| `production` | `False` | Netlify: promote to production deploy |
| `removal_plan` | `None` | GitHub Pages: exact destination-bound obsolete-source diff |
| `reviewed_plan_sha256` | `None` | Explicit approval of that exact current removal plan |
| `removal_quarantine_dir` | `None` | Retained directory outside the source/destination for recoverable removals |

`dry_run=True` is the default at every layer — accidental imports cannot trigger
real deployments.

GitHub Pages preserves destination-only and immutable publication evidence.
Obsolete previously managed source requires an exact reviewed removal plan;
unreviewed stale source prevents a push. Quarantine, rollback and parity limits
are documented in [`publication-removals.md`](../../../docs/guides/publication-removals.md).

### `SiteDeployResult`

Returned by every adapter: `success`, `hosting`, `url`, `deploy_id`, `error`.

### Adapters

| Class | Provider | Credential env |
| --- | --- | --- |
| `GitHubPagesAdapter` | GitHub Pages | `GITHUB_TOKEN` |
| `CloudflarePagesAdapter` | Cloudflare Pages | `CLOUDFLARE_API_TOKEN` |
| `NetlifyAdapter` | Netlify | `NETLIFY_AUTH_TOKEN` |

All adapters share the same interface: `deploy(config: SiteDeployConfig) -> SiteDeployResult`.

### Registry

```python
STATIC_SITE_ADAPTERS: dict[SiteHosting, type[...]]

adapter = get_adapter(SiteHosting.GITHUB_PAGES)
result = adapter.deploy(config)
```

## Files

| File | Purpose |
| --- | --- |
| `__init__.py` | Re-exports public symbols |
| `models.py` | `SiteHosting`, `SiteDeployConfig`, `SiteDeployResult` |
| `github_pages.py` | `GitHubPagesAdapter` |
| `cloudflare_pages.py` | `CloudflarePagesAdapter` |
| `netlify.py` | `NetlifyAdapter` |
| `registry.py` | `STATIC_SITE_ADAPTERS` dict + `get_adapter()` |

## Tests

```bash
uv run pytest tests/infra_tests/publishing/test_static_site.py -v
```

## See also

- [`README.md`](README.md)
- [`../AGENTS.md`](../AGENTS.md) — publishing module overview