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
//! **The role's grant, read where litany writes it** (round-1 triage ruling 3,
//! bl-52b7): what `providers.yaml` says the calling agent's role may call.
//!
//! litany's grant gate is one line (its `prompt/dispatch/tool_step/permit.rs`):
//! a role may call a tool that is **in its `tools:` grant OR injected by the
//! host**. The `||` is the whole story. yog's injection was the second half
//! unconditionally — `clients` declared for every agent of every role — so any
//! role could widen itself by loading, and a role's grant bounded nothing that
//! a machine advertised. Measured: a **compactor**, whose grant is empty by
//! litany's own template and whose deletion-only confinement its
//! `docs/PRINCIPLES.md` states as a guarantee, had `bash` refused correctly by
//! that gate, then called `clients {"op":"load"}` and made thirty arbitrary
//! shell calls on an enrolled machine, inside the engine's own git worktrees.
//!
//! **The ruling: a grant is a grant.** `clients` is part of it, not injected
//! beside it — so a role that is not granted `clients` is declared nothing at
//! all, its loaded set included, and an empty grant is empty. The injection
//! stops being an escape hatch from the law litany states and becomes a thing
//! the law governs.
//!
//! Two facts, each read from its single existing home; yog stores neither.
//!
//! 1. **The role** is litany's dispatch commit subject, `dispatch: <role>
//! [<agent-id>]` (its ARCH §2.5, `prompt/role.rs`: *"a child agent's role
//! lives in its dispatch commit subject … no sidecar role table"*). A root
//! agent's subject lacks the prefix, and roots are workers — the same
//! default litany's own reader applies, not a case of its own.
//! 2. **The grant** is `roles.<role>.tools` in the `providers.yaml` of the
//! config that **governs** this agent (§9.4's own derivation, the one every
//! other yog surface asks), read through §9.4's block grammar so the
//! picker, the fork composer and this reader cannot disagree about what a
//! config file says.
//!
//! **Every failure is an empty grant, and that is fail-closed.** A workspace
//! that is not there, a repository git will not read, a role the file does not
//! declare, a `tools:` line that is not the flow sequence litany writes: each
//! answers "this role is granted nothing", which declares nothing. The
//! opposite default — treating an unreadable config as full trust — is the
//! thing this ball is about.
use Path;
use crate;
use crateAGENT_REF_PREFIX;
use crate;
/// Workspace subdirectory holding the bare repository (litany ARCH §2.2).
const REPO_DIR: &str = "repo.git";
// The agent's **branch** is `agents/<id>`, not the bare id (litany ARCH §2.3),
// and both reads below address the branch — so the prefix comes from
// `git_tree`, the module that already enumerates that namespace, rather than
// from a second spelling here.
/// Subject prefix of a child's dispatch commit (litany ARCH §2.5).
const DISPATCH_PREFIX: &str = "dispatch: ";
/// The role every root agent resolves — litany's own default, read from yog's
/// one home for it ([`WORKER_ROLE`]), which the §8.6 birth grant writes the
/// same list of.
use crateWORKER_ROLE as WORKER;
/// The tools `agent`'s role is granted in `workspace`. Empty for every reason
/// a grant cannot be read — see the module doc.
/// The role recorded in the dispatch commit that founds `agent`'s branch, or
/// [`WORKER`] when there is none — a root, whose subject lacks the prefix.
///
/// The `--grep` is anchored on the exact `[<agent>]` tail, so only the agent's
/// *own* dispatch commit matches and never a descendant's `[<agent>-<sub>]`;
/// exactly one commit per branch carries it, so `-n 1` is the whole answer.
/// litany's own reader is `prompt::role::derive`, which is private to a crate
/// that exposes only `cmd` — so the pattern crosses as text, exactly as the
/// engine-act names do.
/// The role a dispatch subject names, or `None` for any other subject.