Loading libraries from Gitea…
diff --git a/docs/standards.md b/docs/standards.md
index ccea720..0067ffc 100644
--- a/docs/standards.md
+++ b/docs/standards.md
@@ -3,40 +3,123 @@
The house standards every Rethink Studios project follows. They keep our code
consistent, readable, and predictable across the whole suite.
-## File hygiene
+## Files and style
-- Files end with a **single trailing newline** (LF / Unix line endings).
-- **No trailing whitespace** on any line.
+- Files end with a **single trailing newline** (LF / Unix line endings), and
+ carry **no trailing whitespace** on any line.
+- **4 spaces** for indentation by default. Respect language norms — TS/JS use
+ **2 spaces**, Go uses **tabs** — and when editing an existing file, follow that
+ file's existing indentation.
+- **flake8 clean**, max line length **120**. **Type hints** on public functions.
-## Indentation
+A well-formed module — module docstring, type hints, lowercase-start docstring:
-- **4 spaces** by default.
-- Respect language norms: TS/JS use **2 spaces**, Go uses **tabs**.
-- When editing an existing file, follow that file's existing indentation.
+```python
+"""async key/value store backed by a single json file"""
-## Docstrings and comments
+from pathlib import Path
-- Public functions get a **docstring**. Style: **lowercase-start, no trailing
- period**.
-- Keep inline comments minimal — prefer docstrings. Use an inline comment only
+
+def load_state(path: Path) -> dict[str, str]:
+ """read the json state file, returning an empty dict if it's missing"""
+ if not path.exists():
+ return {}
+ return _read_json(path)
+```
+
+flake8 tells you the moment you drift — keep the tree clean:
+
+```text
+$ flake8
+./aiokv/store.py:14:80: E501 line too long (96 > 79 characters)
+./aiokv/store.py:22:1: F401 'json' imported but unused
+./aiokv/store.py:31:5: E303 too many blank lines (3)
+```
+
+!!! tip "Run it locally"
+ Wire the shared config into an alias so every project lints the same way:
+ `alias flake8='flake8 --config ~/.config/flake8'` (max line 120). See the
+ [Workflow](workflow.md#handy-shell-setup) page.
+
+## Documentation
+
+- Public functions get a **docstring** — **lowercase-start, no trailing period**.
+- Keep inline comments minimal; prefer docstrings. Use an inline comment only
where the code is genuinely complex.
- Each module/file states its scope and purpose via a **module docstring**
(header string) — **not** a license or copyright header.
+- Every library and project has a **README** with the install line, what it does,
+ and a usage example.
-## READMEs
+=== "Do"
-Every library and project has a defined **README** covering:
+ ```python
+ def mask_secret(value: str, keep: int = 4) -> str:
+ """mask all but the last ``keep`` characters of a secret"""
+ if len(value) <= keep:
+ return "*" * len(value)
+ return "*" * (len(value) - keep) + value[-keep:]
+ ```
-- the install line,
-- what it does,
-- a usage example.
+=== "Don't"
-## Linting and types
+ ```python
+ # Masks a secret. <- license-header-style noise, capitalized, trailing period
+ def mask_secret(value, keep=4): # no type hints
+ # loop over the chars and hide them
+ return "*" * (len(value) - keep) + value[-keep:] # crashes if short
+ ```
-- **flake8 clean**, max line length **120**.
-- **Type hints** on public functions.
+## Quality and error handling
-## Error handling
+**Fail loud** — never swallow exceptions. Catch the **specific** exception and
+**log** it; don't paper over failures with a bare `except`.
-- **Fail loud** — never swallow exceptions.
-- Catch the **specific** exception, and **log** it.
+=== "Do"
+
+ ```python
+ import logging
+
+ log = logging.getLogger(__name__)
+
+
+ def fetch(url: str) -> bytes:
+ """fetch ``url``, logging and re-raising on failure"""
+ try:
+ return _client.get(url).content
+ except TimeoutError:
+ log.warning("fetch timed out: %s", url)
+ raise
+ ```
+
+=== "Don't"
+
+ ```python
+ def fetch(url):
+ try:
+ return _client.get(url).content
+ except Exception:
+ pass # swallowed — the caller has no idea anything broke
+ ```
+
+When something does break, a loud failure gives you a real traceback to act on:
+
+```python-traceback
+Traceback (most recent call last):
+ File "run.py", line 42, in