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
97
98
99
100
101
102
103
104
105
106
//! Derived availability: whether a scope may reach an upstream target right now,
//! evaluated from facts that are owned elsewhere (#206).
//!
//! Availability is the question a caller actually asks — *can I use this model?* —
//! and it is not a field anybody stores. It is derived, every time, from six
//! independent things: what the catalogue carries, what the scope enabled, what
//! the provider account is entitled to, what policy permits, what discovery
//! observed, and how this replica's own requests have been going. This module
//! defines what that derivation *is*, so the slices that will feed it cannot each
//! invent their own answer. The decision it implements is ADR 0038.
//!
//! # The shape of the domain
//!
//! | Module | Answers |
//! | --- | --- |
//! | [`refs`] | what a verdict is about: a tenancy scope, an upstream target, and the credential a decision was made against |
//! | [`dimensions`] | the five single-valued inputs, kept separate because they have five different authorities |
//! | [`discovery`] | the sixth input: observations, how complete they were, when they expire, and what each one establishes |
//! | [`verdict`] | the five states, the closed reason vocabulary, and the dimension that decided |
//! | [`index`] | the immutable index, the precedence ladder over it, and last-known-good retention |
//!
//! # Four properties everything else rests on
//!
//! **Absence of evidence is `unknown`, never `available` and never `denied`.** An
//! index that failed to load, a key nobody has observed, a policy that could not
//! be decided, and a listing that broke halfway all produce
//! [`AvailabilityState::Unknown`]. Defaulting such a case open would route traffic
//! at a target nobody established exists; defaulting it closed would let one
//! failed refresh deny a fleet. `unknown` is routable only where the scope
//! explicitly *chose* it: [`Availability::permits_attempt`] refuses a
//! [`DecidedBy::NoRecord`] verdict, so an index that is empty or missing a key
//! permits nothing, and every other `unknown` is one the [`index`] ladder let past
//! its enablement and policy rungs.
//!
//! **A discovery outage costs freshness, not access.** The last definitive
//! positive observation is retained across non-definitive ones, so an outage
//! degrades to `available (last_known_good)` and then to
//! [`AvailabilityState::Stale`] at expiry. Nothing here can fail a readiness probe
//! or empty a catalogue: the index is a value carried beside a snapshot, and
//! `/readyz` does not read it.
//!
//! **Uncertainty is never silently upgraded.** Only definitive evidence raises
//! certainty. A partial listing does not become a denial, an indeterminate probe
//! does not become an availability, an expired positive becomes `stale` rather
//! than staying `available`, and an expired *negative* becomes `unknown` rather
//! than remaining a denial.
//!
//! **Verdicts are per scope, and bounded by type.** Every record is keyed by
//! [`ScopeRef`], so one tenant's evidence can never decide another's — an observed
//! look is filed under the key it names, and a declared one is refused if it names
//! another — and every
//! field of [`Availability`] is an enum, a bool, or a timestamp — there is nowhere
//! to put a provider error body, a policy expression, a credential, or free text.
//! The one place free text is allowed is
//! [`DiscoveryObservation::detail`], which is for the log line and has no path
//! into a verdict.
//!
//! # What this slice deliberately is not
//!
//! Contract only, in the same sense as [`crate::backends`],
//! [`crate::convergence`], and [`crate::status`]: nothing here is constructed by
//! `serve`.
//!
//! - no provider is polled and no observation is persisted — the discovery
//! mechanism and its storage are their own slices, and this module only says what
//! an observation *means*;
//! - no request is enforced against a verdict, `/v1/models` is unchanged, and
//! readiness is unchanged;
//! - an index is derived and projected onto a [`ConfigSnapshot`] as a value
//! alongside the config ([`ConfigSnapshot::with_availability`]); it is never
//! desired-state truth and cannot add a model, namespace, or credential to what
//! a deployment declares;
//! - [`AvailabilityIndex::evaluate`] is a pure function over data already in hand,
//! so wiring it into the request path later still performs no catalogue,
//! discovery, Postgres, Redis, or `SecretStore` lookup per request.
//!
//! [`ConfigSnapshot`]: crate::state::ConfigSnapshot
//! [`ConfigSnapshot::with_availability`]: crate::state::ConfigSnapshot::with_availability
// The availability facade. `allow(unused_imports)` for the same reason the
// desired-state and convergence facades carry it: this is a binary crate, and a
// re-export nothing in the tree names yet is still part of the contract the
// discovery, catalogue, and enforcement slices build against.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;