# CLAUDE.md — `tftio-org-gdocs`

Local notes for this crate. The **authoritative** design doc is
[`docs/plans/org-gdocs.md`](../../docs/plans/org-gdocs.md) (architecture, the
DI/EI/OVR invariants, and the per-task execution journal). Workspace rules in the
root `CLAUDE.md` and `REPO_INVARIANTS.md` apply unchanged.

## What this crate is

`org-gdocs push|pull|clean|open|auth` syncs an org file with a Google Doc. Org is
the single source of truth; Docs is a comment-collaboration surface. The Rust
binary owns *all* logic (projection, the Google client, anchoring, file
writeback); `elisp/org-gdocs.el` is a thin shell that shells out and reads the
result. User-facing docs live in `README.org`.

## Local invariants the compiler can't enforce

- **s-expressions on every surface we own both ends of** (A5). The CLI↔Emacs result
  envelope (`envelope.rs`/`sexp.rs`) and the `** Sync State` block (`syncstate.rs`)
  are sexps, *never* JSON. JSON is confined to forced boundaries: the Google API
  wire format (inside the generated `google-docs1`/`google-drive3` crates — we only
  touch the typed structs) and the OAuth `credentials.json` / `token.json`. Our own
  config is TOML. Adding a `serde_json::json!` request body or a JSON envelope is a
  defect.
- **The body is sacrosanct (DI-2).** Everything above `* GDOC_METADATA` is preserved
  byte-for-byte; the *only* sanctioned body mutation is idempotent `:CUSTOM_ID:`
  insertion (`custom_id.rs`). Writeback is `verbatim-body ++ regenerated-machine-region`
  (`orgfile.rs`). Every orchestration has a byte-for-byte body assertion.
- **Stateless (DI-3).** No DB, no sidecar — all state is the org file (+ OAuth token
  cache). Don't add process-global caches that survive a run.
- **Comments: read + resolve only (DI-4).** Never `comments.create`; map anchors to a
  section or document-level, never a character offset (DI-5), with a quoted-text
  fallback (`comments.rs`).
- **Panic-ban + `missing_docs = deny`** are on with no opt-out (EI-2/EI-6): no
  `unwrap`/`panic!`/indexing in non-test code; every public item documented. `anyhow`
  only at the binary edge; env reads only via `EnvInputs::from_env()` (EI-5/OVR-4).

## Layout

`lib.rs` (module registry + `TOOL_SPEC`), `main.rs` (thin edge), `cli.rs`,
`config.rs`, `error.rs`. Pure cores: `custom_id` (P2), `project` (P3), `syncstate`
(P5), `comments_meta` (P6), `comments` (Q1), `orgfile` (P1). Effects: `auth`,
`google/{client,docs,drive,utf16}` (F4–F6/P4). Orchestration shells: `push` (P7),
`pull` (Q2), `clean`/`open` (Q3).

## Tests (OVR-3 tiers)

Offline unit tests + `mockito` request/response shape tests run in CI. End-to-end
push/pull are `#[ignore]` live tests (`tests/live_push.rs`, `tests/live_pull.rs`)
needing real OAuth — run manually. `tests/fixtures/full-featured.org` is the shared
fixture (offline `fixture_projection.rs` + the live tier). Run gates with `just ci`
and `clippy --all-targets -D warnings` (nursery must be clean too).
