Skip to content

docs: dedupe the project documents and add a task index - #39

Merged
kilianmc merged 1 commit into
devfrom
docs/dedupe-and-index
Aug 20, 2026
Merged

kilianmc merged 1 commit into
devfrom
docs/dedupe-and-index

Conversation

@kilianmc

Copy link
Copy Markdown
Owner

Cross-file deduplication and size reduction over the six documents that describe this project. Not the prose-verbosity trim — that stays deferred until the app is finished, per CLAUDE.md's own "docs deep clean" note. Rule applied throughout: trim status, keep rationale.

Docs only. No behaviour change, no version bump (matching #32).

Size

4218 → 3164 lines across all six documents (−25%). Most of the cut is in the private notes and the plan file (7 of its 8 planned PRs have shipped); CLAUDE.md's body is flat and it grew only by the index, because it is the sink every deduped fact drains into.

The index

New heading-anchored section at the top of CLAUDE.md, grouped by task — adding a migration, touching auth, changing the federated mount, promoting, dependencies, styling. Anchored to heading text, never line numbers; two line numbers already shifted during this work.

Contradictions fixed

Eight, each verified against the code rather than guessed. The one worth calling out was public and wrong in both files:

  • Grade comparability. CLAUDE.md and the README claimed V-scale, Font and French grades are directly comparable. server/domain/grades.py puts boulder in the 1000-band and rope in the 2000-band and raises CrossDisciplineError. So V5 and 7A compare; 6c+ is French rope and does not.
  • README called dev the default branch — main is.
  • CLAUDE.md pointed at server/app/domain/planner/; it is server/domain/.
  • The prose measure said 68ch; _layout.scss says 56ch.
  • The byte-identical-twin rule: the add/add-conflict half expired at the v2.0.0 promotion; the "inert until the next promotion" half stands.
  • A second site said "skip query-cache persistence in demo scope", implying it is fine elsewhere, against the blanket ban.

Two rules that were missing

  • Migrate production BEFORE promoting. A promotion deploys code and runs no migration, so a new mapped column would break every login.
  • The migrate.yml dispatch is handed to Kilian, not attempted — gh workflow run against production is correctly refused, and the connection strings live only in the GitHub environments.

Deduplication direction

Shared facts live in CLAUDE.md; the private notes keep one-line pointers, because those load before CLAUDE.md is read and the pointer is what sends a reader to it. Nothing moved from private to public. REPLAY_GRACE went the other way: the public file keeps the one-line constraint, the analysis moved private.

Review notes

Lightweight review is appropriate — docs, plus a comments-only change to migrate.yml (its diff touches no non-comment line, so YAML validity is unaffected).

Not independently re-read: all 465 changed lines of CLAUDE.md. The consequential and checkable claims were verified against the code; the rest rests on the drafting pass.

🤖 Generated with Claude Code

Cross-file deduplication and size reduction across CLAUDE.md, the README and
the private notes. NOT the prose-verbosity trim, which stays deferred until the
app is finished. Rule applied throughout: trim status, keep rationale.

- CLAUDE.md gains a heading-anchored index grouped by task, so a coder starting
  a PR can find one rule without reading 2000 lines. Anchored to heading text,
  never line numbers, which rot.
- Eight contradictions resolved against the code rather than guessed. The
  significant one was public: CLAUDE.md and the README both claimed V-scale,
  Font and French grades are directly comparable. server/domain/grades.py puts
  boulder in the 1000-band and rope in the 2000-band and raises
  CrossDisciplineError, so V5 and 7A compare but 6c+ does not.
- README no longer calls dev the default branch (main is), and points at
  CLAUDE.md instead of restating the testing policy, CI internals and auth
  internals. Headings de-versioned so anchors stop rotting.
- The byte-identical-twin rule's add/add half is marked expired; the
  "inert until the next promotion" half stands.
- REPLAY_GRACE keeps the operative one-line constraint here; the analysis moved
  to private notes.
- The query-cache persistence ban keeps its rule and loses its expired reason.
  The hazard is that localStorage belongs to the shell, not PR #6 sequencing.
  It does not constrain the outbox.
- Adds two rules that were missing: migrate production BEFORE promoting, and
  hand the migrate.yml dispatch to Kilian rather than attempting it.
- migrate.yml is comments only: drops the revision numbers that went stale at
  0003, keeps the ref-vs-environment distinction.

No version bump, matching #32.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
climb-trainer Ready Ready Preview Aug 20, 2026 9:19am

@kilianmc
kilianmc merged commit d706d95 into dev Aug 20, 2026
5 checks passed
@kilianmc
kilianmc deleted the docs/dedupe-and-index branch August 20, 2026 09:20
kilianmc added a commit that referenced this pull request Aug 20, 2026
…dropped (#40)

Production now holds real accounts, and the v3.0.0 promotion is next. These are
the rules and guards for not losing them.

- tests/test_migrations_additive.py: fails if a migration's upgrade() would
  destroy app_user. Two arms — Alembic ops (drop_table/drop_column) and raw SQL
  in op.execute/sa.text strings (DROP COLUMN, DROP TABLE, DELETE FROM, TRUNCATE,
  SET NOT NULL). Both scoped to the module-level upgrade(); downgrade() bodies
  are legitimately destructive and ignored, which 0003 proves as a standing
  control. Inspects string literals only — dynamically built SQL escapes it, and
  the docstring says so rather than implying a guarantee.
- server/admin.py: create-invite and set-password now print the target host and
  database and require it typed back, with --yes as the only bypass. devseed had
  this and admin did not, while admin is the one documented as run against
  production. set-password confirms before the getpass prompt.
- server/db.py: target_host_and_database() is now the single redaction point;
  devseed delegates to it, so there is one copy of that logic, not two. Host and
  database only — never user, password, query string or full URL.
- CLAUDE.md: minting an invite is a LOCAL command and must never become a
  workflow step (create-invite prints the plaintext code and Actions logs on this
  public repo are world-readable); app_user migrations are additive-only; never
  alembic downgrade against production, and the absent downgrade action in
  migrate.yml is load-bearing; snapshot the Neon branch before a production
  upgrade (retention is plan-dependent, read it from the dashboard); a promotion
  is not complete until the applied revision is read back.
- migrate.yml: comment recording why there is no downgrade option.

Also restores security checklist item 14 ("2FA still enabled on GitHub, Vercel,
Neon and Cloudflare"), which PR #39 deleted along with duplicating item 13's
opening line, leaving the list 12 → 13 → 13 → 15. Recovered verbatim from
9d8dca5. Out of this PR's scope, but a silently dropped security item should not
wait for a later PR.

No version bump; the promotion that follows takes this to 3.0.0.

Co-authored-by: Kilian Mateo <13885240+kilianmc@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 7add15d7 Deployed Aug 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant