1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! **How much room the TENANT has left**, as distinct from how large an object
//! this SERVER accepts.
//!
//! [`crate::Limits`] is the operator's: one set of numbers for the whole box,
//! the same for every namespace, and `max_object_bytes` is a wall around one
//! object. This is the other axis — one namespace's remaining plan, which is a
//! different number for every tenant, changes when they pay, and bounds what
//! they may ACCUMULATE rather than what one request may carry.
//!
//! # Why this exists at all
//!
//! git bytes and LFS bytes land on the same filesystem, are reported by the same
//! `Usage.Read` (as `pack_bytes` and `lfs_bytes`), and — this is the part that
//! made it urgent — are billed at the same `disk_gib_month` on monetize's price
//! list. Only one of them had a door. `gunnar_wire::receive_pack` has counted
//! pack bytes against a plan ceiling and cut the transfer mid-stream since
//! `9f948a2`; the LFS wire counted nothing. A tenant one byte under a 10 GiB
//! plan could open an upload session and put 8 GiB in it — under
//! `max_object_bytes`, so not refused — and then open another.
//!
//! > *"i believe if each user crosses its effective allowed space the operation
//! > should not be allowed"* — the ruling of 2026-09-07
//!
//! # The number is decided elsewhere, deliberately
//!
//! This crate does not know what a plan is, what monetize is, or what a tenant
//! holds on disk. It is handed a byte count and a sentence, exactly as
//! `gunnar_wire::PackCeiling` is, and for the same reason: the arithmetic that
//! produces them needs the signed entitlement fact and a walk of the namespace's
//! repositories, both of which live in `gunnar-server`. Putting it here would
//! drag the entitlement cache into the crate that serves `git-lfs-transfer`, and
//! then a community build could not compile without it.
//!
//! # Exact, with no slack — and that is a fact about LFS, not a preference
//!
//! `gunnar_server::entitlement::EntitlementSlot::pack_ceiling` gives a push
//! 6.25 % of slack because a pack's wire bytes and its stored bytes are
//! genuinely different numbers that nobody knows before the transfer: a thin
//! pack is completed server-side with bases the client never sent, and the
//! engine then stores the result compressed. **An LFS object has no such gap.**
//! `crate::store` stores objects RAW — measured, level-6 DEFLATE over real LFS
//! content came out at ratio 1.000 — and [`crate::VerifyingSink`] checks the
//! bytes against the declared size as they pass, so a client that declares 4 KiB
//! and sends 4 GiB is cut at the first byte past the declaration. Declared bytes
//! ARE the bytes that land. The ceiling can therefore be exact, and an exact
//! ceiling is the only kind a tenant can plan against.
use crate;
/// **A namespace's remaining room, and the sentence a tenant who runs out
/// reads.**
///
/// Two fields and no methods but one, because there is no policy here: the
/// policy is `gunnar-server`'s, which computed [`Allowance::bytes`] from the
/// signed fact's `caps["lfs_bytes"]` minus what the namespace holds, and wrote
/// [`Allowance::refusal`] naming the plan, the cap and the pay page. This type
/// is the number travelling to where the bytes are — the deliberate twin of
/// `gunnar_wire::PackCeiling`, which does the same job one wire over.