|
|
`_do_file_request` read `tr` as a boolean. Present meant "this is a leased
transfer, skip the leaseless ceiling", and nothing asked whether this node had
ever granted such a lease — `slots.touch(tr)` was called beside it and its
answer, `False` if it is not granted, was discarded. So any non-empty string
bought the whole library with no ceiling of any kind: not the per-member cap,
not the node-wide one, not the leaseless bound that exists to bound a client
claiming to be browsing. The queue held only the clients that chose to wait.
`_lease_of` decides it now, and the three answers differ on purpose:
- **granted**, and of *this* session — served, and touched so the sweeper
does not reclaim a transfer that is plainly moving. The session is checked
as well as the id, because touching another connection's lease refreshed
its idle timer.
- **queued** — refused with `lease_not_granted`, on the upload path too,
before anything reaches the operator's disk. A member reading while queued
is the cap not applying.
- **unknown** — bounded by the leaseless ceiling rather than refused. That is
also what a reconnect looks like from here, where the session's leases died
with the old connection and the client is re-opening them, and it leaves
the residual §5.5 already states: a client that lies gets that bound's
worth of files at a time, not the group. Noted once per connection so the
residual is visible rather than merely documented.
Nothing changes for the shipped client: the transfer store awaits
`lease.acquire()` before it reads a byte, so the refused case is one it never
enters. §5.5 gains a paragraph saying the node decides which of the two a
request is — the document described the accounting without ever saying it was
enforced, which is how it came not to be.
`test_lease_enforcement.py` drives the real handlers over a real index; six of
its nine cases fail against the previous source, each on the property.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UMxEQadpzPkYLFf5CYKhpW
|