From 604c8407eee5f59c177ee942c91d3b8a87ef9035 Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Tue, 31 Mar 2026 13:20:22 -0400 Subject: [PATCH] =?UTF-8?q?style:=20avoid=20"the",=20use=20"our"=20?= =?UTF-8?q?=E2=80=94=20writing=20style=20rule=20+=20sweep?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 121 +++++++++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 5d88801..036bb79 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,12 +3,12 @@ ## Project Setup **IMPORTANT**: Before starting any work on a repository: -1. Check for a `CLAUDE.md` file in the repository root +1. Check for a `CLAUDE.md` file in our repository root 2. Check for a `CLAUDE.md` file in parent directories (we often work across repos on localhost) 3. Read and follow all instructions in those files 4. These project-specific instructions override default Claude Code behavior 5. Look for conventions around commits, testing, code style, and workflows -6. If working across multiple repositories, respect the conventions from each repo's CLAUDE.md +6. If working across multiple repositories, respect our conventions from each repo's CLAUDE.md ## Commit Attribution @@ -29,34 +29,34 @@ Commit message here. ## Database Migrations (Alembic) -When adding new columns or modifying the database schema: +When adding new columns or modifying our database schema: 1. **Backup SQLite first**: `cp data/remarkbox.sqlite data/remarkbox.sqlite.bak` -2. **Add the column to the model** in `remarkbox/models/` +2. **Add our column to our model** in `remarkbox/models/` 3. **Generate migration**: `alembic -c development.ini revision --autogenerate -m "description"` -4. **Clean up migration**: Remove extra autogenerated changes, keep only the new field +4. **Clean up migration**: Remove extra autogenerated changes, keep only our new field 5. **Run migration**: `alembic -c development.ini upgrade head` ## Ticket System -Tracked issues live in `docs/tickets/`. Start every session by reading the index: +Tracked issues live in `docs/tickets/`. Start every session by reading our index: ```bash cat docs/tickets/index.md ``` -- **Index**: `docs/tickets/index.md` is the master list. Always update it when creating or closing tickets. +- **Index**: `docs/tickets/index.md` is our master list. Always update it when creating or closing tickets. - **Numbering**: Sequential. Next number = highest existing + 1. - **Workflow**: Set status to `in-progress` when starting, `resolved` when done. Update `index.md` to match. -- **New tickets**: If you find a bug or get a feature request, create a new ticket file and add it to the index. +- **New tickets**: If you find a bug or get a feature request, create a new ticket file and add it to our index. - **Sources**: Tickets reference community threads from `meta.remarkbox.com` and `faq.remarkbox.com` by UUID. ## Remarkbox API and Python Client Remarkbox has a JSON API at `/api/v1/`. You can use it to read and write threads -on production as timehexon. The session cookie is saved at `~/.config/remarkbox/cookies.txt`. +on production as timehexon. Our session cookie is saved at `~/.config/remarkbox/cookies.txt`. -### Quick start (from a Python script in the scratchpad or inline) +### Quick start (from a Python script in our scratchpad or inline) ```python import os, sys @@ -153,7 +153,7 @@ c.reply(node_id, data="

HTML reply

