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
//! **The cut is re-made at every step boundary, not only at the fork**
//! (ARCH §3.3, §2.2 follow-the-tip; bl-37cd).
//!
//! [`super::derive`] cuts an agent's `descriptions/**` to its role's
//! grant, read from the config commit, at the dispatch commit (§2.3
//! step 2). Under fork-is-the-freeze that was the whole story: the
//! commit the cut came from could not move. Under follow-the-tip
//! (bl-403b) it moves at every step boundary, and the cut did not — so
//! a tip that *widens* a role's grant left the agent calling a tool
//! nothing in its tree describes, and a tip that *revokes* one left a
//! convincing schema on disk for a tool its wire array no longer
//! declares. That second shape is the failure the cut exists to close
//! (yog bl-55b1, `super`'s module docs) reappearing one config edit
//! later.
//!
//! **The refresh is the cut, re-run.** No second mechanism and no
//! change-detection: [`super::recut`] is idempotent and total — it
//! drops nothing when nothing is ungranted and checks out the grant
//! unconditionally — so "has the followed commit moved?" is not a
//! question this module asks. It re-cuts, and lets **git** answer
//! whether anything moved, by whether the cut dirtied `descriptions/`.
//! That is the general path with empty inputs (every unchanged
//! boundary), never a special case, and it needs no record of which
//! commit the tree was last cut from — a second home for a fact the
//! tree already carries.
//!
//! **It re-cuts but does not re-decline.** [`super::derive`] refuses a
//! grant the config commit does not describe, and that refusal is the
//! *fork's*: it lands before a branch, worktree or inbox exists. At a
//! boundary the agent already exists, and killing a running
//! conversation because an operator's edit made `providers.yaml` and
//! `descriptions/**` disagree is the very failure class follow-the-tip
//! was ruled in to fix (§2.2 — the workspace whose roles moved onto a
//! dead provider row). So the undescribed tool is simply not in the
//! tree, `tools::compose`'s intersection drops it exactly as it drops
//! any absent schema, and the operator hears an §2.11 notice naming the
//! commit, the role and the tool.
//!
//! **It commits, and it commits BEFORE the read-state capture.** The
//! wire reads descriptors off the worktree (`dispatch::tools`), but
//! replay re-assembles against `meta.json`'s `commit` (§2.10), so a
//! refresh that only touched the worktree would put bytes on the wire
//! that no replay of that step could reproduce. Committing ahead of the
//! capture keeps the read state honest — the same shape and the same
//! moment as the boundary's other landing acts, the inbox drain and the
//! child-result interpretation (§2.11 *delivery is a commit landing
//! ahead of the model call*).
//!
//! **A compactor is unaffected by construction**, which matters because
//! the compaction landing reads *deletions after the dispatch commit* as
//! the pass's product (§2.6): a compactor's grant is the empty built-in
//! pair (§2.7) and its fork already dropped every descriptor, so the
//! re-derivation drops nothing, commits nothing, and cannot manufacture
//! a nomination.
use DESCRIPTIONS_DIR;
use ;
use crateError;
use cratenotice;
use crateGitRunner;
use Path;
/// Re-derive `worktree`'s descriptor tree against the boundary's
/// resolved `grant`, committing when the derivation moved it. Answers
/// whether it committed.
pub
/// The grant, narrowed to what the config commit actually describes,
/// noticing every tool it drops.
///
/// [`super::derive`] refuses such a grant instead, and that refusal is
/// the **fork's**: it lands before a branch, worktree or inbox exists.
/// At a boundary the agent already exists, and killing a running
/// conversation because an operator's edit left `providers.yaml` and
/// `descriptions/**` disagreeing is the very failure class
/// follow-the-tip was ruled in to fix (§2.2 — the workspace whose roles
/// moved onto a dead provider row, and every conversation on it kept
/// refusing). So the undescribed tool is simply absent from the tree,
/// `dispatch::tools::compose`'s intersection drops it exactly as it
/// drops any absent schema (§3.3 *not present == not available*), and
/// the operator hears an §2.11 notice naming the commit, the role and
/// the tool.
///
/// The narrowing reaches the check-out only, never [`drop_ungranted`],
/// which reads the grant whole. **Revoked** is a tool the tip removed
/// from the role's `tools:` — it is no longer in the grant at all, so
/// the whole-grant drop takes its stale copy, which is the revoke half
/// of this ball. **Undescribed** is a different fact: the tool is still
/// granted and the commit merely fails to describe it, which is a
/// config fault, not a revocation. Deleting the tree's copy on a fault
/// would destroy the only surviving description on the strength of a
/// disagreement; the notice says so and the bytes stay.