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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! The **attempt** — one fork of a conversation from one point in its history
//! (VISION §5 V2, the Counterfactualist rung; DESIGN §5.1 #32, §11 rail).
//!
//! *"A pinned notch offers Fork from here: a goal composer seeded empty,
//! firing the ordinary fork with the pinned commit as ref."* That is the
//! whole gesture, and it is **one** gesture: an attempt. A **cohort** — V2's
//! ×N, the parallel candidates an operator compares — is N attempts fired
//! from one notch, and nothing anywhere records that they belong together.
//! Membership is [derived](crate::rail::cohort) from the notch each child
//! hangs on and the ref each forked off, both already on V1's cards, so
//! `N == 1` and `N > 1` are not two paths: they are one path walked once and
//! walked N times.
//!
//! **This is why there is no fan verb, no fan registry and no winner field.**
//! A gesture that fired "the whole fan" would have to name the fan, and a name
//! is a stored fact that the refs already imply. Firing the ordinary fork N
//! times leaves N ordinary `ops.jsonl` rows (§4.2) — N committed execution
//! facts — which is strictly more provenance than one row for N would be.
//!
//! **The upstream verb already exists** (litany bl-a693, in the pin since `=0.0.6`):
//! `litany dispatch <role> <ws> <parent> --goal <text> --from <ref>
//! [--pin <dest>=<src>]`. litany's own words: *"`--from <ref>` is not a second
//! kind of dispatch … the flag reaches the existing `fork_point` field … and
//! changes nothing else"* — so yog composes an argv and adds no mechanism.
//!
//! **The three fire-time controls are three real parameters of that argv**,
//! never a fourth thing yog invents (VISION V2.2, "yog policy made visible"):
//!
//! - **config branch** is the fork point itself (`--from`). One control with
//! two kinds of value — the pinned commit ("from here", a fork with
//! ancestry) or `config/<name>` (a clean start, provenance only) — which is
//! VISION V1.3's ruling verbatim: *"'Clean vs fork' is one spawn gesture
//! with one parameter — the fork point."*
//! - **model** is the **role** (`<role>`). litany resolves a model from
//! `roles.<name>.{provider,model}` in the `providers.yaml` of the config
//! lineage governing the fork point, read at that lineage's head, and from
//! nowhere else. So the roles a ref declares, **with the model each names**,
//! are read at that ref ([`roles_at`]): the model shown at the point of choice
//! cannot lie, because yog is reading the very file the run will resolve
//! against. Giving an attempt a model no config declares is a config write
//! — §9.4's [`PickModel`](crate::boundary::Action::PickModel) — not a
//! dispatch flag, and pretending otherwise would be capability theater.
//! - **skills** are pins (`--pin skills/<name>/SKILL.md=<pool>/<name>/SKILL.md`).
//! litany's pin is documented as *"standing context a caller (a frontend, an
//! operator) pins without rewriting the goal or authoring a config commit"*,
//! and the shipped worker manifest composes `order: skills/**`, so a pinned
//! skill reaches assembled context by the config's own glob. The pool is the
//! world's `$LITANY_HOME/skills` ([`skills_root`]) — the same directory the
//! agent's own `load_skill` tool copies out of, so a pin names exactly what
//! the agent could have loaded for itself.
//!
//! **Composing the choice is the seat's** (bl-7cc8). The ×N control, the
//! fork-point list and the skill-pool listing were derived here and reached
//! nothing: `Action::Fork` carries one attempt by ruling (§8.5) and fires N
//! times, and no §8.5 reply carries an offer. They are gone; what stays is what
//! the argv itself needs.
//!
//! **Read-only by construction** (VISION §4.10, bl-2b8c). An attempt forks the
//! *conversation* repo and nothing else; project-mutating attempts need
//! §4.10's isolation and binding (yog bl-8746) and are not reachable from
//! here. Nothing in this module can touch a project worktree.
use ;
pub use ;
/// The litany subcommand an attempt is (ARCH §3.4).
const DISPATCH: &str = "dispatch";
const GOAL: &str = "--goal";
const FROM: &str = "--from";
const PIN: &str = "--pin";
/// The skills pool, under the world's `$LITANY_HOME` — and the destination
/// prefix a pinned skill lands at in the child's worktree. One constant,
/// because they are one name: the pin reproduces the pool's own layout.
pub const SKILLS_DIR: &str = "skills";
/// The one file of a skill directory a pin carries: its instructions. A pin's
/// destination is one path, so a skill's `references/**` stay where the
/// agent's own `load_skill` can still fetch them whole.
const SKILL_FILE: &str = "SKILL.md";
/// One attempt's fire-time overrides — everything that varies between the
/// candidates of a cohort. The goal, the workspace and the dispatching parent
/// do not vary (they are what makes the candidates comparable), so they are
/// not here: they ride the [`Fork`](crate::boundary::Action::Fork) action
/// beside this.
/// One attempt, addressed: the candidate's overrides plus the three facts the
/// whole cohort shares (where, whose history, what for) and the world pool its
/// pins are drawn from. Owned and whole, so [`argv`] is a pure function of one
/// value and the executor carries no second parameter list to keep in step.
/// The argv one attempt fires: `litany dispatch <role> <ws> <parent> --goal
/// <goal> --from <ref> [--pin skills/<s>/SKILL.md=<pool>/<s>/SKILL.md]…`.
///
/// **The goal is passed verbatim** — the same rule the start flow's fire keeps
/// (§3.3, bl-6920): what an operator wrote is what the model reads, unmutated.
/// The pin sources are absolute, so a child spawned in any cwd resolves them.
/// One skill's `<dest>=<src>` pin spec. The destination mirrors the pool's own
/// layout, so a pinned skill and a `load_skill`-loaded one land at the same
/// path and the manifest's `skills/**` glob sees both.