worktree-controller 1.30.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- worktree_controller/__init__.py +3 -0
- worktree_controller/activation_layout.py +483 -0
- worktree_controller/branch_retirement.py +1865 -0
- worktree_controller/canonical_refresh.py +150 -0
- worktree_controller/canonical_transition.py +324 -0
- worktree_controller/cleanup_attempts.py +442 -0
- worktree_controller/cleanup_evidence.py +75 -0
- worktree_controller/cleanup_recovery.py +912 -0
- worktree_controller/cli.py +1907 -0
- worktree_controller/controller.py +1974 -0
- worktree_controller/convergence.py +893 -0
- worktree_controller/delivered_closeout.py +928 -0
- worktree_controller/disposable.py +677 -0
- worktree_controller/environment.py +1038 -0
- worktree_controller/frozen_recovery.py +291 -0
- worktree_controller/git_backend.py +682 -0
- worktree_controller/governance.py +365 -0
- worktree_controller/hardlinks.py +294 -0
- worktree_controller/integration_cleanup.py +92 -0
- worktree_controller/integration_conflict.py +117 -0
- worktree_controller/integration_retry.py +526 -0
- worktree_controller/keyed_document_scope.py +162 -0
- worktree_controller/lifecycle.py +8992 -0
- worktree_controller/lifecycle_history.py +358 -0
- worktree_controller/lifecycle_observation.py +234 -0
- worktree_controller/metadata_codec.py +1694 -0
- worktree_controller/metadata_relocation.py +131 -0
- worktree_controller/models.py +546 -0
- worktree_controller/mount_diagnostics.py +324 -0
- worktree_controller/multiple_cleanup_recovery.py +730 -0
- worktree_controller/namespace_migration.py +1412 -0
- worktree_controller/native_session_recovery.py +171 -0
- worktree_controller/owner_actions.py +34 -0
- worktree_controller/policy.py +333 -0
- worktree_controller/preservation.py +983 -0
- worktree_controller/preserved_cleanup.py +849 -0
- worktree_controller/publication_execution.py +361 -0
- worktree_controller/reconciler.py +430 -0
- worktree_controller/recovery_guidance.py +205 -0
- worktree_controller/registration_backfill.py +166 -0
- worktree_controller/registration_prune.py +391 -0
- worktree_controller/rendering.py +179 -0
- worktree_controller/resource_admission.py +1736 -0
- worktree_controller/retirement_adapters.py +130 -0
- worktree_controller/retirement_execution.py +234 -0
- worktree_controller/semantics.py +459 -0
- worktree_controller/session.py +505 -0
- worktree_controller/session_admission.py +265 -0
- worktree_controller/source_cleanup.py +515 -0
- worktree_controller/source_preservation.py +692 -0
- worktree_controller/source_recovery.py +592 -0
- worktree_controller/store.py +1228 -0
- worktree_controller/tool_cli_contract.json +1791 -0
- worktree_controller/transaction_scope.py +876 -0
- worktree_controller/writer_lease.py +662 -0
- worktree_controller/writer_session.py +887 -0
- worktree_controller-1.30.4.dist-info/METADATA +3149 -0
- worktree_controller-1.30.4.dist-info/RECORD +61 -0
- worktree_controller-1.30.4.dist-info/WHEEL +4 -0
- worktree_controller-1.30.4.dist-info/entry_points.txt +5 -0
- worktree_controller-1.30.4.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,1907 @@
|
|
|
1
|
+
"""Command-line interface for worktree-controller."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from . import __version__
|
|
12
|
+
from .branch_retirement import (
|
|
13
|
+
authorize_branch_retirement,
|
|
14
|
+
branch_retirement_executions,
|
|
15
|
+
branch_retirement_status,
|
|
16
|
+
complete_branch_retirement,
|
|
17
|
+
plan_branch_retirement,
|
|
18
|
+
record_branch_retirement,
|
|
19
|
+
verify_branch_retirement,
|
|
20
|
+
)
|
|
21
|
+
from .controller import adopt, doctor, envelope, guard_write, plan, status
|
|
22
|
+
from .delivered_closeout import archive_retained, close_delivered
|
|
23
|
+
from .frozen_recovery import recover_frozen_checkout
|
|
24
|
+
from .governance import gc_apply, gc_plan
|
|
25
|
+
from .integration_conflict import resolve_integration
|
|
26
|
+
from .integration_retry import retry_integration
|
|
27
|
+
from .lifecycle import (
|
|
28
|
+
abandon_integration_intent,
|
|
29
|
+
abort_integration,
|
|
30
|
+
abort_publication_lease,
|
|
31
|
+
acknowledge_lifecycle_event,
|
|
32
|
+
acquire,
|
|
33
|
+
acquire_across,
|
|
34
|
+
acquire_publication_lease,
|
|
35
|
+
acquire_when_free,
|
|
36
|
+
adopt_delivered,
|
|
37
|
+
adopt_recovery,
|
|
38
|
+
claim_integration,
|
|
39
|
+
cleanup_disposable,
|
|
40
|
+
cleanup_typed_disposable,
|
|
41
|
+
close_preserved,
|
|
42
|
+
complete_no_change,
|
|
43
|
+
complete_publication_lease,
|
|
44
|
+
create_release_intent,
|
|
45
|
+
enqueue_integration,
|
|
46
|
+
externalize,
|
|
47
|
+
handoff,
|
|
48
|
+
integration_queue,
|
|
49
|
+
integration_recovery_matrix,
|
|
50
|
+
lifecycle_events,
|
|
51
|
+
park,
|
|
52
|
+
quarantine,
|
|
53
|
+
reconcile_integration_intents,
|
|
54
|
+
reconcile_publication_receipts,
|
|
55
|
+
reconcile_release_intents,
|
|
56
|
+
reconcile_release_plans,
|
|
57
|
+
reconcile_session,
|
|
58
|
+
record_equivalent_replay,
|
|
59
|
+
refresh_integration,
|
|
60
|
+
register_disposable,
|
|
61
|
+
release,
|
|
62
|
+
reopen,
|
|
63
|
+
reopen_integration,
|
|
64
|
+
resume,
|
|
65
|
+
review,
|
|
66
|
+
update_external_binding,
|
|
67
|
+
validate_integration,
|
|
68
|
+
)
|
|
69
|
+
from .models import (
|
|
70
|
+
LIFECYCLE_STATES,
|
|
71
|
+
ORDINARY_ROLES,
|
|
72
|
+
WORKTREE_ROLES,
|
|
73
|
+
ControllerError,
|
|
74
|
+
WriterHolder,
|
|
75
|
+
)
|
|
76
|
+
from .namespace_migration import (
|
|
77
|
+
LEGACY_ROOT_NAME,
|
|
78
|
+
migrate_namespace,
|
|
79
|
+
namespace_migration_receipts,
|
|
80
|
+
plan_namespace_migration,
|
|
81
|
+
verify_namespace,
|
|
82
|
+
)
|
|
83
|
+
from .reconciler import reconcile_writers
|
|
84
|
+
from .rendering import render
|
|
85
|
+
from .retirement_execution import KIND_CAS_DELETE
|
|
86
|
+
from .writer_lease import acquire_writer_lease, release_writer_lease, resolve_holder
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _common_parser() -> argparse.ArgumentParser:
|
|
90
|
+
parser = argparse.ArgumentParser(add_help=False)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--repo", type=Path, default=Path.cwd(), help="path inside the managed Git repository"
|
|
93
|
+
)
|
|
94
|
+
parser.add_argument("--json", action="store_true", help="emit the stable JSON contract")
|
|
95
|
+
return parser
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
99
|
+
parser = argparse.ArgumentParser(
|
|
100
|
+
prog="worktree-controller",
|
|
101
|
+
description="Govern worktree budget, authority, ownership, and lifecycle",
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
104
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
105
|
+
common = _common_parser()
|
|
106
|
+
|
|
107
|
+
status_parser = commands.add_parser("status", parents=[common], help="show Git and controller state")
|
|
108
|
+
status_parser.add_argument("--namespace-pid", type=int,
|
|
109
|
+
help="compare mounts with an existing writer process")
|
|
110
|
+
history_parser = commands.add_parser(
|
|
111
|
+
"lifecycle-history", parents=[common],
|
|
112
|
+
help="query live allocation and durable closed lifecycle evidence without mutation",
|
|
113
|
+
)
|
|
114
|
+
selector = history_parser.add_mutually_exclusive_group(required=True)
|
|
115
|
+
for name in ("allocation-id", "authority-key", "task-key", "integration-intent-id", "release-receipt-id"):
|
|
116
|
+
selector.add_argument(f"--{name}")
|
|
117
|
+
history_parser.add_argument("--limit", type=int, default=100)
|
|
118
|
+
history_parser.add_argument("--after", help="exclusive release receipt id cursor")
|
|
119
|
+
inspect_parser = commands.add_parser(
|
|
120
|
+
"release-recovery-inspect", parents=[common],
|
|
121
|
+
help="read the exact original release request without recovery or authorization",
|
|
122
|
+
)
|
|
123
|
+
inspect_parser.add_argument("--transaction-id", required=True)
|
|
124
|
+
guide_parser = commands.add_parser(
|
|
125
|
+
"recovery-guide", parents=[common], help="explain a blocked task and its next formal step without mutation",
|
|
126
|
+
)
|
|
127
|
+
guide_selector = guide_parser.add_mutually_exclusive_group(required=True)
|
|
128
|
+
guide_selector.add_argument("--path", type=Path)
|
|
129
|
+
guide_selector.add_argument("--intent-id")
|
|
130
|
+
admission_parser = commands.add_parser("admission-queue", parents=[common],
|
|
131
|
+
help="inspect or resume durable resource admission requests")
|
|
132
|
+
admission_parser.add_argument("--apply", action="store_true")
|
|
133
|
+
admission_parser.add_argument("--all-repositories", action="store_true")
|
|
134
|
+
host_parser = commands.add_parser("host-execution", parents=[common],
|
|
135
|
+
help="budget and track a process without a repository writer lease")
|
|
136
|
+
host_parser.add_argument("--action",
|
|
137
|
+
choices=("admit", "bind", "transfer", "clear", "cancel", "inspect"),
|
|
138
|
+
required=True)
|
|
139
|
+
host_parser.add_argument("--path", type=Path)
|
|
140
|
+
host_parser.add_argument("--request-id")
|
|
141
|
+
host_parser.add_argument("--client-id", default="agent-workspace")
|
|
142
|
+
host_parser.add_argument("--session-id")
|
|
143
|
+
host_parser.add_argument("--run-id")
|
|
144
|
+
host_parser.add_argument("--holder-pid", type=int)
|
|
145
|
+
host_parser.add_argument("--memory-bytes", type=int, default=2 * 1024**3)
|
|
146
|
+
host_parser.add_argument("--recover-dead-holder", action="store_true",
|
|
147
|
+
help="typed release of an ALLOCATED reservation whose own recorded holder "
|
|
148
|
+
"is provably dead; needs that holder digest and terminal evidence")
|
|
149
|
+
host_parser.add_argument("--expected-holder-sha256",
|
|
150
|
+
help="sha256 of the reservation's recorded holder, presented by the caller")
|
|
151
|
+
host_parser.add_argument("--terminal-evidence",
|
|
152
|
+
help="canonical JSON terminal-state record for the reservation's session/run")
|
|
153
|
+
for execution_action in ("admit", "cancel"):
|
|
154
|
+
execution_parser = commands.add_parser("execution-" + execution_action, parents=[common],
|
|
155
|
+
help="reserve or cancel resources for a never-launched execution")
|
|
156
|
+
execution_parser.add_argument("--path", type=Path, required=True)
|
|
157
|
+
execution_parser.add_argument("--owner", required=True)
|
|
158
|
+
execution_parser.add_argument("--client-id", required=True)
|
|
159
|
+
execution_parser.add_argument("--session-id", required=True)
|
|
160
|
+
execution_parser.add_argument("--run-id")
|
|
161
|
+
execution_parser.add_argument("--memory-bytes", type=int, default=2 * 1024**3)
|
|
162
|
+
admit_session_parser = commands.add_parser(
|
|
163
|
+
"session-admit", parents=[common],
|
|
164
|
+
help="acquire a new feature allocation and admit its execution in one process",
|
|
165
|
+
)
|
|
166
|
+
admit_session_parser.add_argument("--task-key", required=True)
|
|
167
|
+
admit_session_parser.add_argument("--authority-key", required=True)
|
|
168
|
+
admit_session_parser.add_argument("--module", required=True)
|
|
169
|
+
admit_session_parser.add_argument("--owner", required=True)
|
|
170
|
+
admit_session_parser.add_argument("--branch", required=True)
|
|
171
|
+
admit_session_parser.add_argument("--base-ref", required=True)
|
|
172
|
+
admit_session_parser.add_argument("--client-id", required=True)
|
|
173
|
+
admit_session_parser.add_argument("--session-id", required=True)
|
|
174
|
+
admit_session_parser.add_argument("--run-id")
|
|
175
|
+
bind_session_parser = commands.add_parser(
|
|
176
|
+
"session-bind", parents=[common],
|
|
177
|
+
help="grant, check and register one live executor's write entitlement in one process",
|
|
178
|
+
)
|
|
179
|
+
bind_session_parser.add_argument("--path", type=Path, required=True)
|
|
180
|
+
bind_session_parser.add_argument("--task-key", required=True)
|
|
181
|
+
bind_session_parser.add_argument("--authority-key", required=True)
|
|
182
|
+
bind_session_parser.add_argument("--owner", required=True)
|
|
183
|
+
bind_session_parser.add_argument("--client-id", required=True)
|
|
184
|
+
bind_session_parser.add_argument("--holder-pid", type=int, required=True)
|
|
185
|
+
bind_session_parser.add_argument("--session-id", required=True)
|
|
186
|
+
bind_session_parser.add_argument("--run-id")
|
|
187
|
+
bind_session_parser.add_argument("--kind", choices=["agent", "command", "test"], default="agent")
|
|
188
|
+
commands.add_parser(
|
|
189
|
+
"capabilities", parents=[common], help="read caller compatibility capabilities"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
refresh_parser = commands.add_parser(
|
|
193
|
+
"canonical-refresh", parents=[common],
|
|
194
|
+
help="fast-forward an ACTIVE idle canonical checkout to published main",
|
|
195
|
+
)
|
|
196
|
+
refresh_parser.add_argument("--dry-run", action="store_true")
|
|
197
|
+
|
|
198
|
+
canonical_parser = commands.add_parser(
|
|
199
|
+
"canonical-transition", parents=[common],
|
|
200
|
+
help="advance a frozen canonical checkout to exact published main",
|
|
201
|
+
)
|
|
202
|
+
canonical_parser.add_argument("--path", type=Path, required=True)
|
|
203
|
+
canonical_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
204
|
+
canonical_parser.add_argument("--owner", required=True)
|
|
205
|
+
canonical_parser.add_argument("--expected-branch", required=True)
|
|
206
|
+
canonical_parser.add_argument("--expected-head", required=True)
|
|
207
|
+
canonical_parser.add_argument("--expected-main-head", required=True)
|
|
208
|
+
canonical_parser.add_argument("--expected-remote-head", required=True)
|
|
209
|
+
canonical_parser.add_argument("--new-owner", required=True)
|
|
210
|
+
canonical_parser.add_argument("--new-task-key", required=True)
|
|
211
|
+
canonical_parser.add_argument("--new-authority-key", required=True)
|
|
212
|
+
|
|
213
|
+
plan_parser = commands.add_parser(
|
|
214
|
+
"plan", parents=[common], help="make a read-only allocation decision"
|
|
215
|
+
)
|
|
216
|
+
plan_parser.add_argument("--task-key", required=True)
|
|
217
|
+
plan_parser.add_argument("--authority-key")
|
|
218
|
+
plan_parser.add_argument("--module", required=True)
|
|
219
|
+
plan_parser.add_argument("--role", required=True, choices=sorted(WORKTREE_ROLES))
|
|
220
|
+
plan_parser.add_argument("--target", type=Path)
|
|
221
|
+
|
|
222
|
+
wait_parser = commands.add_parser(
|
|
223
|
+
"acquire-when-free",
|
|
224
|
+
parents=[common],
|
|
225
|
+
help="acquire, waiting a bounded time for capacity that may free",
|
|
226
|
+
)
|
|
227
|
+
wait_parser.add_argument("--task-key", required=True)
|
|
228
|
+
wait_parser.add_argument("--authority-key", required=True)
|
|
229
|
+
wait_parser.add_argument("--module", required=True)
|
|
230
|
+
wait_parser.add_argument("--role", required=True, choices=sorted(ORDINARY_ROLES))
|
|
231
|
+
wait_parser.add_argument("--owner", required=True)
|
|
232
|
+
wait_parser.add_argument("--branch", required=True)
|
|
233
|
+
wait_parser.add_argument("--base-ref", required=True)
|
|
234
|
+
wait_parser.add_argument("--path", type=Path)
|
|
235
|
+
wait_parser.add_argument("--scope", action="append", default=[])
|
|
236
|
+
wait_parser.add_argument("--deadline-seconds", type=int, required=True)
|
|
237
|
+
wait_parser.add_argument("--poll-seconds", type=float, default=2.0)
|
|
238
|
+
|
|
239
|
+
across_parser = commands.add_parser(
|
|
240
|
+
"acquire-across",
|
|
241
|
+
parents=[common],
|
|
242
|
+
help="admit one task in every required repository, or in none",
|
|
243
|
+
)
|
|
244
|
+
across_parser.add_argument(
|
|
245
|
+
"--request",
|
|
246
|
+
action="append",
|
|
247
|
+
required=True,
|
|
248
|
+
help="JSON object naming repository, task_key, authority_key, module, role, "
|
|
249
|
+
"owner, branch, base_ref and optional target/scope_paths",
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
guard_parser = commands.add_parser(
|
|
253
|
+
"write-guard", parents=[common], help="authorize a declared task write before editing"
|
|
254
|
+
)
|
|
255
|
+
guard_parser.add_argument("--path", type=Path, required=True)
|
|
256
|
+
guard_parser.add_argument("--task-key", required=True)
|
|
257
|
+
guard_parser.add_argument("--authority-key", required=True)
|
|
258
|
+
guard_parser.add_argument("--owner", required=True)
|
|
259
|
+
guard_parser.add_argument("--holder", help="pid or ancestor:<program> of the lease holder")
|
|
260
|
+
guard_parser.add_argument("--client-id", default="manual")
|
|
261
|
+
guard_parser.add_argument("--session-id")
|
|
262
|
+
guard_parser.add_argument("--run-id")
|
|
263
|
+
guard_parser.add_argument(
|
|
264
|
+
"--operation",
|
|
265
|
+
required=True,
|
|
266
|
+
choices=["feature-write", "integration-write", "recovery", "finalization"],
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
adopt_parser = commands.add_parser(
|
|
270
|
+
"adopt", parents=[common], help="adopt a registered worktree into metadata"
|
|
271
|
+
)
|
|
272
|
+
adopt_parser.add_argument("--path", type=Path, required=True)
|
|
273
|
+
adopt_parser.add_argument("--task-key", required=True)
|
|
274
|
+
adopt_parser.add_argument("--authority-key", required=True)
|
|
275
|
+
adopt_parser.add_argument("--module", required=True)
|
|
276
|
+
adopt_parser.add_argument("--role", required=True, choices=sorted(WORKTREE_ROLES))
|
|
277
|
+
adopt_parser.add_argument("--owner", required=True)
|
|
278
|
+
adopt_parser.add_argument("--lifecycle", required=True, choices=sorted(LIFECYCLE_STATES))
|
|
279
|
+
adopt_parser.add_argument("--base-commit")
|
|
280
|
+
adopt_parser.add_argument("--task-commit")
|
|
281
|
+
adopt_parser.add_argument("--scope", action="append", default=[])
|
|
282
|
+
adopt_parser.add_argument("--source-allocation", action="append", default=[])
|
|
283
|
+
adopt_parser.add_argument("--external-binding", action="append", default=[])
|
|
284
|
+
|
|
285
|
+
acquire_parser = commands.add_parser(
|
|
286
|
+
"acquire", parents=[common], help="create one policy-approved linked worktree"
|
|
287
|
+
)
|
|
288
|
+
acquire_parser.add_argument("--task-key", required=True)
|
|
289
|
+
acquire_parser.add_argument("--authority-key", required=True)
|
|
290
|
+
acquire_parser.add_argument("--module", required=True)
|
|
291
|
+
acquire_parser.add_argument("--role", required=True, choices=sorted(WORKTREE_ROLES))
|
|
292
|
+
acquire_parser.add_argument("--owner", required=True)
|
|
293
|
+
acquire_parser.add_argument("--branch", required=True)
|
|
294
|
+
acquire_parser.add_argument("--base-ref", required=True)
|
|
295
|
+
acquire_parser.add_argument("--path", type=Path)
|
|
296
|
+
acquire_parser.add_argument("--scope", action="append", default=[])
|
|
297
|
+
acquire_parser.add_argument("--source-allocation", action="append", default=[])
|
|
298
|
+
acquire_parser.add_argument("--source-handoff", action="append", default=[])
|
|
299
|
+
acquire_parser.add_argument("--external-binding", action="append", default=[])
|
|
300
|
+
|
|
301
|
+
commands.add_parser(
|
|
302
|
+
"integration-queue", parents=[common], help="show frozen integration intent queue"
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
enqueue_parser = commands.add_parser(
|
|
306
|
+
"integration-enqueue",
|
|
307
|
+
parents=[common],
|
|
308
|
+
help="queue a frozen source handoff without occupying a checkout",
|
|
309
|
+
)
|
|
310
|
+
enqueue_parser.add_argument("--task-key", required=True)
|
|
311
|
+
enqueue_parser.add_argument("--authority-key", required=True)
|
|
312
|
+
enqueue_parser.add_argument("--module", required=True)
|
|
313
|
+
enqueue_parser.add_argument("--owner", required=True)
|
|
314
|
+
enqueue_parser.add_argument("--source-allocation", action="append", default=[])
|
|
315
|
+
enqueue_parser.add_argument("--source-handoff", action="append", default=[])
|
|
316
|
+
enqueue_parser.add_argument("--source-snapshot", action="append", default=[])
|
|
317
|
+
|
|
318
|
+
claim_parser = commands.add_parser(
|
|
319
|
+
"integration-claim",
|
|
320
|
+
parents=[common],
|
|
321
|
+
help="claim the oldest queued intent into an available candidate slot",
|
|
322
|
+
)
|
|
323
|
+
claim_parser.add_argument("--owner", required=True)
|
|
324
|
+
claim_parser.add_argument("--intent-id")
|
|
325
|
+
claim_parser.add_argument("--path", type=Path)
|
|
326
|
+
claim_parser.add_argument("--branch")
|
|
327
|
+
claim_parser.add_argument("--resolve-conflicts", action="store_true")
|
|
328
|
+
|
|
329
|
+
resolve_parser = commands.add_parser(
|
|
330
|
+
"integration-resolve", parents=[common],
|
|
331
|
+
help="bind an owner-resolved two-parent merge to its pending conflict claim",
|
|
332
|
+
)
|
|
333
|
+
resolve_parser.add_argument("--path", type=Path, required=True)
|
|
334
|
+
resolve_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
335
|
+
resolve_parser.add_argument("--owner", required=True)
|
|
336
|
+
resolve_parser.add_argument("--expected-head", required=True)
|
|
337
|
+
resolve_parser.add_argument("--finalizer-record-id", required=True)
|
|
338
|
+
|
|
339
|
+
refresh_parser = commands.add_parser(
|
|
340
|
+
"integration-refresh",
|
|
341
|
+
parents=[common],
|
|
342
|
+
help="rebuild a validated candidate from frozen handoffs and latest main",
|
|
343
|
+
)
|
|
344
|
+
refresh_parser.add_argument("--path", type=Path, required=True)
|
|
345
|
+
refresh_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
346
|
+
refresh_parser.add_argument("--owner", required=True)
|
|
347
|
+
|
|
348
|
+
validate_parser = commands.add_parser(
|
|
349
|
+
"integration-validate",
|
|
350
|
+
parents=[common],
|
|
351
|
+
help="bind validation evidence to the exact candidate revision",
|
|
352
|
+
)
|
|
353
|
+
validate_parser.add_argument("--path", type=Path, required=True)
|
|
354
|
+
validate_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
355
|
+
validate_parser.add_argument("--owner", required=True)
|
|
356
|
+
validate_parser.add_argument("--validation-evidence-id", required=True)
|
|
357
|
+
validate_parser.add_argument("--tests-receipt-id")
|
|
358
|
+
validate_parser.add_argument("--snapshot-receipt-id")
|
|
359
|
+
|
|
360
|
+
integration_reopen_parser = commands.add_parser(
|
|
361
|
+
"integration-reopen",
|
|
362
|
+
parents=[common],
|
|
363
|
+
help="invalidate prepared evidence before changing an integration candidate",
|
|
364
|
+
)
|
|
365
|
+
integration_reopen_parser.add_argument("--path", type=Path, required=True)
|
|
366
|
+
integration_reopen_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
367
|
+
integration_reopen_parser.add_argument("--owner", required=True)
|
|
368
|
+
|
|
369
|
+
events_parser = commands.add_parser(
|
|
370
|
+
"lifecycle-events",
|
|
371
|
+
parents=[common],
|
|
372
|
+
help="list durable integration lifecycle events not acknowledged by a consumer",
|
|
373
|
+
)
|
|
374
|
+
events_parser.add_argument("--consumer", required=True)
|
|
375
|
+
|
|
376
|
+
event_ack_parser = commands.add_parser(
|
|
377
|
+
"lifecycle-event-ack",
|
|
378
|
+
parents=[common],
|
|
379
|
+
help="idempotently acknowledge one durable integration lifecycle event",
|
|
380
|
+
)
|
|
381
|
+
event_ack_parser.add_argument("--consumer", required=True)
|
|
382
|
+
event_ack_parser.add_argument("--event-id", required=True)
|
|
383
|
+
|
|
384
|
+
commands.add_parser(
|
|
385
|
+
"integration-recovery-matrix",
|
|
386
|
+
parents=[common],
|
|
387
|
+
help="show the supported integration transaction recovery contract",
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
equivalent_parser = commands.add_parser(
|
|
391
|
+
"integration-equivalent",
|
|
392
|
+
parents=[common],
|
|
393
|
+
help="bind explicit equivalent-replay evidence before integration validation",
|
|
394
|
+
)
|
|
395
|
+
equivalent_parser.add_argument("--path", type=Path, required=True)
|
|
396
|
+
equivalent_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
397
|
+
equivalent_parser.add_argument("--owner", required=True)
|
|
398
|
+
equivalent_parser.add_argument("--source-allocation", required=True)
|
|
399
|
+
equivalent_parser.add_argument("--source-handoff", required=True)
|
|
400
|
+
equivalent_parser.add_argument("--replay-commit", required=True)
|
|
401
|
+
equivalent_parser.add_argument("--evidence-id", required=True)
|
|
402
|
+
|
|
403
|
+
no_change_parser = commands.add_parser(
|
|
404
|
+
"complete-no-change",
|
|
405
|
+
parents=[common],
|
|
406
|
+
help="record a genuine no-change completion for a task that produced no commit",
|
|
407
|
+
)
|
|
408
|
+
no_change_parser.add_argument("--path", type=Path, required=True)
|
|
409
|
+
no_change_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
410
|
+
no_change_parser.add_argument("--owner", required=True)
|
|
411
|
+
delivered_parser = commands.add_parser(
|
|
412
|
+
"close-delivered", parents=[common],
|
|
413
|
+
help="close an owner-reviewed retained or legacy preserved checkout already published",
|
|
414
|
+
)
|
|
415
|
+
delivered_parser.add_argument("--path", type=Path, required=True)
|
|
416
|
+
delivered_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
417
|
+
delivered_parser.add_argument("--owner-release", required=True)
|
|
418
|
+
delivered_parser.add_argument("--actor", required=True)
|
|
419
|
+
delivered_parser.add_argument("--dry-run", action="store_true")
|
|
420
|
+
delivered_parser.add_argument("--plan-id")
|
|
421
|
+
archive_parser = commands.add_parser(
|
|
422
|
+
"archive-retained", parents=[common],
|
|
423
|
+
help="preserve an unfinished clean retained checkout on its branch before release",
|
|
424
|
+
)
|
|
425
|
+
archive_parser.add_argument("--path", type=Path, required=True)
|
|
426
|
+
archive_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
427
|
+
archive_parser.add_argument("--owner-release", required=True)
|
|
428
|
+
archive_parser.add_argument("--actor", required=True)
|
|
429
|
+
archive_parser.add_argument("--dry-run", action="store_true")
|
|
430
|
+
archive_parser.add_argument("--plan-id")
|
|
431
|
+
preserved_parser = commands.add_parser("close-preserved", parents=[common],
|
|
432
|
+
help="close exactly preserved source work without declaring business completion")
|
|
433
|
+
preserved_parser.add_argument("--path", type=Path, required=True)
|
|
434
|
+
preserved_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
435
|
+
preserved_parser.add_argument("--owner", required=True)
|
|
436
|
+
abandon_parser = commands.add_parser(
|
|
437
|
+
"integration-abandon",
|
|
438
|
+
parents=[common],
|
|
439
|
+
help="terminate an integration intent whose preparation is already gone",
|
|
440
|
+
)
|
|
441
|
+
abandon_parser.add_argument("--intent-id", required=True)
|
|
442
|
+
abandon_parser.add_argument("--owner", required=True)
|
|
443
|
+
abandon_parser.add_argument("--reason", required=True)
|
|
444
|
+
abort_parser = commands.add_parser(
|
|
445
|
+
"integration-abort",
|
|
446
|
+
parents=[common],
|
|
447
|
+
help="terminate a failed or owner-aborted integration preparation",
|
|
448
|
+
)
|
|
449
|
+
abort_parser.add_argument("--path", type=Path, required=True)
|
|
450
|
+
abort_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
451
|
+
abort_parser.add_argument("--owner", required=True)
|
|
452
|
+
abort_parser.add_argument("--reason", required=True)
|
|
453
|
+
retry_parser = commands.add_parser(
|
|
454
|
+
"integration-retry", parents=[common],
|
|
455
|
+
help="retry an aborted released candidate under its original frozen intent",
|
|
456
|
+
)
|
|
457
|
+
retry_parser.add_argument("--intent-id", required=True)
|
|
458
|
+
retry_parser.add_argument("--owner", required=True)
|
|
459
|
+
retry_parser.add_argument("--reason", required=True)
|
|
460
|
+
retry_parser.add_argument("--prerequisite-intent")
|
|
461
|
+
retry_parser.add_argument("--dry-run", action="store_true")
|
|
462
|
+
retry_parser.add_argument("--expected-plan-id")
|
|
463
|
+
session_parser = commands.add_parser(
|
|
464
|
+
"reconcile-session",
|
|
465
|
+
parents=[common],
|
|
466
|
+
help="terminal reconciliation when a task session stops",
|
|
467
|
+
)
|
|
468
|
+
session_parser.add_argument("--path", type=Path, required=True)
|
|
469
|
+
session_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
470
|
+
session_parser.add_argument("--owner", required=True)
|
|
471
|
+
session_parser.add_argument(
|
|
472
|
+
"--trigger", required=True, choices=["task-terminal", "session-archive", "manual"]
|
|
473
|
+
)
|
|
474
|
+
lease_acquire = commands.add_parser(
|
|
475
|
+
"writer-lease-acquire",
|
|
476
|
+
parents=[common],
|
|
477
|
+
help="bind write entitlement to a verifiable live process",
|
|
478
|
+
)
|
|
479
|
+
lease_acquire.add_argument("--path", type=Path, required=True)
|
|
480
|
+
lease_acquire.add_argument("--owner")
|
|
481
|
+
lease_acquire.add_argument("--client-id", required=True)
|
|
482
|
+
lease_acquire.add_argument("--holder-pid", type=int, required=True)
|
|
483
|
+
lease_acquire.add_argument("--session-id")
|
|
484
|
+
lease_acquire.add_argument("--run-id")
|
|
485
|
+
lease_acquire.add_argument("--ttl-seconds", type=int)
|
|
486
|
+
lease_acquire.add_argument("--expected-record-version", type=int)
|
|
487
|
+
lease_release = commands.add_parser(
|
|
488
|
+
"writer-lease-release",
|
|
489
|
+
parents=[common],
|
|
490
|
+
help="give up write entitlement without asserting the task finished",
|
|
491
|
+
)
|
|
492
|
+
lease_release.add_argument("--path", type=Path, required=True)
|
|
493
|
+
lease_release.add_argument("--holder-pid", type=int)
|
|
494
|
+
lease_release.add_argument("--holder-boot-id")
|
|
495
|
+
lease_release.add_argument("--holder-start-ticks", type=int)
|
|
496
|
+
lease_release.add_argument("--client-id", default="manual")
|
|
497
|
+
lease_release.add_argument("--session-id")
|
|
498
|
+
lease_release.add_argument("--run-id")
|
|
499
|
+
lease_release.add_argument("--lease-id")
|
|
500
|
+
commands.add_parser("writer-session", help="strict executor admission and post-exit cleanup")
|
|
501
|
+
reconcile_writers_parser = commands.add_parser(
|
|
502
|
+
"reconcile-writers",
|
|
503
|
+
parents=[common],
|
|
504
|
+
help="report, and optionally converge, provably inactive writer entitlement",
|
|
505
|
+
)
|
|
506
|
+
reconcile_writers_parser.add_argument("--actor", default="lifecycle-reconciler")
|
|
507
|
+
reconcile_writers_parser.add_argument(
|
|
508
|
+
"--trigger", choices=("manual", "admission", "background"), default="manual"
|
|
509
|
+
)
|
|
510
|
+
reconcile_writers_parser.add_argument(
|
|
511
|
+
"--apply",
|
|
512
|
+
action="store_true",
|
|
513
|
+
help="converge instead of reporting; without it the command is read-only",
|
|
514
|
+
)
|
|
515
|
+
reconcile_writers_parser.add_argument(
|
|
516
|
+
"--only",
|
|
517
|
+
action="append",
|
|
518
|
+
default=[],
|
|
519
|
+
metavar="TASK_KEY",
|
|
520
|
+
help="converge only these allocations; everything else is reported but untouched",
|
|
521
|
+
)
|
|
522
|
+
reconcile_writers_parser.add_argument(
|
|
523
|
+
"--adopt-legacy",
|
|
524
|
+
action="store_true",
|
|
525
|
+
help="one-time classification of allocations created before writer leases",
|
|
526
|
+
)
|
|
527
|
+
park_parser = commands.add_parser(
|
|
528
|
+
"park", parents=[common], help="retain an unfinished checkout and free its writer slot"
|
|
529
|
+
)
|
|
530
|
+
park_parser.add_argument("--path", type=Path, required=True)
|
|
531
|
+
park_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
532
|
+
park_parser.add_argument("--owner", required=True)
|
|
533
|
+
park_parser.add_argument("--checkpoint-id", help="content-addressed checkpoint retained by the existing Task")
|
|
534
|
+
park_parser.add_argument("--checkpoint-head", help="exact HEAD saved in that checkpoint")
|
|
535
|
+
park_parser.add_argument("--waiting-on", help="external dependency kept by the Task, not a reason to retain a directory")
|
|
536
|
+
resume_parser = commands.add_parser(
|
|
537
|
+
"resume", parents=[common], help="return a retained checkout to writer status"
|
|
538
|
+
)
|
|
539
|
+
resume_parser.add_argument("--path", type=Path, required=True)
|
|
540
|
+
resume_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
541
|
+
resume_parser.add_argument("--owner", required=True)
|
|
542
|
+
adopt_parser = commands.add_parser(
|
|
543
|
+
"adopt-delivered",
|
|
544
|
+
parents=[common],
|
|
545
|
+
help="adopt an allocation whose deliverable is already in the publication branch",
|
|
546
|
+
)
|
|
547
|
+
adopt_parser.add_argument("--path", type=Path, required=True)
|
|
548
|
+
adopt_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
549
|
+
adopt_parser.add_argument("--new-owner", required=True)
|
|
550
|
+
adopt_parser.add_argument("--actor", required=True)
|
|
551
|
+
review_parser = commands.add_parser(
|
|
552
|
+
"review", parents=[common], help="record owner review or explicit owner transfer"
|
|
553
|
+
)
|
|
554
|
+
review_parser.add_argument("--path", type=Path, required=True)
|
|
555
|
+
review_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
556
|
+
review_parser.add_argument("--owner", required=True)
|
|
557
|
+
review_parser.add_argument("--new-owner")
|
|
558
|
+
review_parser.add_argument("--add-scope", action="append", default=[])
|
|
559
|
+
review_parser.add_argument("--expected-head")
|
|
560
|
+
review_parser.add_argument("--scope-reason")
|
|
561
|
+
|
|
562
|
+
handoff_parser = commands.add_parser(
|
|
563
|
+
"handoff", parents=[common], help="record an integration-ready or preserved handoff"
|
|
564
|
+
)
|
|
565
|
+
handoff_parser.add_argument("--path", type=Path, required=True)
|
|
566
|
+
handoff_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
567
|
+
handoff_parser.add_argument("--kind", required=True, choices=["integration-ready", "preserved"])
|
|
568
|
+
handoff_parser.add_argument("--commit", required=True)
|
|
569
|
+
handoff_parser.add_argument("--finalizer-record-id", required=True)
|
|
570
|
+
handoff_parser.add_argument("--finalizer-commit")
|
|
571
|
+
handoff_parser.add_argument("--scope", action="append", default=[])
|
|
572
|
+
handoff_parser.add_argument(
|
|
573
|
+
"--scope-changed", action="store_true",
|
|
574
|
+
help="record the exact paths the handoff commit changed as the task scope",
|
|
575
|
+
)
|
|
576
|
+
handoff_parser.add_argument("--mainline-commit")
|
|
577
|
+
|
|
578
|
+
quarantine_parser = commands.add_parser(
|
|
579
|
+
"quarantine", parents=[common], help="isolate a drifted integration candidate"
|
|
580
|
+
)
|
|
581
|
+
quarantine_parser.add_argument("--path", type=Path, required=True)
|
|
582
|
+
quarantine_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
583
|
+
quarantine_parser.add_argument("--owner", required=True)
|
|
584
|
+
quarantine_parser.add_argument("--reason", required=True)
|
|
585
|
+
quarantine_parser.add_argument("--expected-commit")
|
|
586
|
+
|
|
587
|
+
recovery_adopt_parser = commands.add_parser(
|
|
588
|
+
"recovery-adopt",
|
|
589
|
+
parents=[common],
|
|
590
|
+
help="move an existing checkout under governance recovery capacity",
|
|
591
|
+
)
|
|
592
|
+
recovery_adopt_parser.add_argument("--source-path", type=Path, required=True)
|
|
593
|
+
recovery_adopt_parser.add_argument("--recovery-path", type=Path, required=True)
|
|
594
|
+
recovery_adopt_parser.add_argument("--expected-source-record-version", type=int, required=True)
|
|
595
|
+
recovery_adopt_parser.add_argument(
|
|
596
|
+
"--expected-recovery-record-version", type=int, required=True
|
|
597
|
+
)
|
|
598
|
+
recovery_adopt_parser.add_argument("--source-owner", required=True)
|
|
599
|
+
recovery_adopt_parser.add_argument("--recovery-owner", required=True)
|
|
600
|
+
recovery_adopt_parser.add_argument("--scope", action="append", default=[])
|
|
601
|
+
|
|
602
|
+
externalize_parser = commands.add_parser(
|
|
603
|
+
"externalize", parents=[common], help="bind quarantined lineage to a recovery allocation"
|
|
604
|
+
)
|
|
605
|
+
externalize_parser.add_argument("--source-path", type=Path, required=True)
|
|
606
|
+
externalize_parser.add_argument("--recovery-path", type=Path, required=True)
|
|
607
|
+
externalize_parser.add_argument("--expected-source-record-version", type=int, required=True)
|
|
608
|
+
externalize_parser.add_argument("--expected-recovery-record-version", type=int, required=True)
|
|
609
|
+
externalize_parser.add_argument("--owner", required=True)
|
|
610
|
+
|
|
611
|
+
resource_register_parser = commands.add_parser(
|
|
612
|
+
"resource-register", parents=[common], help="register a rebuildable task-local resource"
|
|
613
|
+
)
|
|
614
|
+
resource_register_parser.add_argument("--path", type=Path, required=True)
|
|
615
|
+
resource_register_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
616
|
+
resource_register_parser.add_argument("--owner", required=True)
|
|
617
|
+
resource_register_parser.add_argument("--resource-path", required=True)
|
|
618
|
+
resource_register_parser.add_argument("--kind", required=True, choices=["python-venv"])
|
|
619
|
+
resource_register_parser.add_argument(
|
|
620
|
+
"--reproducible", action=argparse.BooleanOptionalAction, required=True
|
|
621
|
+
)
|
|
622
|
+
resource_register_parser.add_argument("--creator", required=True)
|
|
623
|
+
resource_register_parser.add_argument(
|
|
624
|
+
"--teardown-policy", required=True, choices=["manual", "on-release"]
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
resource_clean_parser = commands.add_parser(
|
|
628
|
+
"resource-clean", parents=[common], help="remove a registered rebuildable resource"
|
|
629
|
+
)
|
|
630
|
+
resource_clean_parser.add_argument("--path", type=Path, required=True)
|
|
631
|
+
resource_clean_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
632
|
+
resource_clean_parser.add_argument("--owner", required=True)
|
|
633
|
+
resource_mode = resource_clean_parser.add_mutually_exclusive_group(required=True)
|
|
634
|
+
resource_mode.add_argument("--resource-path")
|
|
635
|
+
resource_mode.add_argument(
|
|
636
|
+
"--typed", action="store_true", help="use the narrow typed cleanup contract"
|
|
637
|
+
)
|
|
638
|
+
resource_clean_parser.add_argument("--dry-run", action="store_true")
|
|
639
|
+
resource_clean_parser.add_argument("--expected-plan-id")
|
|
640
|
+
resource_clean_parser.add_argument("--preservation-receipt", type=Path)
|
|
641
|
+
resource_clean_parser.add_argument("--preservation-receipt-sha256")
|
|
642
|
+
resource_clean_parser.add_argument(
|
|
643
|
+
"--additional-preservation-receipt", type=Path, action="append", default=[]
|
|
644
|
+
)
|
|
645
|
+
resource_clean_parser.add_argument(
|
|
646
|
+
"--additional-preservation-receipt-sha256", action="append", default=[]
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
recovery_parser = commands.add_parser(
|
|
650
|
+
"resource-recover",
|
|
651
|
+
parents=[common],
|
|
652
|
+
help="append a re-preserved cleanup baseline or resume its remaining actions",
|
|
653
|
+
)
|
|
654
|
+
recovery_parser.add_argument(
|
|
655
|
+
"--stage",
|
|
656
|
+
required=True,
|
|
657
|
+
choices=["prepare", "prepare-multiple", "resume", "reconcile-attempt", "reconcile-typed", "rollout-check"],
|
|
658
|
+
)
|
|
659
|
+
recovery_parser.add_argument("--path", type=Path)
|
|
660
|
+
recovery_parser.add_argument("--owner")
|
|
661
|
+
recovery_parser.add_argument("--expected-record-version", type=int)
|
|
662
|
+
recovery_parser.add_argument("--transaction-id")
|
|
663
|
+
recovery_parser.add_argument("--transaction-sha256")
|
|
664
|
+
recovery_parser.add_argument("--cleanup-receipt-sha256")
|
|
665
|
+
recovery_parser.add_argument("--preservation-receipt", type=Path)
|
|
666
|
+
recovery_parser.add_argument("--preservation-receipt-sha256")
|
|
667
|
+
recovery_parser.add_argument("--expected-plan-id")
|
|
668
|
+
recovery_parser.add_argument("--recovery-receipt", type=Path)
|
|
669
|
+
recovery_parser.add_argument("--recovery-receipt-sha256")
|
|
670
|
+
recovery_parser.add_argument("--dry-run", action="store_true")
|
|
671
|
+
|
|
672
|
+
lease_acquire_parser = commands.add_parser(
|
|
673
|
+
"lease-acquire", parents=[common], help="acquire serialized main publication authority"
|
|
674
|
+
)
|
|
675
|
+
lease_acquire_parser.add_argument("--path", type=Path, required=True)
|
|
676
|
+
lease_acquire_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
677
|
+
lease_acquire_parser.add_argument("--owner", required=True)
|
|
678
|
+
lease_acquire_parser.add_argument("--run-id")
|
|
679
|
+
lease_acquire_parser.add_argument("--ttl-seconds", type=int, default=900)
|
|
680
|
+
|
|
681
|
+
lease_complete_parser = commands.add_parser(
|
|
682
|
+
"lease-complete", parents=[common], help="verify publication and release its lease"
|
|
683
|
+
)
|
|
684
|
+
lease_complete_parser.add_argument("--path", type=Path, required=True)
|
|
685
|
+
lease_complete_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
686
|
+
lease_complete_parser.add_argument("--lease-id", required=True)
|
|
687
|
+
lease_complete_parser.add_argument("--published-commit", required=True)
|
|
688
|
+
lease_complete_parser.add_argument("--finalizer-record-id", required=True)
|
|
689
|
+
lease_complete_parser.add_argument("--run-id", required=True)
|
|
690
|
+
lease_complete_parser.add_argument(
|
|
691
|
+
"--auto-release",
|
|
692
|
+
action=argparse.BooleanOptionalAction,
|
|
693
|
+
default=True,
|
|
694
|
+
help="guarded release after remote verification (default: enabled)",
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
publication_session_parser = commands.add_parser(
|
|
698
|
+
"publication-execution-session", parents=[common],
|
|
699
|
+
help="fence a consumer's exact publication through the public stdio protocol",
|
|
700
|
+
)
|
|
701
|
+
publication_session_parser.add_argument("--candidate-oid", required=True)
|
|
702
|
+
publication_session_parser.add_argument("--lease-id", required=True)
|
|
703
|
+
publication_session_parser.add_argument("--run-id", required=True)
|
|
704
|
+
|
|
705
|
+
lease_abort_parser = commands.add_parser(
|
|
706
|
+
"lease-abort", parents=[common], help="release unchanged publication authority"
|
|
707
|
+
)
|
|
708
|
+
lease_abort_parser.add_argument("--path", type=Path, required=True)
|
|
709
|
+
lease_abort_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
710
|
+
lease_abort_parser.add_argument("--lease-id")
|
|
711
|
+
lease_abort_parser.add_argument("--owner", required=True)
|
|
712
|
+
lease_abort_parser.add_argument("--run-id", required=True)
|
|
713
|
+
|
|
714
|
+
release_parser = commands.add_parser(
|
|
715
|
+
"release", parents=[common], help="remove an evidence-cleared linked checkout"
|
|
716
|
+
)
|
|
717
|
+
release_parser.add_argument("--path", type=Path, required=True)
|
|
718
|
+
release_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
719
|
+
release_parser.add_argument("--owner-release")
|
|
720
|
+
release_parser.add_argument("--intent-id")
|
|
721
|
+
release_parser.add_argument("--publication-receipt-id")
|
|
722
|
+
release_parser.add_argument("--teardown-reproducible-venv", action="store_true")
|
|
723
|
+
release_parser.add_argument("--dry-run", action="store_true")
|
|
724
|
+
|
|
725
|
+
gc_plan_parser = commands.add_parser(
|
|
726
|
+
"gc-plan", parents=[common], help="classify worktrees and preflight a selected release"
|
|
727
|
+
)
|
|
728
|
+
gc_plan_parser.add_argument("--path", type=Path)
|
|
729
|
+
gc_plan_parser.add_argument("--owner-release")
|
|
730
|
+
gc_plan_parser.add_argument("--intent-id")
|
|
731
|
+
gc_plan_parser.add_argument("--namespace-pid", type=int,
|
|
732
|
+
help="compare mounts with an existing writer process")
|
|
733
|
+
|
|
734
|
+
gc_apply_parser = commands.add_parser(
|
|
735
|
+
"gc-apply", parents=[common], help="apply a reviewed plan through guarded release"
|
|
736
|
+
)
|
|
737
|
+
gc_apply_parser.add_argument("--path", type=Path, required=True)
|
|
738
|
+
gc_apply_parser.add_argument("--plan-id", required=True)
|
|
739
|
+
gc_apply_parser.add_argument("--owner-release")
|
|
740
|
+
gc_apply_parser.add_argument("--intent-id")
|
|
741
|
+
|
|
742
|
+
release_intent_parser = commands.add_parser(
|
|
743
|
+
"release-intent", parents=[common], help="record a short-lived feature release intent"
|
|
744
|
+
)
|
|
745
|
+
release_intent_parser.add_argument("--path", type=Path, required=True)
|
|
746
|
+
release_intent_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
747
|
+
release_intent_parser.add_argument("--owner", required=True)
|
|
748
|
+
release_intent_parser.add_argument(
|
|
749
|
+
"--trigger",
|
|
750
|
+
required=True,
|
|
751
|
+
choices=[
|
|
752
|
+
"integration-remote-verified",
|
|
753
|
+
"task-terminal",
|
|
754
|
+
"session-archive",
|
|
755
|
+
"manual",
|
|
756
|
+
"capacity-pressure",
|
|
757
|
+
"binding-cleared",
|
|
758
|
+
],
|
|
759
|
+
)
|
|
760
|
+
release_intent_parser.add_argument("--integration-intent-id")
|
|
761
|
+
|
|
762
|
+
retirement_plan_parser = commands.add_parser(
|
|
763
|
+
"branch-retirement-plan",
|
|
764
|
+
parents=[common],
|
|
765
|
+
help="classify a released branch and persist an OID-bound retirement plan",
|
|
766
|
+
)
|
|
767
|
+
retirement_target = retirement_plan_parser.add_mutually_exclusive_group(required=True)
|
|
768
|
+
retirement_target.add_argument("--allocation-id")
|
|
769
|
+
retirement_target.add_argument("--branch")
|
|
770
|
+
retirement_plan_parser.add_argument("--remote", required=True)
|
|
771
|
+
retirement_plan_parser.add_argument("--integrated-into", required=True)
|
|
772
|
+
retirement_plan_parser.add_argument("--dry-run", action="store_true")
|
|
773
|
+
|
|
774
|
+
retirement_status_parser = commands.add_parser(
|
|
775
|
+
"branch-retirement-status",
|
|
776
|
+
parents=[common],
|
|
777
|
+
help="revalidate a retirement plan and show independent local/remote progress",
|
|
778
|
+
)
|
|
779
|
+
retirement_status_parser.add_argument("--plan-id", required=True)
|
|
780
|
+
|
|
781
|
+
retirement_verify_parser = commands.add_parser(
|
|
782
|
+
"branch-retirement-verify",
|
|
783
|
+
parents=[common],
|
|
784
|
+
help="verify one retirement operation immediately before mutation and return the CAS fields",
|
|
785
|
+
)
|
|
786
|
+
retirement_verify_parser.add_argument("--plan-id", required=True)
|
|
787
|
+
retirement_verify_parser.add_argument("--operation", choices=("local", "remote"), required=True)
|
|
788
|
+
|
|
789
|
+
retirement_authorize_parser = commands.add_parser(
|
|
790
|
+
"branch-retirement-authorize",
|
|
791
|
+
parents=[common],
|
|
792
|
+
help="grant one single-use execution authorization for one retirement operation",
|
|
793
|
+
)
|
|
794
|
+
retirement_authorize_parser.add_argument("--plan-id", required=True)
|
|
795
|
+
retirement_authorize_parser.add_argument("--operation", choices=("local", "remote"), required=True)
|
|
796
|
+
retirement_authorize_parser.add_argument("--request-id", required=True)
|
|
797
|
+
retirement_authorize_parser.add_argument(
|
|
798
|
+
"--holder",
|
|
799
|
+
default="self",
|
|
800
|
+
help="self, or ancestor:<program> of the process performing the mutation",
|
|
801
|
+
)
|
|
802
|
+
retirement_authorize_parser.add_argument("--client-id", default="retirement-executor")
|
|
803
|
+
retirement_authorize_parser.add_argument("--session-id")
|
|
804
|
+
retirement_authorize_parser.add_argument("--run-id")
|
|
805
|
+
retirement_authorize_parser.add_argument(
|
|
806
|
+
"--kind", choices=("cas-delete",), default="cas-delete", help="the only grantable kind"
|
|
807
|
+
)
|
|
808
|
+
retirement_authorize_parser.add_argument("--ttl-seconds", type=int, default=900)
|
|
809
|
+
|
|
810
|
+
retirement_complete_parser = commands.add_parser(
|
|
811
|
+
"branch-retirement-complete",
|
|
812
|
+
parents=[common],
|
|
813
|
+
help="close an authorized retirement using the Controller's own ref observation",
|
|
814
|
+
)
|
|
815
|
+
retirement_complete_parser.add_argument("--authorization-id", required=True)
|
|
816
|
+
retirement_complete_parser.add_argument("--token", required=True)
|
|
817
|
+
retirement_complete_parser.add_argument("--result-file", type=Path, required=True)
|
|
818
|
+
|
|
819
|
+
retirement_executions_parser = commands.add_parser(
|
|
820
|
+
"branch-retirement-executions",
|
|
821
|
+
parents=[common],
|
|
822
|
+
help="list, inspect or abandon outstanding retirement execution authorizations",
|
|
823
|
+
)
|
|
824
|
+
retirement_executions_parser.add_argument(
|
|
825
|
+
"--action", choices=("list", "inspect", "abandon"), required=True
|
|
826
|
+
)
|
|
827
|
+
retirement_executions_parser.add_argument("--authorization-id")
|
|
828
|
+
retirement_executions_parser.add_argument("--token")
|
|
829
|
+
retirement_executions_parser.add_argument("--reason")
|
|
830
|
+
|
|
831
|
+
retirement_record_parser = commands.add_parser(
|
|
832
|
+
"branch-retirement-record",
|
|
833
|
+
parents=[common],
|
|
834
|
+
help="record one consumer-reported retirement execution result",
|
|
835
|
+
)
|
|
836
|
+
retirement_record_parser.add_argument("--plan-id", required=True)
|
|
837
|
+
retirement_record_parser.add_argument("--operation", choices=("local", "remote"), required=True)
|
|
838
|
+
summary_target = retirement_record_parser.add_mutually_exclusive_group(required=True)
|
|
839
|
+
summary_target.add_argument(
|
|
840
|
+
"--summary-file",
|
|
841
|
+
type=Path,
|
|
842
|
+
help="legacy consumer summary; translated by the compatibility adapter",
|
|
843
|
+
)
|
|
844
|
+
summary_target.add_argument(
|
|
845
|
+
"--result-file", type=Path, help="provider-neutral retirement-execution-result/v1 document"
|
|
846
|
+
)
|
|
847
|
+
|
|
848
|
+
namespace_plan_parser = commands.add_parser(
|
|
849
|
+
"namespace-migration-plan",
|
|
850
|
+
parents=[common],
|
|
851
|
+
help="report the legacy namespace move for one repository without writing",
|
|
852
|
+
)
|
|
853
|
+
namespace_plan_parser.add_argument("--legacy-namespace", default=LEGACY_ROOT_NAME)
|
|
854
|
+
namespace_plan_parser.add_argument("--policy-from", type=Path)
|
|
855
|
+
namespace_migrate_parser = commands.add_parser(
|
|
856
|
+
"namespace-migrate",
|
|
857
|
+
parents=[common],
|
|
858
|
+
help="idempotently move the legacy metadata namespace under the repository lock",
|
|
859
|
+
)
|
|
860
|
+
namespace_migrate_parser.add_argument("--legacy-namespace", default=LEGACY_ROOT_NAME)
|
|
861
|
+
namespace_migrate_parser.add_argument("--policy-from", type=Path)
|
|
862
|
+
namespace_migrate_parser.add_argument("--actor", required=True)
|
|
863
|
+
namespace_migrate_parser.add_argument("--expected-plan-id", required=True)
|
|
864
|
+
namespace_migrate_parser.add_argument("--dry-run", action="store_true")
|
|
865
|
+
commands.add_parser(
|
|
866
|
+
"namespace-migration-receipts",
|
|
867
|
+
parents=[common],
|
|
868
|
+
help="list the immutable namespace migration receipts of one repository",
|
|
869
|
+
)
|
|
870
|
+
commands.add_parser(
|
|
871
|
+
"namespace-migration-verify",
|
|
872
|
+
parents=[common],
|
|
873
|
+
help="re-derive a completed namespace migration from immutable evidence",
|
|
874
|
+
)
|
|
875
|
+
|
|
876
|
+
reopen_parser = commands.add_parser(
|
|
877
|
+
"reopen", parents=[common], help="invalidate a frozen handoff before continuing work"
|
|
878
|
+
)
|
|
879
|
+
reopen_parser.add_argument("--path", type=Path, required=True)
|
|
880
|
+
reopen_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
881
|
+
reopen_parser.add_argument("--owner", required=True)
|
|
882
|
+
|
|
883
|
+
for recovery_command in ("recover-handoff", "recover-published"):
|
|
884
|
+
recovery_parser = commands.add_parser(
|
|
885
|
+
recovery_command, parents=[common], help="recover a published frozen checkout with immutable evidence"
|
|
886
|
+
)
|
|
887
|
+
recovery_parser.add_argument("--path", type=Path, required=True)
|
|
888
|
+
recovery_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
889
|
+
recovery_parser.add_argument("--expected-head", required=True)
|
|
890
|
+
recovery_parser.add_argument("--owner", required=True)
|
|
891
|
+
if recovery_command == "recover-published":
|
|
892
|
+
recovery_parser.add_argument("--branch", required=True)
|
|
893
|
+
|
|
894
|
+
for binding_action in ("add", "remove", "transfer"):
|
|
895
|
+
binding_parser = commands.add_parser(
|
|
896
|
+
f"binding-{binding_action}",
|
|
897
|
+
parents=[common],
|
|
898
|
+
help=f"{binding_action} an explicit runtime or workspace binding",
|
|
899
|
+
)
|
|
900
|
+
binding_parser.add_argument("--path", type=Path, required=True)
|
|
901
|
+
binding_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
902
|
+
binding_parser.add_argument("--owner", required=True)
|
|
903
|
+
binding_parser.add_argument("--binding", required=True)
|
|
904
|
+
if binding_action == "transfer":
|
|
905
|
+
binding_parser.add_argument("--holder-pid", type=int, required=True)
|
|
906
|
+
if binding_action == "remove":
|
|
907
|
+
binding_parser.add_argument("--recover-archived-codex-session", action="store_true")
|
|
908
|
+
binding_parser.add_argument("--dry-run", action="store_true")
|
|
909
|
+
|
|
910
|
+
reconcile_parser = commands.add_parser(
|
|
911
|
+
"reconcile", help="reconcile immutable receipts or existing release intents"
|
|
912
|
+
)
|
|
913
|
+
reconcile_commands = reconcile_parser.add_subparsers(dest="reconcile_command", required=True)
|
|
914
|
+
receipts_parser = reconcile_commands.add_parser("receipts", parents=[common])
|
|
915
|
+
receipts_parser.add_argument("--actor", required=True)
|
|
916
|
+
receipts_parser.add_argument("--receipt-id", action="append", default=[])
|
|
917
|
+
receipts_parser.add_argument("--dry-run", action="store_true")
|
|
918
|
+
no_change_parser = reconcile_commands.add_parser(
|
|
919
|
+
"no-change-completion", parents=[common],
|
|
920
|
+
help="bind exact legacy no-change completion to its successful cleanup evidence",
|
|
921
|
+
)
|
|
922
|
+
no_change_parser.add_argument("--path", type=Path, required=True)
|
|
923
|
+
no_change_parser.add_argument("--owner", required=True)
|
|
924
|
+
no_change_parser.add_argument("--expected-record-version", type=int, required=True)
|
|
925
|
+
no_change_parser.add_argument("--completion-receipt-id", required=True)
|
|
926
|
+
no_change_parser.add_argument("--completion-receipt-sha256", required=True)
|
|
927
|
+
no_change_parser.add_argument("--cleanup-receipt-id", action="append", required=True)
|
|
928
|
+
no_change_parser.add_argument("--cleanup-receipt-sha256", action="append", required=True)
|
|
929
|
+
no_change_parser.add_argument("--dry-run", action="store_true")
|
|
930
|
+
no_change_parser.add_argument("--expected-plan-id")
|
|
931
|
+
intents_parser = reconcile_commands.add_parser("release-intents", parents=[common])
|
|
932
|
+
intents_parser.add_argument("--actor", required=True)
|
|
933
|
+
intents_parser.add_argument(
|
|
934
|
+
"--trigger",
|
|
935
|
+
required=True,
|
|
936
|
+
choices=[
|
|
937
|
+
"integration-remote-verified",
|
|
938
|
+
"task-terminal",
|
|
939
|
+
"session-archive",
|
|
940
|
+
"binding-cleared",
|
|
941
|
+
"manual",
|
|
942
|
+
"capacity-pressure",
|
|
943
|
+
],
|
|
944
|
+
)
|
|
945
|
+
intents_parser.add_argument("--intent-id", action="append", default=[])
|
|
946
|
+
intents_parser.add_argument("--dry-run", action="store_true")
|
|
947
|
+
release_plans_parser = reconcile_commands.add_parser("release-plans", parents=[common])
|
|
948
|
+
release_plans_parser.add_argument("--actor", required=True)
|
|
949
|
+
release_plans_parser.add_argument("--dry-run", action="store_true")
|
|
950
|
+
retention_parser = reconcile_commands.add_parser(
|
|
951
|
+
"retention",
|
|
952
|
+
parents=[common],
|
|
953
|
+
help="close idle clean checkouts through guarded release (dry-run unless --apply)",
|
|
954
|
+
)
|
|
955
|
+
retention_parser.add_argument("--actor", required=True)
|
|
956
|
+
retention_parser.add_argument(
|
|
957
|
+
"--trigger", choices=("manual", "admission", "background"), default="manual"
|
|
958
|
+
)
|
|
959
|
+
retention_parser.add_argument("--apply", action="store_true")
|
|
960
|
+
registrations_parser = reconcile_commands.add_parser(
|
|
961
|
+
"binding-registrations", parents=[common],
|
|
962
|
+
help="tie legacy linked bindings to their current Git registration (dry-run first)",
|
|
963
|
+
)
|
|
964
|
+
registrations_parser.add_argument("--dry-run", action="store_true")
|
|
965
|
+
registrations_parser.add_argument("--expected-plan-id")
|
|
966
|
+
integration_intents_parser = reconcile_commands.add_parser(
|
|
967
|
+
"integration-intents", parents=[common]
|
|
968
|
+
)
|
|
969
|
+
integration_intents_parser.add_argument("--actor", required=True)
|
|
970
|
+
integration_intents_parser.add_argument("--intent-id", action="append", default=[])
|
|
971
|
+
integration_intents_parser.add_argument("--dry-run", action="store_true")
|
|
972
|
+
integration_intents_parser.add_argument("--dispatch", action="store_true")
|
|
973
|
+
|
|
974
|
+
doctor_parser = commands.add_parser("doctor", parents=[common], help="diagnose controller drift")
|
|
975
|
+
doctor_parser.add_argument("--namespace-pid", type=int,
|
|
976
|
+
help="compare mounts with an existing writer process")
|
|
977
|
+
return parser
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
def _print(payload: dict[str, Any], as_json: bool) -> None:
|
|
981
|
+
if as_json:
|
|
982
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True))
|
|
983
|
+
else:
|
|
984
|
+
print(render(payload))
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
def main(argv: list[str] | None = None) -> int:
|
|
988
|
+
from .store import decode_cache
|
|
989
|
+
|
|
990
|
+
arguments = list(sys.argv[1:] if argv is None else argv)
|
|
991
|
+
# Queries and execution's first attempt need one snapshot. Recovery opts into reuse below.
|
|
992
|
+
if arguments and arguments[0] in {
|
|
993
|
+
"status", "doctor", "lifecycle-history", "release-recovery-inspect", "recovery-guide",
|
|
994
|
+
"execution-admit", "execution-cancel"
|
|
995
|
+
}:
|
|
996
|
+
return _main(arguments)
|
|
997
|
+
# Writer checks load each repository once; retain the CLI reader without its caches.
|
|
998
|
+
reuse = arguments[:2] not in (
|
|
999
|
+
["writer-session", "check"], ["writer-session", "host-check"]
|
|
1000
|
+
)
|
|
1001
|
+
with decode_cache(reuse=reuse):
|
|
1002
|
+
return _main(arguments)
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
def _main(argv: list[str] | None) -> int:
|
|
1006
|
+
arguments = list(sys.argv[1:] if argv is None else argv)
|
|
1007
|
+
if arguments and arguments[0] == "writer-session":
|
|
1008
|
+
from .writer_session import main as writer_session_main
|
|
1009
|
+
|
|
1010
|
+
return writer_session_main(arguments[1:])
|
|
1011
|
+
parser = build_parser()
|
|
1012
|
+
parsed = parser.parse_args(arguments)
|
|
1013
|
+
try:
|
|
1014
|
+
if parsed.command == "capabilities":
|
|
1015
|
+
from .writer_session import (
|
|
1016
|
+
HOST_HANDOFF_CONTINUATION_VERSION,
|
|
1017
|
+
HOST_MANAGED_WRITER_SESSION_VERSION,
|
|
1018
|
+
)
|
|
1019
|
+
|
|
1020
|
+
payload = envelope("capabilities")
|
|
1021
|
+
payload["decision"] = {
|
|
1022
|
+
"code": "CAPABILITIES",
|
|
1023
|
+
"contract_version": 60,
|
|
1024
|
+
"exited_holder_release_version": 1,
|
|
1025
|
+
"canonical_refresh_version": 1,
|
|
1026
|
+
"host_handoff_continuation_version": HOST_HANDOFF_CONTINUATION_VERSION,
|
|
1027
|
+
"release_recovery_inspection_version": 1,
|
|
1028
|
+
"rollout_transaction_diagnostics_version": 1,
|
|
1029
|
+
"no_change_cleanup_closeout_version": 1,
|
|
1030
|
+
"canonical_transition_version": 1,
|
|
1031
|
+
"canonical_main_refresh_version": 1,
|
|
1032
|
+
"integration_lineage_admission_version": 1,
|
|
1033
|
+
"integration_keyed_document_scope_version": 1,
|
|
1034
|
+
"canonical_transition_retirement_version": 1,
|
|
1035
|
+
"closed_lifecycle_query_version": 1,
|
|
1036
|
+
"source_release_summary_version": 1,
|
|
1037
|
+
"tracked_source_progress_recovery_version": 1,
|
|
1038
|
+
"published_checkout_recovery_version": 1,
|
|
1039
|
+
"published_handoff_resource_registration_version": 1,
|
|
1040
|
+
"multiple_preservation_cleanup_version": 1,
|
|
1041
|
+
"multiple_preservation_recovery_version": 1,
|
|
1042
|
+
"preservation_supersession_version": 1,
|
|
1043
|
+
"retained_typed_cleanup_version": 1,
|
|
1044
|
+
"aborted_integration_preserved_cleanup_version": 1,
|
|
1045
|
+
"preservation_leaf_version": 1,
|
|
1046
|
+
"integration_publication_execution_version": 1,
|
|
1047
|
+
"integration_retry_version": 1,
|
|
1048
|
+
"integration_conflict_resolution_version": 2,
|
|
1049
|
+
"session_admission_version": 1,
|
|
1050
|
+
"capabilities_version": 1,
|
|
1051
|
+
"storage_layout_version": 5,
|
|
1052
|
+
"writer_session_version": 2,
|
|
1053
|
+
"holder_resolver_version": 1,
|
|
1054
|
+
"host_managed_writer_session_version": HOST_MANAGED_WRITER_SESSION_VERSION,
|
|
1055
|
+
"resource_admission_version": 1,
|
|
1056
|
+
"acquire_no_effect_recovery_version": 1,
|
|
1057
|
+
"execution_admission_version": 1,
|
|
1058
|
+
"host_execution_admission_version": 2,
|
|
1059
|
+
"runtime_binding_version": 1,
|
|
1060
|
+
"archived_codex_binding_recovery_version": 1,
|
|
1061
|
+
"branch_retirement_version": 1,
|
|
1062
|
+
"branch_retirement_verify_version": 1,
|
|
1063
|
+
"branch_retirement_execution_version": 1,
|
|
1064
|
+
"namespace_migration_version": 1,
|
|
1065
|
+
"governance_version": 2,
|
|
1066
|
+
"delivered_closeout_version": 1,
|
|
1067
|
+
"retained_archive_version": 1,
|
|
1068
|
+
"retention_convergence_version": 2,
|
|
1069
|
+
"session_end_selector_version": 1,
|
|
1070
|
+
"session_closeout_report_version": 1,
|
|
1071
|
+
"session_closeout_expectations_version": 1,
|
|
1072
|
+
"recovery_guidance_version": 1,
|
|
1073
|
+
"hosted_session_closeout_check_version": 1,
|
|
1074
|
+
"checkout_owner_action_version": 1,
|
|
1075
|
+
"task_checkpoint_park_version": 1,
|
|
1076
|
+
"binding_registration_backfill_version": 1,
|
|
1077
|
+
"gc_apply_replay_version": 1,
|
|
1078
|
+
"doctor_mount_version": 2,
|
|
1079
|
+
"cleanup_hardlink_topology_version": 2,
|
|
1080
|
+
"typed_cleanup_no_action_version": 1,
|
|
1081
|
+
"typed_cleanup_no_action_receipt_version": 1,
|
|
1082
|
+
"typed_cleanup_verify_boundary_version": 1,
|
|
1083
|
+
"supported_writer_session_versions": [1, 2],
|
|
1084
|
+
"writer_lease_schema_version": 2,
|
|
1085
|
+
}
|
|
1086
|
+
elif parsed.command == "publication-execution-session":
|
|
1087
|
+
from .publication_execution import run_session
|
|
1088
|
+
|
|
1089
|
+
return run_session(
|
|
1090
|
+
parsed.repo, candidate_oid=parsed.candidate_oid,
|
|
1091
|
+
lease_id=parsed.lease_id, run_id=parsed.run_id,
|
|
1092
|
+
)
|
|
1093
|
+
elif parsed.command == "status":
|
|
1094
|
+
payload = status(parsed.repo, namespace_pid=parsed.namespace_pid)
|
|
1095
|
+
elif parsed.command == "canonical-refresh":
|
|
1096
|
+
from .canonical_refresh import refresh_canonical
|
|
1097
|
+
|
|
1098
|
+
payload = refresh_canonical(parsed.repo, dry_run=parsed.dry_run)
|
|
1099
|
+
elif parsed.command == "canonical-transition":
|
|
1100
|
+
from .canonical_transition import transition_canonical
|
|
1101
|
+
|
|
1102
|
+
payload = transition_canonical(
|
|
1103
|
+
parsed.repo, target=parsed.path,
|
|
1104
|
+
expected_record_version=parsed.expected_record_version,
|
|
1105
|
+
owner=parsed.owner, expected_branch=parsed.expected_branch,
|
|
1106
|
+
expected_head=parsed.expected_head,
|
|
1107
|
+
expected_main_head=parsed.expected_main_head,
|
|
1108
|
+
expected_remote_head=parsed.expected_remote_head,
|
|
1109
|
+
new_owner=parsed.new_owner, new_task_key=parsed.new_task_key,
|
|
1110
|
+
new_authority_key=parsed.new_authority_key,
|
|
1111
|
+
)
|
|
1112
|
+
elif parsed.command == "lifecycle-history":
|
|
1113
|
+
from .lifecycle_history import lifecycle_history
|
|
1114
|
+
|
|
1115
|
+
payload = lifecycle_history(
|
|
1116
|
+
parsed.repo, allocation_id=parsed.allocation_id,
|
|
1117
|
+
authority_key=parsed.authority_key, task_key=parsed.task_key,
|
|
1118
|
+
integration_intent_id=parsed.integration_intent_id,
|
|
1119
|
+
release_receipt_id=parsed.release_receipt_id,
|
|
1120
|
+
limit=parsed.limit, after=parsed.after,
|
|
1121
|
+
)
|
|
1122
|
+
elif parsed.command == "recovery-guide":
|
|
1123
|
+
from .recovery_guidance import recovery_guide
|
|
1124
|
+
|
|
1125
|
+
payload = recovery_guide(parsed.repo, target=parsed.path, intent_id=parsed.intent_id)
|
|
1126
|
+
elif parsed.command == "release-recovery-inspect":
|
|
1127
|
+
from . import cleanup_recovery
|
|
1128
|
+
|
|
1129
|
+
payload = cleanup_recovery.inspect_release(parsed.repo, transaction_id=parsed.transaction_id)
|
|
1130
|
+
elif parsed.command == "admission-queue":
|
|
1131
|
+
from .resource_admission import reconcile as reconcile_admission
|
|
1132
|
+
|
|
1133
|
+
payload = reconcile_admission(repository_path=None if parsed.all_repositories else parsed.repo,
|
|
1134
|
+
apply=parsed.apply)
|
|
1135
|
+
elif parsed.command == "host-execution":
|
|
1136
|
+
from .resource_admission import host_execution
|
|
1137
|
+
|
|
1138
|
+
evidence = None
|
|
1139
|
+
if parsed.terminal_evidence is not None:
|
|
1140
|
+
try:
|
|
1141
|
+
evidence = json.loads(parsed.terminal_evidence)
|
|
1142
|
+
except ValueError:
|
|
1143
|
+
raise ControllerError("INVALID_REQUEST", "terminal evidence must be canonical JSON") from None
|
|
1144
|
+
payload = host_execution(parsed.action, target=parsed.path, request_id=parsed.request_id,
|
|
1145
|
+
client_id=parsed.client_id, session_id=parsed.session_id, run_id=parsed.run_id,
|
|
1146
|
+
holder_pid=parsed.holder_pid, memory_bytes=parsed.memory_bytes,
|
|
1147
|
+
recover_dead_holder=parsed.recover_dead_holder,
|
|
1148
|
+
expected_holder_sha256=parsed.expected_holder_sha256,
|
|
1149
|
+
terminal_evidence=evidence)
|
|
1150
|
+
elif parsed.command == "session-admit":
|
|
1151
|
+
from .convergence import admission_convergence
|
|
1152
|
+
from .session_admission import admit_session
|
|
1153
|
+
|
|
1154
|
+
payload = admit_session(
|
|
1155
|
+
parsed.repo, task_key=parsed.task_key, authority_key=parsed.authority_key,
|
|
1156
|
+
module=parsed.module, owner=parsed.owner, branch=parsed.branch,
|
|
1157
|
+
base_ref=parsed.base_ref, client_id=parsed.client_id,
|
|
1158
|
+
session_id=parsed.session_id, run_id=parsed.run_id,
|
|
1159
|
+
)
|
|
1160
|
+
if payload["decision"].get("code") in {"SESSION_ADMITTED", "RESOURCE_WAIT"}:
|
|
1161
|
+
# Started after admission, so the pass never holds the lock this
|
|
1162
|
+
# admission needs; it still runs on every admission that changed state.
|
|
1163
|
+
convergence = admission_convergence(parsed.repo)
|
|
1164
|
+
if convergence is not None:
|
|
1165
|
+
payload["retention_convergence"] = convergence
|
|
1166
|
+
elif parsed.command == "session-bind":
|
|
1167
|
+
from .session_admission import bind_session
|
|
1168
|
+
|
|
1169
|
+
payload = bind_session(
|
|
1170
|
+
parsed.repo, target=parsed.path, task_key=parsed.task_key,
|
|
1171
|
+
authority_key=parsed.authority_key, owner=parsed.owner,
|
|
1172
|
+
client_id=parsed.client_id, holder_pid=parsed.holder_pid,
|
|
1173
|
+
session_id=parsed.session_id, run_id=parsed.run_id, kind=parsed.kind,
|
|
1174
|
+
)
|
|
1175
|
+
elif parsed.command in {"execution-admit", "execution-cancel"}:
|
|
1176
|
+
from .resource_admission import admit_execution
|
|
1177
|
+
|
|
1178
|
+
payload = admit_execution(parsed.repo, target=parsed.path, owner=parsed.owner,
|
|
1179
|
+
client_id=parsed.client_id, session_id=parsed.session_id,
|
|
1180
|
+
run_id=parsed.run_id, memory_bytes=parsed.memory_bytes,
|
|
1181
|
+
cancel=parsed.command == "execution-cancel", _cache_recovery=True)
|
|
1182
|
+
elif parsed.command == "plan":
|
|
1183
|
+
payload = plan(
|
|
1184
|
+
parsed.repo,
|
|
1185
|
+
task_key=parsed.task_key,
|
|
1186
|
+
authority_key=parsed.authority_key,
|
|
1187
|
+
module=parsed.module,
|
|
1188
|
+
role=parsed.role,
|
|
1189
|
+
target=parsed.target,
|
|
1190
|
+
)
|
|
1191
|
+
elif parsed.command == "write-guard":
|
|
1192
|
+
payload = guard_write(
|
|
1193
|
+
parsed.repo,
|
|
1194
|
+
target=parsed.path,
|
|
1195
|
+
task_key=parsed.task_key,
|
|
1196
|
+
authority_key=parsed.authority_key,
|
|
1197
|
+
owner=parsed.owner,
|
|
1198
|
+
operation=parsed.operation,
|
|
1199
|
+
holder=(
|
|
1200
|
+
resolve_holder(
|
|
1201
|
+
parsed.holder,
|
|
1202
|
+
client_id=parsed.client_id,
|
|
1203
|
+
session_id=parsed.session_id,
|
|
1204
|
+
run_id=parsed.run_id,
|
|
1205
|
+
)
|
|
1206
|
+
if parsed.holder
|
|
1207
|
+
else None
|
|
1208
|
+
),
|
|
1209
|
+
)
|
|
1210
|
+
elif parsed.command == "adopt":
|
|
1211
|
+
payload = adopt(
|
|
1212
|
+
parsed.repo,
|
|
1213
|
+
target=parsed.path,
|
|
1214
|
+
task_key=parsed.task_key,
|
|
1215
|
+
authority_key=parsed.authority_key,
|
|
1216
|
+
module=parsed.module,
|
|
1217
|
+
role=parsed.role,
|
|
1218
|
+
owner=parsed.owner,
|
|
1219
|
+
lifecycle=parsed.lifecycle,
|
|
1220
|
+
base_commit=parsed.base_commit,
|
|
1221
|
+
task_commit=parsed.task_commit,
|
|
1222
|
+
scope_paths=tuple(parsed.scope),
|
|
1223
|
+
source_allocations=tuple(parsed.source_allocation),
|
|
1224
|
+
external_bindings=tuple(parsed.external_binding),
|
|
1225
|
+
)
|
|
1226
|
+
elif parsed.command == "acquire":
|
|
1227
|
+
from .convergence import admission_convergence
|
|
1228
|
+
|
|
1229
|
+
try:
|
|
1230
|
+
payload = acquire(
|
|
1231
|
+
parsed.repo,
|
|
1232
|
+
task_key=parsed.task_key,
|
|
1233
|
+
authority_key=parsed.authority_key,
|
|
1234
|
+
module=parsed.module,
|
|
1235
|
+
role=parsed.role,
|
|
1236
|
+
owner=parsed.owner,
|
|
1237
|
+
branch=parsed.branch,
|
|
1238
|
+
base_ref=parsed.base_ref,
|
|
1239
|
+
target=parsed.path,
|
|
1240
|
+
scope_paths=tuple(parsed.scope),
|
|
1241
|
+
source_allocations=tuple(parsed.source_allocation),
|
|
1242
|
+
source_handoffs=tuple(parsed.source_handoff),
|
|
1243
|
+
external_bindings=tuple(parsed.external_binding),
|
|
1244
|
+
)
|
|
1245
|
+
finally:
|
|
1246
|
+
# After the acquisition, including a refused one, so the detached
|
|
1247
|
+
# pass never queues this admission behind its repository lock.
|
|
1248
|
+
convergence = admission_convergence(parsed.repo)
|
|
1249
|
+
if convergence is not None:
|
|
1250
|
+
payload["retention_convergence"] = convergence
|
|
1251
|
+
elif parsed.command == "integration-queue":
|
|
1252
|
+
payload = integration_queue(parsed.repo)
|
|
1253
|
+
elif parsed.command == "integration-enqueue":
|
|
1254
|
+
payload = enqueue_integration(
|
|
1255
|
+
parsed.repo,
|
|
1256
|
+
task_key=parsed.task_key,
|
|
1257
|
+
authority_key=parsed.authority_key,
|
|
1258
|
+
module=parsed.module,
|
|
1259
|
+
owner=parsed.owner,
|
|
1260
|
+
source_allocations=tuple(parsed.source_allocation),
|
|
1261
|
+
source_handoffs=tuple(parsed.source_handoff),
|
|
1262
|
+
source_snapshot_ids=tuple(parsed.source_snapshot),
|
|
1263
|
+
)
|
|
1264
|
+
elif parsed.command == "integration-claim":
|
|
1265
|
+
payload = claim_integration(
|
|
1266
|
+
parsed.repo,
|
|
1267
|
+
owner=parsed.owner,
|
|
1268
|
+
intent_id=parsed.intent_id,
|
|
1269
|
+
target=parsed.path,
|
|
1270
|
+
branch=parsed.branch,
|
|
1271
|
+
resolve_conflicts=parsed.resolve_conflicts,
|
|
1272
|
+
)
|
|
1273
|
+
elif parsed.command == "integration-resolve":
|
|
1274
|
+
payload = resolve_integration(
|
|
1275
|
+
parsed.repo, target=parsed.path,
|
|
1276
|
+
expected_record_version=parsed.expected_record_version, owner=parsed.owner,
|
|
1277
|
+
expected_head=parsed.expected_head, finalizer_record_id=parsed.finalizer_record_id,
|
|
1278
|
+
)
|
|
1279
|
+
elif parsed.command == "integration-refresh":
|
|
1280
|
+
payload = refresh_integration(
|
|
1281
|
+
parsed.repo,
|
|
1282
|
+
target=parsed.path,
|
|
1283
|
+
expected_record_version=parsed.expected_record_version,
|
|
1284
|
+
owner=parsed.owner,
|
|
1285
|
+
)
|
|
1286
|
+
elif parsed.command == "integration-validate":
|
|
1287
|
+
payload = validate_integration(
|
|
1288
|
+
parsed.repo,
|
|
1289
|
+
target=parsed.path,
|
|
1290
|
+
expected_record_version=parsed.expected_record_version,
|
|
1291
|
+
owner=parsed.owner,
|
|
1292
|
+
validation_evidence_id=parsed.validation_evidence_id,
|
|
1293
|
+
tests_receipt_id=parsed.tests_receipt_id,
|
|
1294
|
+
snapshot_receipt_id=parsed.snapshot_receipt_id,
|
|
1295
|
+
)
|
|
1296
|
+
elif parsed.command == "integration-reopen":
|
|
1297
|
+
payload = reopen_integration(
|
|
1298
|
+
parsed.repo,
|
|
1299
|
+
target=parsed.path,
|
|
1300
|
+
expected_record_version=parsed.expected_record_version,
|
|
1301
|
+
owner=parsed.owner,
|
|
1302
|
+
)
|
|
1303
|
+
elif parsed.command == "lifecycle-events":
|
|
1304
|
+
payload = lifecycle_events(parsed.repo, consumer=parsed.consumer)
|
|
1305
|
+
elif parsed.command == "lifecycle-event-ack":
|
|
1306
|
+
payload = acknowledge_lifecycle_event(
|
|
1307
|
+
parsed.repo,
|
|
1308
|
+
consumer=parsed.consumer,
|
|
1309
|
+
event_id=parsed.event_id,
|
|
1310
|
+
)
|
|
1311
|
+
elif parsed.command == "integration-recovery-matrix":
|
|
1312
|
+
payload = integration_recovery_matrix(parsed.repo)
|
|
1313
|
+
elif parsed.command == "integration-equivalent":
|
|
1314
|
+
payload = record_equivalent_replay(
|
|
1315
|
+
parsed.repo,
|
|
1316
|
+
target=parsed.path,
|
|
1317
|
+
expected_record_version=parsed.expected_record_version,
|
|
1318
|
+
owner=parsed.owner,
|
|
1319
|
+
source_allocation_id=parsed.source_allocation,
|
|
1320
|
+
source_handoff=parsed.source_handoff,
|
|
1321
|
+
replay_commit=parsed.replay_commit,
|
|
1322
|
+
evidence_id=parsed.evidence_id,
|
|
1323
|
+
)
|
|
1324
|
+
elif parsed.command == "close-delivered":
|
|
1325
|
+
payload = close_delivered(
|
|
1326
|
+
parsed.repo, target=parsed.path,
|
|
1327
|
+
expected_record_version=parsed.expected_record_version,
|
|
1328
|
+
owner_release=parsed.owner_release, actor=parsed.actor,
|
|
1329
|
+
dry_run=parsed.dry_run, plan_id=parsed.plan_id,
|
|
1330
|
+
)
|
|
1331
|
+
elif parsed.command == "archive-retained":
|
|
1332
|
+
payload = archive_retained(
|
|
1333
|
+
parsed.repo, target=parsed.path,
|
|
1334
|
+
expected_record_version=parsed.expected_record_version,
|
|
1335
|
+
owner_release=parsed.owner_release, actor=parsed.actor,
|
|
1336
|
+
dry_run=parsed.dry_run, plan_id=parsed.plan_id,
|
|
1337
|
+
)
|
|
1338
|
+
elif parsed.command in {"complete-no-change", "close-preserved"}:
|
|
1339
|
+
close = close_preserved if parsed.command == "close-preserved" else complete_no_change
|
|
1340
|
+
payload = close(
|
|
1341
|
+
parsed.repo,
|
|
1342
|
+
target=parsed.path,
|
|
1343
|
+
expected_record_version=parsed.expected_record_version,
|
|
1344
|
+
owner=parsed.owner,
|
|
1345
|
+
)
|
|
1346
|
+
elif parsed.command == "integration-abandon":
|
|
1347
|
+
payload = abandon_integration_intent(
|
|
1348
|
+
parsed.repo,
|
|
1349
|
+
intent_id=parsed.intent_id,
|
|
1350
|
+
owner=parsed.owner,
|
|
1351
|
+
reason=parsed.reason,
|
|
1352
|
+
)
|
|
1353
|
+
elif parsed.command == "integration-abort":
|
|
1354
|
+
payload = abort_integration(
|
|
1355
|
+
parsed.repo,
|
|
1356
|
+
target=parsed.path,
|
|
1357
|
+
expected_record_version=parsed.expected_record_version,
|
|
1358
|
+
owner=parsed.owner,
|
|
1359
|
+
reason=parsed.reason,
|
|
1360
|
+
)
|
|
1361
|
+
elif parsed.command == "integration-retry":
|
|
1362
|
+
payload = retry_integration(
|
|
1363
|
+
parsed.repo, intent_id=parsed.intent_id, owner=parsed.owner,
|
|
1364
|
+
reason=parsed.reason, prerequisite_intent_id=parsed.prerequisite_intent,
|
|
1365
|
+
dry_run=parsed.dry_run, expected_plan_id=parsed.expected_plan_id,
|
|
1366
|
+
)
|
|
1367
|
+
elif parsed.command == "reconcile-session":
|
|
1368
|
+
payload = reconcile_session(
|
|
1369
|
+
parsed.repo,
|
|
1370
|
+
target=parsed.path,
|
|
1371
|
+
expected_record_version=parsed.expected_record_version,
|
|
1372
|
+
owner=parsed.owner,
|
|
1373
|
+
trigger=parsed.trigger,
|
|
1374
|
+
)
|
|
1375
|
+
elif parsed.command == "writer-lease-acquire":
|
|
1376
|
+
payload = acquire_writer_lease(
|
|
1377
|
+
parsed.repo,
|
|
1378
|
+
target=parsed.path,
|
|
1379
|
+
owner=parsed.owner,
|
|
1380
|
+
client_id=parsed.client_id,
|
|
1381
|
+
holder_pid=parsed.holder_pid,
|
|
1382
|
+
session_id=parsed.session_id,
|
|
1383
|
+
run_id=parsed.run_id,
|
|
1384
|
+
ttl_seconds=parsed.ttl_seconds,
|
|
1385
|
+
expected_record_version=parsed.expected_record_version,
|
|
1386
|
+
)
|
|
1387
|
+
elif parsed.command == "writer-lease-release":
|
|
1388
|
+
payload = release_writer_lease(
|
|
1389
|
+
parsed.repo,
|
|
1390
|
+
target=parsed.path,
|
|
1391
|
+
holder_pid=parsed.holder_pid,
|
|
1392
|
+
lease_id=parsed.lease_id,
|
|
1393
|
+
holder=(
|
|
1394
|
+
WriterHolder(
|
|
1395
|
+
client_id=parsed.client_id,
|
|
1396
|
+
pid=parsed.holder_pid,
|
|
1397
|
+
boot_id=parsed.holder_boot_id,
|
|
1398
|
+
start_ticks=parsed.holder_start_ticks,
|
|
1399
|
+
session_id=parsed.session_id,
|
|
1400
|
+
run_id=parsed.run_id,
|
|
1401
|
+
)
|
|
1402
|
+
if all(
|
|
1403
|
+
value is not None
|
|
1404
|
+
for value in (
|
|
1405
|
+
parsed.holder_pid,
|
|
1406
|
+
parsed.holder_boot_id,
|
|
1407
|
+
parsed.holder_start_ticks,
|
|
1408
|
+
)
|
|
1409
|
+
)
|
|
1410
|
+
else None
|
|
1411
|
+
),
|
|
1412
|
+
)
|
|
1413
|
+
elif parsed.command == "reconcile-writers":
|
|
1414
|
+
payload = reconcile_writers(
|
|
1415
|
+
parsed.repo,
|
|
1416
|
+
actor=parsed.actor,
|
|
1417
|
+
trigger=parsed.trigger,
|
|
1418
|
+
dry_run=not parsed.apply,
|
|
1419
|
+
adopt_legacy=parsed.adopt_legacy,
|
|
1420
|
+
only=tuple(parsed.only),
|
|
1421
|
+
)
|
|
1422
|
+
elif parsed.command == "acquire-when-free":
|
|
1423
|
+
payload = acquire_when_free(
|
|
1424
|
+
parsed.repo,
|
|
1425
|
+
deadline_seconds=parsed.deadline_seconds,
|
|
1426
|
+
poll_seconds=parsed.poll_seconds,
|
|
1427
|
+
task_key=parsed.task_key,
|
|
1428
|
+
authority_key=parsed.authority_key,
|
|
1429
|
+
module=parsed.module,
|
|
1430
|
+
role=parsed.role,
|
|
1431
|
+
owner=parsed.owner,
|
|
1432
|
+
branch=parsed.branch,
|
|
1433
|
+
base_ref=parsed.base_ref,
|
|
1434
|
+
target=parsed.path,
|
|
1435
|
+
scope_paths=tuple(parsed.scope),
|
|
1436
|
+
)
|
|
1437
|
+
elif parsed.command == "acquire-across":
|
|
1438
|
+
payload = acquire_across([json.loads(item) for item in parsed.request])
|
|
1439
|
+
elif parsed.command == "park":
|
|
1440
|
+
payload = park(
|
|
1441
|
+
parsed.repo,
|
|
1442
|
+
target=parsed.path,
|
|
1443
|
+
expected_record_version=parsed.expected_record_version,
|
|
1444
|
+
owner=parsed.owner,
|
|
1445
|
+
checkpoint_id=parsed.checkpoint_id,
|
|
1446
|
+
checkpoint_head=parsed.checkpoint_head,
|
|
1447
|
+
waiting_on=parsed.waiting_on,
|
|
1448
|
+
)
|
|
1449
|
+
elif parsed.command == "resume":
|
|
1450
|
+
payload = resume(
|
|
1451
|
+
parsed.repo,
|
|
1452
|
+
target=parsed.path,
|
|
1453
|
+
expected_record_version=parsed.expected_record_version,
|
|
1454
|
+
owner=parsed.owner,
|
|
1455
|
+
)
|
|
1456
|
+
elif parsed.command == "adopt-delivered":
|
|
1457
|
+
payload = adopt_delivered(
|
|
1458
|
+
parsed.repo,
|
|
1459
|
+
target=parsed.path,
|
|
1460
|
+
expected_record_version=parsed.expected_record_version,
|
|
1461
|
+
new_owner=parsed.new_owner,
|
|
1462
|
+
actor=parsed.actor,
|
|
1463
|
+
)
|
|
1464
|
+
elif parsed.command == "review":
|
|
1465
|
+
payload = review(
|
|
1466
|
+
parsed.repo,
|
|
1467
|
+
target=parsed.path,
|
|
1468
|
+
expected_record_version=parsed.expected_record_version,
|
|
1469
|
+
owner=parsed.owner,
|
|
1470
|
+
new_owner=parsed.new_owner,
|
|
1471
|
+
add_scope_paths=tuple(parsed.add_scope),
|
|
1472
|
+
expected_head=parsed.expected_head,
|
|
1473
|
+
scope_reason=parsed.scope_reason,
|
|
1474
|
+
)
|
|
1475
|
+
elif parsed.command == "handoff":
|
|
1476
|
+
payload = handoff(
|
|
1477
|
+
parsed.repo,
|
|
1478
|
+
target=parsed.path,
|
|
1479
|
+
expected_record_version=parsed.expected_record_version,
|
|
1480
|
+
kind=parsed.kind,
|
|
1481
|
+
commit=parsed.commit,
|
|
1482
|
+
finalizer_record_id=parsed.finalizer_record_id,
|
|
1483
|
+
finalizer_commit=parsed.finalizer_commit,
|
|
1484
|
+
scope_paths=tuple(parsed.scope),
|
|
1485
|
+
mainline_commit=parsed.mainline_commit,
|
|
1486
|
+
scope_changed=parsed.scope_changed,
|
|
1487
|
+
)
|
|
1488
|
+
elif parsed.command == "quarantine":
|
|
1489
|
+
payload = quarantine(
|
|
1490
|
+
parsed.repo,
|
|
1491
|
+
target=parsed.path,
|
|
1492
|
+
expected_record_version=parsed.expected_record_version,
|
|
1493
|
+
owner=parsed.owner,
|
|
1494
|
+
reason=parsed.reason,
|
|
1495
|
+
expected_commit=parsed.expected_commit,
|
|
1496
|
+
)
|
|
1497
|
+
elif parsed.command == "externalize":
|
|
1498
|
+
payload = externalize(
|
|
1499
|
+
parsed.repo,
|
|
1500
|
+
source_target=parsed.source_path,
|
|
1501
|
+
recovery_target=parsed.recovery_path,
|
|
1502
|
+
expected_source_record_version=parsed.expected_source_record_version,
|
|
1503
|
+
expected_recovery_record_version=parsed.expected_recovery_record_version,
|
|
1504
|
+
owner=parsed.owner,
|
|
1505
|
+
)
|
|
1506
|
+
elif parsed.command == "recovery-adopt":
|
|
1507
|
+
payload = adopt_recovery(
|
|
1508
|
+
parsed.repo,
|
|
1509
|
+
source_target=parsed.source_path,
|
|
1510
|
+
recovery_target=parsed.recovery_path,
|
|
1511
|
+
expected_source_record_version=parsed.expected_source_record_version,
|
|
1512
|
+
expected_recovery_record_version=parsed.expected_recovery_record_version,
|
|
1513
|
+
source_owner=parsed.source_owner,
|
|
1514
|
+
recovery_owner=parsed.recovery_owner,
|
|
1515
|
+
scope_paths=tuple(parsed.scope),
|
|
1516
|
+
)
|
|
1517
|
+
elif parsed.command == "resource-register":
|
|
1518
|
+
payload = register_disposable(
|
|
1519
|
+
parsed.repo,
|
|
1520
|
+
target=parsed.path,
|
|
1521
|
+
expected_record_version=parsed.expected_record_version,
|
|
1522
|
+
owner=parsed.owner,
|
|
1523
|
+
resource_path=parsed.resource_path,
|
|
1524
|
+
kind=parsed.kind,
|
|
1525
|
+
reproducible=parsed.reproducible,
|
|
1526
|
+
creator=parsed.creator,
|
|
1527
|
+
teardown_policy=parsed.teardown_policy,
|
|
1528
|
+
)
|
|
1529
|
+
elif parsed.command == "resource-clean":
|
|
1530
|
+
if parsed.typed:
|
|
1531
|
+
payload = cleanup_typed_disposable(
|
|
1532
|
+
parsed.repo,
|
|
1533
|
+
target=parsed.path,
|
|
1534
|
+
expected_record_version=parsed.expected_record_version,
|
|
1535
|
+
owner=parsed.owner,
|
|
1536
|
+
dry_run=parsed.dry_run,
|
|
1537
|
+
expected_plan_id=parsed.expected_plan_id,
|
|
1538
|
+
preservation_receipt=parsed.preservation_receipt,
|
|
1539
|
+
preservation_receipt_sha256=parsed.preservation_receipt_sha256,
|
|
1540
|
+
additional_preservation_receipts=tuple(parsed.additional_preservation_receipt),
|
|
1541
|
+
additional_preservation_receipt_sha256=tuple(
|
|
1542
|
+
parsed.additional_preservation_receipt_sha256
|
|
1543
|
+
),
|
|
1544
|
+
)
|
|
1545
|
+
else:
|
|
1546
|
+
if (
|
|
1547
|
+
parsed.dry_run
|
|
1548
|
+
or parsed.expected_plan_id
|
|
1549
|
+
or parsed.preservation_receipt
|
|
1550
|
+
or parsed.preservation_receipt_sha256
|
|
1551
|
+
or parsed.additional_preservation_receipt
|
|
1552
|
+
or parsed.additional_preservation_receipt_sha256
|
|
1553
|
+
):
|
|
1554
|
+
raise ControllerError("INVALID_RESOURCE", "dry-run and plan id require --typed")
|
|
1555
|
+
payload = cleanup_disposable(
|
|
1556
|
+
parsed.repo,
|
|
1557
|
+
target=parsed.path,
|
|
1558
|
+
expected_record_version=parsed.expected_record_version,
|
|
1559
|
+
owner=parsed.owner,
|
|
1560
|
+
resource_path=parsed.resource_path,
|
|
1561
|
+
)
|
|
1562
|
+
elif parsed.command == "resource-recover":
|
|
1563
|
+
from . import cleanup_recovery
|
|
1564
|
+
|
|
1565
|
+
if parsed.stage == "rollout-check":
|
|
1566
|
+
if not parsed.dry_run:
|
|
1567
|
+
raise ControllerError("INVALID_RECOVERY", "rollout check requires --dry-run")
|
|
1568
|
+
payload = cleanup_recovery.rollout_check(
|
|
1569
|
+
parsed.repo,
|
|
1570
|
+
receipt_path=parsed.preservation_receipt,
|
|
1571
|
+
receipt_sha=parsed.preservation_receipt_sha256,
|
|
1572
|
+
)
|
|
1573
|
+
elif parsed.stage == "reconcile-typed":
|
|
1574
|
+
if not parsed.transaction_id or not parsed.transaction_sha256:
|
|
1575
|
+
raise ControllerError("INVALID_RECOVERY", "exact typed transaction and digest required")
|
|
1576
|
+
from .cleanup_attempts import reconcile_typed
|
|
1577
|
+
|
|
1578
|
+
payload = reconcile_typed(parsed.repo, parsed.transaction_id, parsed.transaction_sha256,
|
|
1579
|
+
dry_run=parsed.dry_run, expected_plan_id=parsed.expected_plan_id)
|
|
1580
|
+
elif parsed.stage == "prepare-multiple":
|
|
1581
|
+
if not all([
|
|
1582
|
+
parsed.path, parsed.owner, parsed.expected_record_version,
|
|
1583
|
+
parsed.transaction_id, parsed.transaction_sha256,
|
|
1584
|
+
parsed.cleanup_receipt_sha256,
|
|
1585
|
+
]):
|
|
1586
|
+
raise ControllerError(
|
|
1587
|
+
"INVALID_RECOVERY", "exact original multiple cleanup bindings required"
|
|
1588
|
+
)
|
|
1589
|
+
from . import multiple_cleanup_recovery
|
|
1590
|
+
|
|
1591
|
+
payload = multiple_cleanup_recovery.prepare(
|
|
1592
|
+
parsed.repo, target=parsed.path, owner=parsed.owner,
|
|
1593
|
+
version=parsed.expected_record_version,
|
|
1594
|
+
recovery=multiple_cleanup_recovery.context(
|
|
1595
|
+
parsed.transaction_id, parsed.transaction_sha256,
|
|
1596
|
+
parsed.cleanup_receipt_sha256,
|
|
1597
|
+
),
|
|
1598
|
+
dry_run=parsed.dry_run, expected_plan_id=parsed.expected_plan_id,
|
|
1599
|
+
)
|
|
1600
|
+
elif parsed.stage == "prepare":
|
|
1601
|
+
if not all(
|
|
1602
|
+
[
|
|
1603
|
+
parsed.path,
|
|
1604
|
+
parsed.owner,
|
|
1605
|
+
parsed.expected_record_version,
|
|
1606
|
+
parsed.transaction_id,
|
|
1607
|
+
parsed.transaction_sha256,
|
|
1608
|
+
parsed.cleanup_receipt_sha256,
|
|
1609
|
+
parsed.preservation_receipt,
|
|
1610
|
+
parsed.preservation_receipt_sha256,
|
|
1611
|
+
]
|
|
1612
|
+
):
|
|
1613
|
+
raise ControllerError(
|
|
1614
|
+
"INVALID_RECOVERY", "exact original and new preservation bindings required"
|
|
1615
|
+
)
|
|
1616
|
+
payload = cleanup_recovery.prepare(
|
|
1617
|
+
parsed.repo,
|
|
1618
|
+
target=parsed.path,
|
|
1619
|
+
owner=parsed.owner,
|
|
1620
|
+
version=parsed.expected_record_version,
|
|
1621
|
+
recovery=cleanup_recovery.context(
|
|
1622
|
+
parsed.transaction_id,
|
|
1623
|
+
parsed.transaction_sha256,
|
|
1624
|
+
parsed.cleanup_receipt_sha256,
|
|
1625
|
+
),
|
|
1626
|
+
receipt_path=parsed.preservation_receipt,
|
|
1627
|
+
receipt_sha=parsed.preservation_receipt_sha256,
|
|
1628
|
+
dry_run=parsed.dry_run,
|
|
1629
|
+
expected_plan_id=parsed.expected_plan_id,
|
|
1630
|
+
)
|
|
1631
|
+
else:
|
|
1632
|
+
if not parsed.recovery_receipt or not parsed.recovery_receipt_sha256:
|
|
1633
|
+
raise ControllerError(
|
|
1634
|
+
"INVALID_RECOVERY", "immutable recovery record and trusted digest required"
|
|
1635
|
+
)
|
|
1636
|
+
recovery_options = dict(
|
|
1637
|
+
recovery_path=parsed.recovery_receipt,
|
|
1638
|
+
recovery_sha=parsed.recovery_receipt_sha256,
|
|
1639
|
+
dry_run=parsed.dry_run,
|
|
1640
|
+
)
|
|
1641
|
+
if parsed.stage == "reconcile-attempt":
|
|
1642
|
+
payload = cleanup_recovery.reconcile_attempt(
|
|
1643
|
+
parsed.repo, **recovery_options, expected_plan_id=parsed.expected_plan_id
|
|
1644
|
+
)
|
|
1645
|
+
else:
|
|
1646
|
+
payload = cleanup_recovery.resume(parsed.repo, **recovery_options)
|
|
1647
|
+
elif parsed.command == "lease-acquire":
|
|
1648
|
+
payload = acquire_publication_lease(
|
|
1649
|
+
parsed.repo,
|
|
1650
|
+
target=parsed.path,
|
|
1651
|
+
expected_record_version=parsed.expected_record_version,
|
|
1652
|
+
owner=parsed.owner,
|
|
1653
|
+
run_id=parsed.run_id,
|
|
1654
|
+
ttl_seconds=parsed.ttl_seconds,
|
|
1655
|
+
)
|
|
1656
|
+
elif parsed.command == "lease-complete":
|
|
1657
|
+
payload = complete_publication_lease(
|
|
1658
|
+
parsed.repo,
|
|
1659
|
+
target=parsed.path,
|
|
1660
|
+
expected_record_version=parsed.expected_record_version,
|
|
1661
|
+
lease_id=parsed.lease_id,
|
|
1662
|
+
published_commit=parsed.published_commit,
|
|
1663
|
+
finalizer_record_id=parsed.finalizer_record_id,
|
|
1664
|
+
run_id=parsed.run_id,
|
|
1665
|
+
auto_release=parsed.auto_release,
|
|
1666
|
+
)
|
|
1667
|
+
elif parsed.command == "lease-abort":
|
|
1668
|
+
payload = abort_publication_lease(
|
|
1669
|
+
parsed.repo,
|
|
1670
|
+
target=parsed.path,
|
|
1671
|
+
expected_record_version=parsed.expected_record_version,
|
|
1672
|
+
lease_id=parsed.lease_id,
|
|
1673
|
+
owner=parsed.owner,
|
|
1674
|
+
run_id=parsed.run_id,
|
|
1675
|
+
)
|
|
1676
|
+
elif parsed.command == "release":
|
|
1677
|
+
payload = release(
|
|
1678
|
+
parsed.repo,
|
|
1679
|
+
target=parsed.path,
|
|
1680
|
+
expected_record_version=parsed.expected_record_version,
|
|
1681
|
+
owner_release=parsed.owner_release,
|
|
1682
|
+
teardown_reproducible_venv=parsed.teardown_reproducible_venv,
|
|
1683
|
+
dry_run=parsed.dry_run,
|
|
1684
|
+
release_intent_id=parsed.intent_id,
|
|
1685
|
+
publication_receipt_id=parsed.publication_receipt_id,
|
|
1686
|
+
)
|
|
1687
|
+
elif parsed.command == "gc-plan":
|
|
1688
|
+
payload = gc_plan(
|
|
1689
|
+
parsed.repo,
|
|
1690
|
+
target=parsed.path,
|
|
1691
|
+
owner_release=parsed.owner_release,
|
|
1692
|
+
release_intent_id=parsed.intent_id,
|
|
1693
|
+
namespace_pid=parsed.namespace_pid,
|
|
1694
|
+
)
|
|
1695
|
+
elif parsed.command == "gc-apply":
|
|
1696
|
+
payload = gc_apply(
|
|
1697
|
+
parsed.repo,
|
|
1698
|
+
target=parsed.path,
|
|
1699
|
+
expected_gc_plan_id=parsed.plan_id,
|
|
1700
|
+
owner_release=parsed.owner_release,
|
|
1701
|
+
release_intent_id=parsed.intent_id,
|
|
1702
|
+
)
|
|
1703
|
+
elif parsed.command == "release-intent":
|
|
1704
|
+
payload = create_release_intent(
|
|
1705
|
+
parsed.repo,
|
|
1706
|
+
target=parsed.path,
|
|
1707
|
+
expected_record_version=parsed.expected_record_version,
|
|
1708
|
+
owner=parsed.owner,
|
|
1709
|
+
trigger=parsed.trigger,
|
|
1710
|
+
integration_intent_id=parsed.integration_intent_id,
|
|
1711
|
+
)
|
|
1712
|
+
elif parsed.command == "branch-retirement-plan":
|
|
1713
|
+
payload = plan_branch_retirement(
|
|
1714
|
+
parsed.repo,
|
|
1715
|
+
allocation_id=parsed.allocation_id,
|
|
1716
|
+
branch=parsed.branch,
|
|
1717
|
+
remote=parsed.remote,
|
|
1718
|
+
integrated_into=parsed.integrated_into,
|
|
1719
|
+
dry_run=parsed.dry_run,
|
|
1720
|
+
)
|
|
1721
|
+
elif parsed.command == "branch-retirement-status":
|
|
1722
|
+
payload = branch_retirement_status(parsed.repo, plan_id=parsed.plan_id)
|
|
1723
|
+
elif parsed.command == "branch-retirement-verify":
|
|
1724
|
+
payload = verify_branch_retirement(
|
|
1725
|
+
parsed.repo,
|
|
1726
|
+
plan_id=parsed.plan_id,
|
|
1727
|
+
operation=parsed.operation,
|
|
1728
|
+
)
|
|
1729
|
+
elif parsed.command == "branch-retirement-authorize":
|
|
1730
|
+
payload = authorize_branch_retirement(
|
|
1731
|
+
parsed.repo,
|
|
1732
|
+
plan_id=parsed.plan_id,
|
|
1733
|
+
operation=parsed.operation,
|
|
1734
|
+
request_id=parsed.request_id,
|
|
1735
|
+
holder=parsed.holder,
|
|
1736
|
+
client_id=parsed.client_id,
|
|
1737
|
+
session_id=parsed.session_id,
|
|
1738
|
+
run_id=parsed.run_id,
|
|
1739
|
+
kind=KIND_CAS_DELETE,
|
|
1740
|
+
ttl_seconds=parsed.ttl_seconds,
|
|
1741
|
+
)
|
|
1742
|
+
elif parsed.command == "branch-retirement-complete":
|
|
1743
|
+
payload = complete_branch_retirement(
|
|
1744
|
+
parsed.repo,
|
|
1745
|
+
authorization_id=parsed.authorization_id,
|
|
1746
|
+
token=parsed.token,
|
|
1747
|
+
result_path=parsed.result_file,
|
|
1748
|
+
)
|
|
1749
|
+
elif parsed.command == "branch-retirement-executions":
|
|
1750
|
+
payload = branch_retirement_executions(
|
|
1751
|
+
parsed.repo,
|
|
1752
|
+
action=parsed.action,
|
|
1753
|
+
authorization_id=parsed.authorization_id,
|
|
1754
|
+
token=parsed.token,
|
|
1755
|
+
reason=parsed.reason,
|
|
1756
|
+
)
|
|
1757
|
+
elif parsed.command == "branch-retirement-record":
|
|
1758
|
+
payload = record_branch_retirement(
|
|
1759
|
+
parsed.repo,
|
|
1760
|
+
plan_id=parsed.plan_id,
|
|
1761
|
+
operation=parsed.operation,
|
|
1762
|
+
summary_path=parsed.summary_file,
|
|
1763
|
+
result_path=parsed.result_file,
|
|
1764
|
+
)
|
|
1765
|
+
elif parsed.command == "namespace-migration-plan":
|
|
1766
|
+
payload = plan_namespace_migration(
|
|
1767
|
+
parsed.repo,
|
|
1768
|
+
legacy_namespace=parsed.legacy_namespace,
|
|
1769
|
+
policy_from=parsed.policy_from,
|
|
1770
|
+
)
|
|
1771
|
+
elif parsed.command == "namespace-migrate":
|
|
1772
|
+
payload = migrate_namespace(
|
|
1773
|
+
parsed.repo,
|
|
1774
|
+
legacy_namespace=parsed.legacy_namespace,
|
|
1775
|
+
policy_from=parsed.policy_from,
|
|
1776
|
+
actor=parsed.actor,
|
|
1777
|
+
expected_plan_id=parsed.expected_plan_id,
|
|
1778
|
+
dry_run=parsed.dry_run,
|
|
1779
|
+
)
|
|
1780
|
+
elif parsed.command == "namespace-migration-receipts":
|
|
1781
|
+
payload = namespace_migration_receipts(parsed.repo)
|
|
1782
|
+
elif parsed.command == "namespace-migration-verify":
|
|
1783
|
+
payload = verify_namespace(parsed.repo)
|
|
1784
|
+
elif parsed.command in {"recover-handoff", "recover-published"}:
|
|
1785
|
+
payload = recover_frozen_checkout(
|
|
1786
|
+
parsed.repo, target=parsed.path,
|
|
1787
|
+
expected_record_version=parsed.expected_record_version,
|
|
1788
|
+
expected_head=parsed.expected_head, owner=parsed.owner,
|
|
1789
|
+
branch=getattr(parsed, "branch", None),
|
|
1790
|
+
)
|
|
1791
|
+
elif parsed.command == "reopen":
|
|
1792
|
+
payload = reopen(
|
|
1793
|
+
parsed.repo,
|
|
1794
|
+
target=parsed.path,
|
|
1795
|
+
expected_record_version=parsed.expected_record_version,
|
|
1796
|
+
owner=parsed.owner,
|
|
1797
|
+
)
|
|
1798
|
+
elif parsed.command in {"binding-add", "binding-remove", "binding-transfer"}:
|
|
1799
|
+
payload = update_external_binding(
|
|
1800
|
+
parsed.repo,
|
|
1801
|
+
target=parsed.path,
|
|
1802
|
+
expected_record_version=parsed.expected_record_version,
|
|
1803
|
+
owner=parsed.owner,
|
|
1804
|
+
binding=parsed.binding,
|
|
1805
|
+
holder_pid=getattr(parsed, "holder_pid", None),
|
|
1806
|
+
action=parsed.command.removeprefix("binding-"),
|
|
1807
|
+
recover_archived_codex_session=getattr(
|
|
1808
|
+
parsed, "recover_archived_codex_session", False),
|
|
1809
|
+
dry_run=getattr(parsed, "dry_run", False),
|
|
1810
|
+
)
|
|
1811
|
+
elif parsed.command == "reconcile" and parsed.reconcile_command == "no-change-completion":
|
|
1812
|
+
from .delivered_closeout import reconcile_no_change_completion
|
|
1813
|
+
|
|
1814
|
+
payload = reconcile_no_change_completion(
|
|
1815
|
+
parsed.repo, target=parsed.path, owner=parsed.owner,
|
|
1816
|
+
expected_record_version=parsed.expected_record_version,
|
|
1817
|
+
completion_id=parsed.completion_receipt_id,
|
|
1818
|
+
completion_sha256=parsed.completion_receipt_sha256,
|
|
1819
|
+
cleanup_ids=tuple(parsed.cleanup_receipt_id),
|
|
1820
|
+
cleanup_sha256=tuple(parsed.cleanup_receipt_sha256),
|
|
1821
|
+
dry_run=parsed.dry_run, expected_plan_id=parsed.expected_plan_id,
|
|
1822
|
+
)
|
|
1823
|
+
elif parsed.command == "reconcile" and parsed.reconcile_command == "receipts":
|
|
1824
|
+
payload = reconcile_publication_receipts(
|
|
1825
|
+
parsed.repo,
|
|
1826
|
+
actor=parsed.actor,
|
|
1827
|
+
receipt_ids=tuple(parsed.receipt_id),
|
|
1828
|
+
dry_run=parsed.dry_run,
|
|
1829
|
+
)
|
|
1830
|
+
elif parsed.command == "reconcile" and parsed.reconcile_command == "release-intents":
|
|
1831
|
+
payload = reconcile_release_intents(
|
|
1832
|
+
parsed.repo,
|
|
1833
|
+
actor=parsed.actor,
|
|
1834
|
+
trigger=parsed.trigger,
|
|
1835
|
+
intent_ids=tuple(parsed.intent_id),
|
|
1836
|
+
dry_run=parsed.dry_run,
|
|
1837
|
+
)
|
|
1838
|
+
elif parsed.command == "reconcile" and parsed.reconcile_command == "release-plans":
|
|
1839
|
+
payload = reconcile_release_plans(
|
|
1840
|
+
parsed.repo, actor=parsed.actor, dry_run=parsed.dry_run
|
|
1841
|
+
)
|
|
1842
|
+
elif parsed.command == "reconcile" and parsed.reconcile_command == "retention":
|
|
1843
|
+
from .convergence import converge_retention
|
|
1844
|
+
|
|
1845
|
+
payload = converge_retention(
|
|
1846
|
+
parsed.repo,
|
|
1847
|
+
actor=parsed.actor,
|
|
1848
|
+
trigger=parsed.trigger,
|
|
1849
|
+
dry_run=not parsed.apply,
|
|
1850
|
+
)
|
|
1851
|
+
elif parsed.command == "reconcile" and parsed.reconcile_command == "binding-registrations":
|
|
1852
|
+
from .registration_backfill import reconcile_binding_registrations
|
|
1853
|
+
|
|
1854
|
+
payload = reconcile_binding_registrations(
|
|
1855
|
+
parsed.repo, dry_run=parsed.dry_run, expected_plan_id=parsed.expected_plan_id
|
|
1856
|
+
)
|
|
1857
|
+
elif parsed.command == "reconcile" and parsed.reconcile_command == "integration-intents":
|
|
1858
|
+
payload = reconcile_integration_intents(
|
|
1859
|
+
parsed.repo,
|
|
1860
|
+
actor=parsed.actor,
|
|
1861
|
+
intent_ids=tuple(parsed.intent_id),
|
|
1862
|
+
dry_run=parsed.dry_run,
|
|
1863
|
+
dispatch=parsed.dispatch,
|
|
1864
|
+
)
|
|
1865
|
+
elif parsed.command == "doctor":
|
|
1866
|
+
payload = doctor(parsed.repo, namespace_pid=parsed.namespace_pid)
|
|
1867
|
+
else:
|
|
1868
|
+
parser.error("unknown command")
|
|
1869
|
+
except (ControllerError, OSError) as exc:
|
|
1870
|
+
payload = envelope(parsed.command)
|
|
1871
|
+
code = exc.code if isinstance(exc, ControllerError) else "FILESYSTEM_ERROR"
|
|
1872
|
+
payload["errors"] = [{"code": code, "message": str(exc)}]
|
|
1873
|
+
payload["decision"] = {"code": "ERROR", "reason": str(exc)}
|
|
1874
|
+
if parsed.command == "canonical-refresh":
|
|
1875
|
+
from .canonical_refresh import CanonicalProcessOccupancyError
|
|
1876
|
+
|
|
1877
|
+
if isinstance(exc, CanonicalProcessOccupancyError):
|
|
1878
|
+
payload["decision"]["process_diagnostics"] = exc.diagnostics
|
|
1879
|
+
if (
|
|
1880
|
+
parsed.command == "resource-recover" and parsed.stage == "rollout-check"
|
|
1881
|
+
and isinstance(exc, cleanup_recovery.RolloutTransactionError)
|
|
1882
|
+
):
|
|
1883
|
+
payload["decision"]["transaction_diagnostics"] = [exc.transaction_diagnostic]
|
|
1884
|
+
if parsed.command == "writer-lease-acquire":
|
|
1885
|
+
payload["decision"]["admission"] = "REFUSED"
|
|
1886
|
+
if parsed.command == "session-bind" and isinstance(getattr(exc, "details", None), dict):
|
|
1887
|
+
payload["decision"]["lease_outcome"] = exc.details
|
|
1888
|
+
_print(payload, parsed.json)
|
|
1889
|
+
return 2
|
|
1890
|
+
_print(payload, parsed.json)
|
|
1891
|
+
if (payload.get("decision") or {}).get("code") in {
|
|
1892
|
+
"RESOURCE_CLEANUP_BLOCKED",
|
|
1893
|
+
"RECOVERY_ATTEMPT_INCOMPLETE",
|
|
1894
|
+
}:
|
|
1895
|
+
return 1
|
|
1896
|
+
if parsed.command == "doctor" and payload.get("decision", {}).get("code") == "FAIL":
|
|
1897
|
+
return 1
|
|
1898
|
+
if (
|
|
1899
|
+
parsed.command == "write-guard"
|
|
1900
|
+
and payload.get("decision", {}).get("code") != "WRITE_ALLOWED"
|
|
1901
|
+
):
|
|
1902
|
+
return 1
|
|
1903
|
+
return 0
|
|
1904
|
+
|
|
1905
|
+
|
|
1906
|
+
if __name__ == "__main__":
|
|
1907
|
+
raise SystemExit(main())
|