summaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-12 12:14:40 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-12 16:36:54 +0200
commit17c06bc23252929af13f4361c4a6300ee76a0c51 (patch)
tree0f6cc4e0e3680ac253a88ccad580e97019abf77f /CLAUDE.md
parentc8462c6060ccd2cccb305edcd64ef12a675f2f58 (diff)
downloadmeshbay-17c06bc23252929af13f4361c4a6300ee76a0c51.tar.gz
docs: AV13–AV15, and two lessons from how they were found
AV13 the mail gate, AV14 the MHP audience and the hub's own identity, AV15 the shape check on the unauthenticated blocklist endpoints. §13.5b also records the auto-block threshold as an open decision rather than a defect. Two lessons, both about tests. A fixture narrower than production tests the fixture — and when it writes down *why* it has to be narrow, that is a bug report nobody filed. Two test helpers described the federation defects accurately, in comments, while routing around them. And a global's state is not a given, in a test least of all. One assertion — that a refusal never logs the address — took three attempts, each passing alone and failing in the full run, for three different reasons: caplog saw nothing because the app configures logging, then a handler saw nothing because an earlier test raised the logger's level, then because `disabled` was left True. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4YmK41VsEURWFdop4EEeT
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md23
1 files changed, 22 insertions, 1 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 4e29feb..516228f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -122,7 +122,7 @@ that produced it.
| Looking for | Read |
|---|---|
| What a label means (`C1`, `H3`, `NS6`, `T3`, `C5b`, `W2`, `E9`, `F1`, `AV4`, …) | `docs/MESHBAY_DESIGN.md` §13 |
-| What one member can cost the others (`AV1`–`AV12`) | §13.5b — the newest category, and the one the first three reviews had no question for |
+| What one member can cost the others (`AV1`–`AV15`) | §13.5b — the newest category, and the one the first three reviews had no question for |
| Trust model, and what the project may and may not claim | §2 |
| Identity, devices, admission, recovery, the keypair bundle | §3 |
| Cryptography, key hierarchy, the group and chat envelopes | §4 |
@@ -148,6 +148,27 @@ These are about working on the tree rather than about the design:
interface, for the web and the app alike; `packages/meshbay-client/scripts/
sync-ui.js` copies it (`npm run sync-ui`) and CI fails if the copy drifts —
**never edit `packages/meshbay-client/ui/` by hand**
+- **A test fixture narrower than production tests the fixture — and when it
+ writes down *why* it has to be narrow, that is a bug report nobody filed.**
+ `test_federation.py` built its MHP envelopes by hand without an `aud`, and
+ `test_public_groups_toggle.py` signed its own token with a comment saying
+ `_issue_mhp_token` "binds `_hub_sk_pem` at import time, before the lifespan
+ loads it, so it cannot be used from a test", and another saying PyJWT
+ rejects a token carrying `aud` when decode is given none. Both observations
+ were exactly right. Between them, MHP could not complete a single
+ authenticated request between two real hubs, and the hub announced itself as
+ `meshbay.org` whatever it was configured as — for a month, with the suite
+ green. When a test has to route around the code to run, the thing it routed
+ around is the finding. Federation's tokens now come from the real issuer
+
+- **A global's state is not a given, in a test least of all.** One assertion —
+ that a refusal never logs the address — took three attempts: `caplog` saw
+ nothing because the app configures logging, then a handler on the module's
+ own logger saw nothing because an earlier test had raised its level, then
+ because `logger.disabled` was left True. Each version passed alone and
+ failed in the full run. Pin what you depend on (level, `.disabled`,
+ `logging.disable`) or assert on a value instead of on a side effect
+
- **A blocking call in an async handler is the whole instance's problem.**
`mail._send` is `smtplib` with a ten-second timeout, and it was called
straight from four handlers: while the MTA thought about it, nothing else was