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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! What:
//! How long a push may show nothing before it is stopped: the environment variable that sets the deadline, its default,
//! the reading of a positive whole number of seconds, and the patience a push runs under.
//! Why:
//! `bounded_push.rs` runs and stops the push; the settings it reads do not use it, so they sit in a file of their own and
//! `bounded_push.rs` re-exports them for the callers that import them from there.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! const pushDeadline = (environment) => secondsVariable(environment, 'CLI_GIT_PUSH_DEADLINE_SECONDS') ?? 30_000;
//! ```
use cratedebug;
use ;
use Duration;
/// Tag used for diagnostics from this module.
const TAG: &str = "monochromatic-git-policy-cli";
/// Environment variable that sets the push deadline in whole seconds.
pub const PUSH_DEADLINE_VARIABLE: &str = "CLI_GIT_PUSH_DEADLINE_SECONDS";
/// How long a push with no connection to a remote open may go without any sign of work (the stall window) when the variable is
/// absent or unusable. Where no progress can be measured, it is how long the push may run in all.
/// Citation: no measurement or owner decision determines 30 seconds. The owner decided the rule, "Stop only on no progress
/// (Recommended)", and not the number. The journal of the commit service (read-only, 794 pushes that landed since 2026-10-20) holds
/// whole-push times, p50 3.5 s, p99 26.4 s, maximum 72.4 s, which include connected time and so are not a measure of silence
/// without a connection; no silence of a disconnected push is logged anywhere. The number is an open question for the owner
/// (`doc/planning/cli-git-shipped-limits-audit.md`, "Push stall window, 30 seconds").
pub const DEFAULT_PUSH_DEADLINE: Duration = from_secs;
/// What:
/// Read a positive whole number of seconds from one environment value.
/// Why:
/// A zero, negative, fractional, empty or non-text value is no setting at all,
/// never "no limit",
/// so a typo cannot remove a bound.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const seconds = Number(value); return Number.isInteger(seconds) && seconds > 0 ? seconds * 1000 : undefined;
/// ```
/// What:
/// Read a positive whole number of seconds from the child environment.
/// Why:
/// The last of repeated entries wins,
/// as in an environment block.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// positiveSeconds(env[name])
/// ```
pub
/// What:
/// The push deadline: the environment's value, or the default.
/// Why:
/// A person may need a longer deadline on a slow link or a shorter one on a flaky one.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const deadlineMs = secondsOf(env.CLI_GIT_PUSH_DEADLINE_SECONDS) ?? DEFAULT_MS;
/// ```
/// What:
/// How long a bounded child may take: a fixed time, or a time without any sign of work and without an open connection.
/// Why:
/// A slow push that keeps moving data is working and should finish, and one whose connection to a remote is open is waiting
/// for the remote and should wait too; one that shows nothing and holds no connection is stuck and should stop fast. A query has
/// no transfer to measure and keeps a fixed bound.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// type Patience = { kind: 'fixed'; ms: number } | { kind: 'progress'; stallMs: number };
/// ```
/// The patience of a push from the environment: the stall window.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// ({ kind: 'progress', stallMs: pushDeadline(env) })
/// ```
/// Remove exactly one trailing `\n` or `\r\n`, as the captured output of the incumbent does.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// output.endsWith('\n') ? output.slice(0, output.endsWith('\r\n') ? -2 : -1) : output
/// ```