# Auth Posture Alignment Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use
> superpowers:subagent-driven-development (recommended) or
> superpowers:executing-plans to implement this plan task-by-task. Steps
> use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Reconcile `CLAUDE.md`, `docs/REQUIREMENTS.md`, and `docs/ARCHITECTURE.md` with the auth work that landed in `main` on 2026-06-23, and add a loud `AUTH_DISABLED` startup warning so a misconfigured production deploy fails loudly.

**Architecture:** Docs-only + one 6-line `__main__.py` edit + three skills addenda. No code paths change; the auth code already in `main` is the source of truth.

**Tech Stack:** Markdown, Python `logging`, existing `cyclone.auth.deps.AUTH_DISABLED` flag.

**Spec:** [`docs/superpowers/specs/2026-06-23-cyclone-auth-posture-alignment-design.md`](../specs/2026-06-23-cyclone-auth-posture-alignment-design.md)

---

## File structure

Modified files:

- `CLAUDE.md` (3 lines: 7, 97, 182)
- `docs/REQUIREMENTS.md` (3 NFR / scope lines + §11 R-1 row + §6.1 SP24 row)
- `docs/ARCHITECTURE.md` (2 lines: 16, 703 + 1 new "Auth" subsection + migrations table note)
- `backend/src/cyclone/__main__.py` (startup warning when `AUTH_DISABLED`)
- `.superpowers/skills/cyclone-tests/SKILL.md` (addendum)
- `.superpowers/skills/cyclone-api-router/SKILL.md` (addendum)
- `.superpowers/skills/cyclone-spec/SKILL.md` (addendum)

## Task 0: Mark spec in implementation

- [ ] Spec header `Status: Draft, awaiting user sign-off` → `Status: Approved (in implementation on sp24-doc-posture-alignment)`.

## Task 1: `CLAUDE.md`

- [ ] Line 7 — replace "Local-only by design: binds to `127.0.0.1`, no auth, no internet exposure." with the v1 posture: "Local-only by design: binds to `127.0.0.1`, requires login (auth boundary is HTTP; file-system protection unchanged), no internet exposure."
- [ ] Line 97 — update SP numbering to reflect "SP numbers are used through **SP22**; **SP23** is the Ubuntu+Docker fork (awaiting user decision); this increment is **SP24**."
- [ ] Line 182 — replace the "Local-only by design. The backend binds to `127.0.0.1`, has no auth…" bullet with the new posture (login required; auth boundary is HTTP; SQLCipher + Keychain unchanged; don't add internet exposure).

## Task 2: `docs/REQUIREMENTS.md`

- [ ] Line 36 — replace "Local-only on purpose: binds `127.0.0.1`, no auth, no internet exposure, single operator, single machine, one trading partner (Colorado Medicaid, currently)." with the v1 posture.
- [ ] Line 39 — replace "Threat model: a process on the same host. No second party to authenticate; no second host to harden against." with the new threat model (process on same host + HTTP-layer login; SQLCipher + Keychain handle file-system threats; SP23 changes the model to LAN).
- [ ] Line 154 (NFR-1) — replace "no auth, no API key" with "login required (bcrypt + HttpOnly session cookie; first admin bootstrapped from env vars `CYCLONE_ADMIN_USERNAME` + `CYCLONE_ADMIN_PASSWORD`); dev/test escape hatch via `CYCLONE_AUTH_DISABLED=1`."
- [ ] §11 R-1 row — change "**Open** — addressed only if/when SP23 ships." to "**Closed by SP24** — auth shipped via the merge of `origin/main` on 2026-06-23 (commits `a25504b`..`39ae988`); SP24 reconciled the docs to match. SP23 still covers the LAN-bind / Docker / RBAC product fork."
- [ ] §6.1 — add an SP24 row pointing at this plan + the spec.

## Task 3: `docs/ARCHITECTURE.md`

- [ ] Line 16 — replace "has no authentication because the threat model is a stolen or imaged drive, not a remote attacker." with the new posture.
- [ ] Line 703 — replace "Multi-user / multi-host — no auth, no LAN-bind, no Docker, no reverse proxy. The operator is one person, the host is one machine. (SP23 fork if this changes.)" with the new posture (login required; SP23 covers LAN-bind / Docker / RBAC fork).
- [ ] Add a new "### Auth" subsection under §5.1 listing the `cyclone.auth/` package contents and the `matrix_gate` dependency contract.
- [ ] Migrations table — add a note that 0013 + 0014 are auth migrations and explain the renumbering on `claims-unique-fix` (0013/0014 → 0015/0016) to keep the auth migrations at the front.

## Task 4: `backend/src/cyclone/__main__.py`

- [ ] After `bootstrap.run()`, check `cyclone.auth.deps.AUTH_DISABLED` and emit a `WARNING` via `logging.getLogger("cyclone")` if True. The warning text must include the words "AUTH_DISABLED" and "dev only" so a misconfigured production deploy is greppable from logs.

## Task 5: Skills addenda

- [ ] `cyclone-tests` — add a paragraph noting the conftest's `AUTH_DISABLED` flip is mandatory context for any new test.
- [ ] `cyclone-api-router` — add a paragraph noting every router needs `Depends(matrix_gate)` and the role matrix is in `cyclone.auth.permissions`.
- [ ] `cyclone-spec` — add a paragraph noting the spec template's "threat model" example needs to be auth-aware (don't say "no second party to authenticate" any more; reference this SP as the reference pattern).

## Task 6: Verification

- [ ] `grep -nE 'no auth|no authentication|no second party' CLAUDE.md docs/REQUIREMENTS.md docs/ARCHITECTURE.md` returns no false-positive matches.
- [ ] `cd backend && .venv/bin/python -c "import cyclone.__main__"` doesn't crash.
- [ ] `cd backend && .venv/bin/python -c "import cyclone; from cyclone.auth import deps; print(deps.AUTH_DISABLED)"` prints `False` (default).
- [ ] `cd backend && CYCLONE_AUTH_DISABLED=1 .venv/bin/python -c "from cyclone.auth.bootstrap import run; run(); from cyclone.auth.deps import AUTH_DISABLED; print(AUTH_DISABLED)"` prints `True` (env var flips the flag).