# Cluster E — Platform code docstrings

## Scope

All Python files in `netcanon/` EXCEPT those under
`migration/codecs/` (Cluster D's scope).  ~67 files:

```
netcanon/
  __init__.py + cli.py + other top-level (~3-5)
  api/                  (14 .py)
  collectors/           (5 .py)
  migration/canonical/  (9 .py — intent.py is the load-bearing one)
  migration/__init__.py + base + matrix + transforms
  models/               (8 .py)
  services/             (5 .py)
  storage/              (7 .py)
```

## Out of scope

* `netcanon/migration/codecs/` (Cluster D)
* `tests/` (Cluster F)
* `tools/` (developer utility scripts — light docstring audit only
  if surfaces are exposed; otherwise skip)
* `netcanon/templates/` (Jinja/HTML, not Python)
* `netcanon/_version.py` (auto-generated by setuptools_scm; skip)

## What to verify

1. **Module-level docstrings.**  Each module should have a
   docstring describing purpose + (for load-bearing modules) the
   public surface.  Per AGENTS.md doc-sync row:
   > A new route, endpoint, or public function in a module whose
   > top-of-file docstring enumerates contents (e.g.
   > netcanon/api/routes/migration.py, netcanon/services/
   > migration_pipeline.py) | The module docstring itself — if it
   > lists endpoints / phases / public surface, your addition
   > changes that list.
   Verify endpoint enumerations, phase lists, public-surface
   lists match current code.

2. **Class docstrings on Pydantic models.**  `intent.py` defines
   `CanonicalIntent`, `CanonicalInterface`, `CanonicalVRRPGroup`,
   `CanonicalIPv4Address`, etc.  Each should have a docstring
   describing role + (for the larger ones) the tier classification
   (Tier 1 / 2 / 3 per intent.py top-of-file convention).  Verify
   newer fields (v0.2.0 Wave A: `vrrp_groups`,
   `virtual_gateway_address`, `is_secondary`, etc.) are mentioned
   if the class has a field enumeration in its docstring.

3. **`CapabilityMatrix` + `UnsupportedPath` / `LossyPath` model
   docstrings** (under `models/migration.py` or similar).  Verify
   field descriptions match Pydantic validators.

4. **API endpoint docstrings.**  Each FastAPI route function
   should have a docstring describing the endpoint contract
   (URL, method, request/response shape, error cases).  Verify
   against the route decorator + Pydantic request/response models.

5. **Service-layer docstrings.**  `services/migration_pipeline.py`
   is FROZEN (per AGENTS.md hard rule).  Verify its module
   docstring states the freeze AND lists the frozen functions.
   Other services (sanitiser, collector wrappers) — verify
   docstrings match current behaviour.

6. **Collector docstrings.**  `collectors/paramiko_collector.py`
   was cited in the security-triage as the AutoAddPolicy path —
   verify the docstring explains the operator-as-trust-anchor
   threat model (relevant to anyone reading the file).

7. **Storage layer.**  `storage/file_store.py` enforces
   `MAX_CONFIG_SIZE`; verify the constant is documented + the
   rationale is in a comment or docstring.

8. **Models.**  `models/` contains Pydantic shapes used across
   API + services.  Verify field-level descriptions exist for
   contracts visible to operators (e.g. via OpenAPI schema gen
   from FastAPI).

9. **`cli.py` / entry-point docstrings.**  `pyproject.toml`
   declares `netcanon = "netcanon.cli:main"`.  Verify `main()`
   has a docstring usable as `--help` text.

## Methodology

* `Read` each in-scope file fully (or at least the
  module/class/function definitions).
* `Grep` for `@router.(get|post|put|delete|patch)` to enumerate
  API endpoints, cross-check against module docstring lists.
* `Grep` for `class .*\(BaseModel\)` to enumerate Pydantic models;
  verify each has a class docstring.

## Severity tagging

(Same as Cluster D.)

## Output format

Write to: `docs/docs-audit/2026-05-21/01-investigation-E.md`

```markdown
# Cluster E — Platform code docstrings

## Summary

## Per-area audit

### canonical/ (CanonicalIntent + related models)
* intent.py module docstring: verified / drift noted
* Class-level audit per canonical type: ...
* Tier annotations per class: ...
* Findings:

| # | Path:Line | Severity | Finding | Fix shape |

### api/ (FastAPI routes + dependencies)
* Endpoint enumerations in module docstrings: ...
* Per-endpoint docstring presence: ...
* Findings:

### services/ (migration_pipeline + sanitiser + others)
* Frozen-surface annotations: ...
* Findings:

### collectors/ (netmiko + paramiko)
### storage/
### models/
### Top-level (cli.py, __init__.py)

## Cross-cutting observations
```

## Constraints

* **READ-ONLY.**  Single output file.
* Hard rules from `AGENTS.md`.  ESPECIALLY:
  * `migration_pipeline.py` is FROZEN — if you find docstring
    drift there, flag clearly so Stage 2 only touches the
    docstring, never the signature.
  * "Real password hashes" rule — if `collectors/` shows any
    cleartext credential handling, flag for separate security
    review.
* Time budget: ~45-60 min.  Smaller than Cluster D by file count,
  but `intent.py` alone is load-bearing + dense.
