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
//! **A step may not advance the lineage its own conversation runs on**
//! (ARCH §3.3 *Environment*, `docs/DESIGN_LEARNING_LOOP.md` §3).
//!
//! The config lineage a conversation is born on holds everything that
//! governs it — `souls/*.md`, `providers.yaml`'s model and grant rows,
//! `facts.md`, the workspace skills. Two acts advance one: the operator's
//! `litany config`, and `litany proposal --accept`, which is the operator
//! agreeing to a proposal. Both are the *operator's*, and the learning
//! loop is built on that: a reviewer proposes onto a branch no lineage
//! points at, and acceptance is the veto's other half (§3 *One writer per
//! branch holds*).
//!
//! Nothing enforced it. A step with the shipped `bash` grant finds
//! `litany` on its PATH, writes a script, exports it as `$EDITOR` and
//! runs `litany config <workspace>` — and the lineage advances, souls,
//! grants, models and facts included, from inside the conversation those
//! very files govern (yog bl-baed, round-1 triage ruling 3). The
//! staged-proposal veto is walkable while that door is open, so it is
//! not a veto.
//!
//! **The marker already exists.** Every tool invocation carries
//! `LITANY_TOOL_ID` — the `tool_use.id` being executed — set by the
//! executor on every spawn since bl-e8d7, owed by a routing host on any
//! spawn it makes (ARCH §3.3). It is present exactly when a process is
//! a tool invocation of a running step, which is exactly the condition
//! these two verbs must refuse under, so nothing new is signalled and no
//! flag is added: the guard reads the signal that is already there.
//!
//! **The refusal names the lawful route**, because the agent that hits
//! it is trying to do something reasonable and the design has a place
//! for it: a step *proposes*, and an operator accepts.
//!
//! Read the marker where every other process-global is read — off
//! [`crate::cmd::Fx`], filled once at the binding (§3.4). Not
//! `std::env::var_os` inside the verb: the environment is per-process
//! and the test binary runs its beats in threads, so a sibling beat
//! setting the contract vars for its own run would decide whether an
//! unrelated `config` was refused (the bl-b5b1 reasoning, `Fx.conv_branch`).
use OsStr;
/// A lineage-advancing verb reached from inside a step — refused,
/// rendered inside the verb's uniform `litany <verb>: <error>` failure
/// line (§3.4).
/// Decline `act` when `tool_id` says this process is a tool invocation.
///
/// Set **and non-empty** is the test, the same reading
/// [`crate::prompt::inbox::resolve_cli_sender`] gives the other contract
/// variable: an exported-but-empty variable is an environment artifact,
/// not a claim to be one of those invocations.