git-ents.gitmain
⌘K
foforge
outcome.rs94 lines · 3.5 KB · rusthistorycomment on this file
1//! `receive`'s gate policy (mandatory or advisory) and the outcome it
2//! reports: which verdict each proposed transition got, and whether the
3//! batch actually landed.
4
5use gix::refs::FullName;
6use gix_hash::ObjectId;
7
8use ents_gate::Verdict;
9
10/// Which of the two gate policies `receive.adoc` names governs one call:
11/// abort the whole batch on a failing verdict (`gate.mandatory-hosted`), or
12/// accept the write regardless and only annotate (`gate.advisory-local`).
13///
14/// The gate itself ([`ents_gate::verify`]) is one pure function evaluated
15/// identically either way (`gate.call-sites`); `Mode` is the policy
16/// [`crate::receive`] applies to a *failing* verdict, which is exactly the
17/// orchestration the development plan assigns to this crate — the gate
18/// crate never sees a `Mode`, and could not: it has no write path to gate.
19///
20/// # Examples
21///
22/// ```
23/// use ents_receive::Mode;
24///
25/// let mode = Mode::Advisory;
26/// assert_eq!(mode, Mode::Advisory);
27/// ```
28// @relation(gate.mandatory-hosted, gate.advisory-local, scope=file)
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum Mode {
31 /// The hosted policy: a failing verdict against any transition in the
32 /// batch aborts the whole batch before any ref is updated
33 /// (`gate.mandatory-hosted`).
34 Mandatory,
35 /// The local policy: every transition is written regardless of its
36 /// verdict; a failing verdict only annotates the result, never blocks
37 /// it (`gate.advisory-local`).
38 Advisory,
39}
40
41/// What happened to one [`crate::Proposal`]'s ref-transaction batch.
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub enum TxResult {
44 /// Every transition in the batch was written atomically.
45 Applied,
46 /// [`Mode::Mandatory`] aborted the whole batch before attempting a
47 /// write, because at least one transition's verdict failed
48 /// (`gate.mandatory-hosted`). See [`crate::Outcome::verdicts`] for
49 /// which one and why.
50 Refused,
51 /// The underlying store rejected the compare-and-swap: `name`'s
52 /// current value no longer matched the precondition read at
53 /// evaluation time — a genuine race, reported in the gate's own
54 /// vocabulary (`Requirement::AtomicCas`) as the gate crate's docs
55 /// anticipate for exactly this caller.
56 Rejected {
57 /// The ref whose precondition was stale.
58 name: FullName,
59 },
60 /// The batch introduced an object matching a previously recorded
61 /// redaction target; the whole batch was refused before any verdict
62 /// was even evaluated, so a redacted hole cannot be silently refilled
63 /// by re-pushing the same bytes (`receive.redaction-ingest`).
64 Redacted {
65 /// The offending object id.
66 oid: ObjectId,
67 },
68}
69
70/// The result of one [`crate::receive`] call: every transition's verdict,
71/// and what happened to the batch as a whole.
72///
73/// # Examples
74///
75/// ```
76/// use ents_receive::{Outcome, TxResult};
77///
78/// let outcome = Outcome {
79/// verdicts: vec![],
80/// result: TxResult::Applied,
81/// };
82/// assert_eq!(outcome.result, TxResult::Applied);
83/// ```
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct Outcome {
86 /// Each proposed transition's refname and the gate's verdict on it,
87 /// in proposal order. Present under both [`Mode`]s: mandatory callers
88 /// use it to see which refusal aborted the batch
89 /// (`gate.verdict-reason`); advisory callers render it to the user
90 /// regardless of [`Outcome::result`] (`gate.advisory-local`).
91 pub verdicts: Vec<(FullName, Verdict)>,
92 /// What happened to the batch.
93 pub result: TxResult,
94}