", source_format="html") ### Authentication -The saved cookie should work indefinitely. If it expires, you'll need an OTP: +Our saved cookie should work indefinitely. If it expires, you'll need an OTP: ```python c.login("timehexon@unturf.com") @@ -163,26 +163,26 @@ c.verify("timehexon@unturf.com", "123456") ### Functional test -Run the full idempotent test suite against production: +Run our full idempotent test suite against production: ```bash env/bin/python remarkbox/api/functional_test.py https://my.remarkbox.com meta.remarkbox.com timehexon@unturf.com --name timehexon ``` -This exercises all endpoints and updates the journey thread with results. +This exercises all endpoints and updates our journey thread with results. ## Superuser (Global Moderator) -Users with `is_superuser=True` can moderate across all namespaces. This bypasses the -normal namespace-scoped `is_moderator()` check. The admin UI is at `/topsecret/users` +Users with `is_superuser=True` can moderate across all namespaces. This bypasses our +normal namespace-scoped `is_moderator()` check. Our admin UI is at `/topsecret/users` where you can promote/demote users by email. -Bootstrap the first superuser via the database script: +Bootstrap our first superuser via our database script: ```bash env/bin/python scripts/promote_superuser.py --ini development.ini --email timehexon@unturf.com ``` -After that, use the web UI at `/topsecret/users` or the existing topsecret admin pages +After that, use our web UI at `/topsecret/users` or our existing topsecret admin pages (all guarded by `@super_fly_required` which checks `is_superuser`). Admin client methods: @@ -194,7 +194,7 @@ c.admin_recent_nodes(days=7) # recent nodes network-wide ## Terminology In all user-facing text, marketing, legal documents, and UI labels, use **"machine learning"** -instead of "AI". The term "AI" should not appear in Remarkbox copy. Internal code comments +instead of "AI". Our term "AI" should not appear in Remarkbox copy. Internal code comments and technical references (e.g., "OpenAI-compatible endpoint") are fine. Third-party brand names like "UncloseAI" are also unchanged. @@ -210,7 +210,7 @@ IP reputation (disabled post count), content length anomalies. - `spam.hard_threshold = 0.8` -- reject with 403 - `spam.soft_threshold = 0.5` -- allow but set `approved=False` (held for moderation) -**Thread creation rate limit**: 1 new thread per 7 minutes per user/IP via the API. +**Thread creation rate limit**: 1 new thread per 7 minutes per user/IP via our API. This does not affect browser users or replies. **Spam hunting scripts** (require superuser cookie): @@ -234,13 +234,13 @@ python scripts/spam/disable_spam.py node-uuid-1 node-uuid-2 ## Operation Voyeur -**All comms are public** from 2026-03-29. Assume every terminal session and output is observed. NEVER display secrets to stdout. NEVER pass secrets as CLI args. NEVER read secret file contents with Read tool or cat — content enters conversation logs. **Path is fine. Content is not.** Safe pattern: write a shell script that reads the key internally, run the script, delete it. +**All comms are public** from 2026-03-29. Assume every terminal session and output is observed. NEVER display secrets to stdout. NEVER pass secrets as CLI args. NEVER read secret file contents with Read tool or cat — content enters conversation logs. **Path is fine. Content is not.** Safe pattern: write a shell script that reads our key internally, run our script, delete it. ## Production Rules -**NEVER run direct SQL or raw database commands on production.** No `sqlite3`, no `UPDATE`, no `DELETE`, no direct file edits on the production database. Ever. If the API doesn't support what you need, add the endpoint first, push it, then use the client. +**NEVER run direct SQL or raw database commands on production.** No `sqlite3`, no `UPDATE`, no `DELETE`, no direct file edits on our production database. Ever. If our API doesn't support what you need, add our endpoint first, push it, then use our client. -**ALL production changes go through the API client.** Use `RemarkboxClient` with the saved cookie at `~/.config/remarkbox/cookies.txt`. This ensures authentication, audit trails, and proper ORM handling. +**ALL production changes go through our API client.** Use `RemarkboxClient` with our saved cookie at `~/.config/remarkbox/cookies.txt`. This ensures authentication, audit trails, and proper ORM handling. **tmux-hosts is read-only.** You may use `tmux-hosts` to read logs, check processes, and investigate issues. You may NOT use it to modify data, run SQL, edit files, or restart services. @@ -253,23 +253,23 @@ c.disable_node(node_id) # sqlite3 /opt/remarkbox/my.remarkbox.com.sqlite "UPDATE rb_node SET disabled=1 WHERE id='...'" ``` -If a moderation operation is not yet supported by the API, the correct workflow is: -1. Add the endpoint to `remarkbox/api/views.py` -2. Add the method to `remarkbox/api/remarkbox_client.py` +If a moderation operation is not yet supported by our API, our correct workflow is: +1. Add our endpoint to `remarkbox/api/views.py` +2. Add our method to `remarkbox/api/remarkbox_client.py` 3. Push, wait for deploy -4. Use the client +4. Use our client ## Deployment Status -After pushing, check if the deploy is live by hitting the version endpoint: +After pushing, check if our deploy is live by hitting our version endpoint: ```bash curl -s https://my.remarkbox.com/api/v1/version # {"version": "5a10e15"} ``` -Compare the returned commit hash against `git rev-parse --short HEAD` to confirm -the latest code is deployed. +Compare our returned commit hash against `git rev-parse --short HEAD` to confirm +our latest code is deployed. You can also check GitLab pipeline status: @@ -281,7 +281,7 @@ curl -s "https://git.unturf.com/api/v4/projects/engineering%2Fremarkbox%2Fremark # https://git.unturf.com/engineering/remarkbox/remarkbox/-/pipelines ``` -The pipeline status will show `"status":"success"` when deployment is complete. +Our pipeline status will show `"status":"success"` when deployment is complete. ## Proxy Architecture @@ -322,28 +322,28 @@ Client → DNS (CNAME or A → 142.93.73.64) ### Key rules -- **CNAME domains MUST have explicit blocks on the proxy.** Without a block, - they fall through to the MPS on-demand TLS catch-all and route to the wrong +- **CNAME domains MUST have explicit blocks on our proxy.** Without a block, + they fall through to our MPS on-demand TLS catch-all and route to our wrong backend. This caused a 5-day outage (see `docs/postmortem-2026-02-25-ssl-outage-caddy-acme.md`). -- **The proxy owns TLS for proxied domains.** The origin server does not need - (and cannot obtain) ACME certs for domains whose DNS points to the proxy. -- **Static sites (www, remarkbox.com) are served directly from the proxy.** - Their content lives at `/opt/www/remarkbox` on the proxy server, deployed +- **Our proxy owns TLS for proxied domains.** Our origin server does not need + (and cannot obtain) ACME certs for domains whose DNS points to our proxy. +- **Static sites (www, remarkbox.com) are served directly from our proxy.** + Their content lives at `/opt/www/remarkbox` on our proxy server, deployed from `~/git/www.remarkbox.com` via CI. -- **origin.remarkbox.com bypasses the proxy.** Its DNS points directly to +- **origin.remarkbox.com bypasses our proxy.** Its DNS points directly to 162.243.167.224. Use it for SSH access and direct backend testing. ## Capability-Driven Presentation Follow Russell Ballestrini's capability-driven presentation practice (russell.ballestrini.net/capability-driven-presentation/). A page need not look -identical across all browsers. Accommodate what the user's browser can do: +identical across all browsers. Accommodate what our user's browser can do: -1. **Single canonical URI** — one URI serves the content. +1. **Single canonical URI** — one URI serves our content. 2. **Consistent content** — regardless of viewer capabilities. 3. **Graceful enhancement/degradation** — use available capabilities to enhance presentation. -### The `js-only` / `