agcoord 0.2.2__tar.gz → 0.3.2__tar.gz
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.
- {agcoord-0.2.2 → agcoord-0.3.2}/AGENTS.md +8 -4
- {agcoord-0.2.2 → agcoord-0.3.2}/CHANGELOG.md +86 -0
- agcoord-0.3.2/Cargo.lock +242 -0
- agcoord-0.3.2/Cargo.toml +16 -0
- agcoord-0.3.2/MANIFEST.in +14 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/PKG-INFO +49 -16
- {agcoord-0.2.2 → agcoord-0.3.2}/README.md +48 -15
- agcoord-0.3.2/conformance/manifest-v1.json +306 -0
- agcoord-0.3.2/docs/conformance.md +67 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/docs/contributing.md +58 -8
- {agcoord-0.2.2 → agcoord-0.3.2}/docs/coordinator.md +172 -44
- {agcoord-0.2.2 → agcoord-0.3.2}/docs/index.md +8 -0
- agcoord-0.3.2/docs/native_broker.md +475 -0
- agcoord-0.3.2/docs/native_host.md +239 -0
- agcoord-0.3.2/docs/native_migration.md +219 -0
- agcoord-0.3.2/docs/releasing.md +169 -0
- agcoord-0.3.2/native/THIRD_PARTY_LICENSES.tsv +30 -0
- agcoord-0.3.2/native/agcoord-broker/Cargo.toml +24 -0
- agcoord-0.3.2/native/agcoord-broker/build.rs +24 -0
- agcoord-0.3.2/native/agcoord-broker/src/broker.rs +2110 -0
- agcoord-0.3.2/native/agcoord-broker/src/cgroup.rs +3266 -0
- agcoord-0.3.2/native/agcoord-broker/src/error.rs +36 -0
- agcoord-0.3.2/native/agcoord-broker/src/host.rs +796 -0
- agcoord-0.3.2/native/agcoord-broker/src/main.rs +1088 -0
- agcoord-0.3.2/native/agcoord-broker/src/platform.rs +303 -0
- agcoord-0.3.2/native/agcoord-broker/src/project_quota.rs +1556 -0
- agcoord-0.3.2/native/agcoord-broker/src/resources.rs +524 -0
- agcoord-0.3.2/native/agcoord-broker/src/store.rs +3349 -0
- agcoord-0.3.2/native/agcoord-broker/src/worker.rs +1411 -0
- agcoord-0.3.2/native/agcoord-broker/tests/client_compatibility.rs +1587 -0
- agcoord-0.3.2/native/agcoord-broker/tests/host_deployment.rs +686 -0
- agcoord-0.3.2/native/agcoord-broker/tests/identity.rs +125 -0
- agcoord-0.3.2/native/agcoord-broker/tests/scheduler.rs +6202 -0
- agcoord-0.3.2/packaging/apparmor/usr.libexec.agcoord.agcoord-broker +74 -0
- agcoord-0.3.2/packaging/systemd/agcoord-broker.service +21 -0
- agcoord-0.3.2/rust-toolchain.toml +5 -0
- agcoord-0.3.2/scripts/audit-native-broker +75 -0
- agcoord-0.3.2/scripts/build-native-broker +102 -0
- agcoord-0.3.2/scripts/build-native-host-package +87 -0
- agcoord-0.3.2/scripts/check-conformance +338 -0
- agcoord-0.3.2/scripts/check-native-host-package +123 -0
- agcoord-0.3.2/scripts/check-native-licenses +51 -0
- agcoord-0.3.2/scripts/check-native-reproducible +34 -0
- agcoord-0.3.2/scripts/install-native-host +196 -0
- agcoord-0.3.2/scripts/native-source-id +28 -0
- agcoord-0.3.2/scripts/rehearse-native-migration +467 -0
- agcoord-0.3.2/scripts/test-native-host-enforcement +57 -0
- agcoord-0.3.2/scripts/verify-release-candidate +574 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/__init__.py +1 -1
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/cgroup.py +47 -10
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/cli.py +93 -6
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/config.py +75 -1
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/github.py +372 -6
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/land.py +30 -7
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/merge.py +4 -2
- agcoord-0.3.2/src/agcoord/native_client.py +376 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/pytest_xdist.py +1 -1
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/queue.py +1898 -115
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/tui.py +10 -1
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/PKG-INFO +49 -16
- agcoord-0.3.2/src/agcoord.egg-info/SOURCES.txt +94 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup.py +61 -3
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cli.py +190 -27
- agcoord-0.3.2/tests/test_conformance_gate.py +112 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_distribution.py +2 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_merge.py +407 -4
- agcoord-0.3.2/tests/test_native_client.py +602 -0
- agcoord-0.3.2/tests/test_native_host_assets.py +120 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_project_quota.py +5 -2
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_queue.py +593 -65
- agcoord-0.3.2/tests/test_release_candidate.py +299 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_tui.py +26 -0
- agcoord-0.2.2/MANIFEST.in +0 -4
- agcoord-0.2.2/docs/releasing.md +0 -72
- agcoord-0.2.2/src/agcoord.egg-info/SOURCES.txt +0 -50
- {agcoord-0.2.2 → agcoord-0.3.2}/LICENSE +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/docs/assets/README.md +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/docs/assets/agcoord-gourd-mascot.png +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/docs/session_handoff_format.md +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/pyproject.toml +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/setup.cfg +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/__main__.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/frame.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/project_quota.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/py.typed +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/resources.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/worker.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/dependency_links.txt +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/entry_points.txt +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/requires.txt +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/top_level.txt +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/conftest.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup_compute.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup_io.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup_memory.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup_tmpfs.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_github_adapter.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_leases.py +0 -0
- {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_pytest_xdist.py +0 -0
|
@@ -11,14 +11,18 @@ procedures listed in [docs/index.md](docs/index.md).
|
|
|
11
11
|
- Verify behavior at public boundaries. Start bug fixes with a failing behavioral test;
|
|
12
12
|
accompany runtime changes with focused tests, affected canonical documentation, and a
|
|
13
13
|
`CHANGELOG.md` entry when the change is user-facing.
|
|
14
|
+
- A documentation-only change needs no tests or AGCoord gate. It qualifies only when every
|
|
15
|
+
changed path is `README.md`, `CHANGELOG.md`, `AGENTS.md`, or Markdown below `docs/`.
|
|
16
|
+
Verify the exact pull-request file list and diff, then merge it through the forge; the
|
|
17
|
+
issue, worktree, branch, pull-request, and no-direct-target-push rules still apply.
|
|
14
18
|
- Tests own and stop every broker, worker, repository, and temporary state they create.
|
|
15
19
|
Never inspect or clean another agent's state.
|
|
16
20
|
- Keep the core coordinator forge-neutral. Forge-specific metadata and publication
|
|
17
21
|
behavior belong in optional adapters.
|
|
18
|
-
-
|
|
19
|
-
every scarce resource, and never submit coordinated work from an
|
|
20
|
-
and publish through one `agc land` request; never bypass or separate
|
|
21
|
-
from publication.
|
|
22
|
+
- For every other change after bootstrap, route checks and publication through the local
|
|
23
|
+
coordinator, declare every scarce resource, and never submit coordinated work from an
|
|
24
|
+
admitted job. Gate and publish through one `agc land` request; never bypass or separate
|
|
25
|
+
its verdict from publication.
|
|
22
26
|
- Never upload an AGCoord distribution to PyPI unless the user explicitly requests it.
|
|
23
27
|
Permission to implement, test, commit, push, merge, tag, or create a GitHub release
|
|
24
28
|
does not authorize an upload.
|
|
@@ -5,6 +5,92 @@ versioning; dates use ISO 8601.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 0.3.2 — 2026-09-02
|
|
9
|
+
|
|
10
|
+
- Allow the installed Python client to perform only its authenticated run-scoped callbacks from
|
|
11
|
+
a managed admitted user namespace, where Linux represents the fixed host-root-owned broker
|
|
12
|
+
with the overflow UID. Selection still rejects arbitrary overflow-owned paths and requires
|
|
13
|
+
exact namespace maps plus the restricted AppArmor preflight; general nested client operations
|
|
14
|
+
retain the ordinary root-owner policy. Publication workers now preserve a virtual environment's
|
|
15
|
+
Python entry-point instead of resolving it to a potentially stale base installation.
|
|
16
|
+
- Normalize host-package creation modes and preserve archived modes during verification, so
|
|
17
|
+
package bytes are independent of the invoking umask and the atomic release gate validates the
|
|
18
|
+
artifact correctly under a restrictive worker umask.
|
|
19
|
+
|
|
20
|
+
## 0.3.1 — 2026-09-02
|
|
21
|
+
|
|
22
|
+
- Add durable `agc drain` and exact-token `agc resume` maintenance operations. Drain atomically
|
|
23
|
+
refuses new submissions while admitted checks and authoritative lands finish, survives broker
|
|
24
|
+
replacement and protocol migration/rollback, remains visible through JSON and the TUI, and is
|
|
25
|
+
now required—with its exact receipt—before replacing host files for an existing spool.
|
|
26
|
+
|
|
27
|
+
## 0.3.0 — 2026-09-01
|
|
28
|
+
|
|
29
|
+
- Make `land` mechanically merge an advanced target into an unchanged same-repository request
|
|
30
|
+
branch before gating by default. The lease-protected source update becomes the row's durable
|
|
31
|
+
exact head before the gate; conflicts and source races fail closed, and
|
|
32
|
+
`--no-target-sync` retains the explicit stale-target refusal.
|
|
33
|
+
- Add a tested native migration and rollback runbook with a compatibility matrix, whole-spool
|
|
34
|
+
backup rehearsal, mixed-owner refusals, capability verification, retirement criteria, and
|
|
35
|
+
stable troubleshooting actions. A clean-install release verifier now binds the Python, native,
|
|
36
|
+
and host artifacts to one versioned manifest and aggregate checksum set before publication.
|
|
37
|
+
- Add the verified native host bundle, long-lived delegated systemd user service, and
|
|
38
|
+
three-domain enforcing AppArmor boundary without `default_allow`/unconfined policy. Staged
|
|
39
|
+
installation and upgrade refuse live work and never
|
|
40
|
+
restart implicitly; managed startup verifies the fixed root-owned release identity, service
|
|
41
|
+
cgroup, controllers, global namespace restriction, and setup profile, while admitted broker
|
|
42
|
+
calls and arbitrary submitted commands remain namespace-restricted. A real-host probe proves
|
|
43
|
+
an enforced CPU receipt without weakening Ubuntu's global policy and retains broker and kernel
|
|
44
|
+
diagnostics, including the failing cgroup2 mount's Linux error number, when namespace setup
|
|
45
|
+
fails. Namespace isolation falls back to a leaf-only bind mount when Linux reports that the
|
|
46
|
+
namespace-rooted cgroup2 view collides with the inherited mountpoint, and native metric parsing
|
|
47
|
+
accepts dotted cgroup fields emitted by Linux 6.17 and later. The trusted launcher enters the
|
|
48
|
+
admitted AppArmor profile before setting `no_new_privs`; later broker-client execution stacks
|
|
49
|
+
another restricted profile instead of requesting a forbidden replacement domain.
|
|
50
|
+
- Retry native broker startup through a bounded transient ownership-lock collision while
|
|
51
|
+
preserving the stable refusal for a genuinely live owner.
|
|
52
|
+
- Publish a native broker's live owner identity only after its termination handlers are ready,
|
|
53
|
+
and require crash-recovery startup checks to observe the exact replacement PID rather than
|
|
54
|
+
accepting stale metadata retained in the locked ownership file.
|
|
55
|
+
- Add a strict version-1 Python/native conformance manifest and executable release gate covering
|
|
56
|
+
commands, repositories, atomic publication, the real TUI, protocols, resources and receipts,
|
|
57
|
+
migrations, contention, cancellation, crash recovery, malformed-input corpora, and the core
|
|
58
|
+
no-duplicate/no-stale/no-unrelated-kill/no-unverified-enforcement safety properties.
|
|
59
|
+
- Route the Python CLI, client, TUI, atomic publication worker, and pytest-xdist child leases
|
|
60
|
+
through the protocol-5 Rust broker. Native selection now verifies one explicit executable and
|
|
61
|
+
exact live-owner identity, concurrent autostart elects one owner, protocol-4 state requires an
|
|
62
|
+
explicit idle migration, and missing, stale, or incompatible binaries fail without a Python
|
|
63
|
+
fallback.
|
|
64
|
+
- Bring the Rust broker's persistent project-quota scratch backend to parity: resolve supported
|
|
65
|
+
ext4 and XFS mounts, allocate collision-safe project identities, apply and verify byte and inode
|
|
66
|
+
ceilings, isolate quota authority from workers, retain terminal usage, and recover or clean up
|
|
67
|
+
only identity-verified state across completion, cancellation, and broker crashes.
|
|
68
|
+
- Bring the Rust broker's cgroup v2 backend to enforcement and receipt parity: verify delegated
|
|
69
|
+
namespace rooting, own collision-safe leaves, apply and measure CPU, process, memory, pressure,
|
|
70
|
+
swap, tmpfs, bandwidth, IOPS, and I/O-weight controls, retain terminal and recovery evidence,
|
|
71
|
+
support required refusal or best-effort tmpfs disk fallback, and reject malformed durable
|
|
72
|
+
resource contracts, receipts, state, or recovery handles without rewriting them.
|
|
73
|
+
- Replace the native broker's direct command spawn with an authenticated in-process launcher:
|
|
74
|
+
user code remains blocked through durable PID/start-token/process-group ownership, verified
|
|
75
|
+
capability and descriptor cleanup, and a token-bound final release. Cancellation now drains
|
|
76
|
+
the complete owned process group, while recovery refuses conflicting or reused identities
|
|
77
|
+
without signaling unrelated processes.
|
|
78
|
+
- Add the protocol-5 Rust scheduler and durable SQLite owner with repository barriers and fair
|
|
79
|
+
lanes, capacity admission, cancellation and atomic land authority, WAL contention handling,
|
|
80
|
+
graceful shutdown, identity-safe crash adoption, stable corruption refusals, and verified
|
|
81
|
+
protocol-1-through-4 migration. Native rollback restores its protocol-4 baseline, preserves
|
|
82
|
+
terminal native history, and prevents reuse of every pre-rollback gate receipt.
|
|
83
|
+
- Add a pinned Rust workspace and reproducible static x86_64 Linux broker artifact with bundled
|
|
84
|
+
SQLite, exact protocol/build identity, checksums, provenance, dependency inventory, and
|
|
85
|
+
automated ELF and clean-copy reproducibility audits.
|
|
86
|
+
- Define the target single-executable Rust broker architecture, including its trust boundary,
|
|
87
|
+
durable protocol 5, native worker handshake, AppArmor transition, explicit protocol-4
|
|
88
|
+
migration, Python client compatibility, and ordered implementation constraints.
|
|
89
|
+
- Document that Ubuntu's unprivileged user-namespace restriction can make an explicitly
|
|
90
|
+
delegated cgroup v2 backend fail with `namespace-mapping-failed`, and that granting `userns`
|
|
91
|
+
permission to a copied Python interpreter or root-owned virtual environment is not a narrow
|
|
92
|
+
broker-specific workaround.
|
|
93
|
+
|
|
8
94
|
## 0.2.2 — 2026-08-31
|
|
9
95
|
|
|
10
96
|
- Preserve every identity-verified live worker when a broker exits unexpectedly, allowing a
|
agcoord-0.3.2/Cargo.lock
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "agcoord-broker"
|
|
7
|
+
version = "0.3.2"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"libc",
|
|
10
|
+
"rusqlite",
|
|
11
|
+
"serde",
|
|
12
|
+
"serde_json",
|
|
13
|
+
"signal-hook",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[[package]]
|
|
17
|
+
name = "bitflags"
|
|
18
|
+
version = "2.13.1"
|
|
19
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
20
|
+
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
|
21
|
+
|
|
22
|
+
[[package]]
|
|
23
|
+
name = "cc"
|
|
24
|
+
version = "1.4.4"
|
|
25
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
26
|
+
checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273"
|
|
27
|
+
dependencies = [
|
|
28
|
+
"find-msvc-tools",
|
|
29
|
+
"shlex",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[[package]]
|
|
33
|
+
name = "errno"
|
|
34
|
+
version = "0.3.14"
|
|
35
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
36
|
+
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
|
37
|
+
dependencies = [
|
|
38
|
+
"libc",
|
|
39
|
+
"windows-sys",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[[package]]
|
|
43
|
+
name = "fallible-iterator"
|
|
44
|
+
version = "0.3.0"
|
|
45
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
46
|
+
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
|
47
|
+
|
|
48
|
+
[[package]]
|
|
49
|
+
name = "fallible-streaming-iterator"
|
|
50
|
+
version = "0.1.9"
|
|
51
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
52
|
+
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
|
53
|
+
|
|
54
|
+
[[package]]
|
|
55
|
+
name = "find-msvc-tools"
|
|
56
|
+
version = "0.1.11"
|
|
57
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
58
|
+
checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890"
|
|
59
|
+
|
|
60
|
+
[[package]]
|
|
61
|
+
name = "itoa"
|
|
62
|
+
version = "1.0.18"
|
|
63
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
64
|
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
65
|
+
|
|
66
|
+
[[package]]
|
|
67
|
+
name = "libc"
|
|
68
|
+
version = "0.2.189"
|
|
69
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
70
|
+
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
|
71
|
+
|
|
72
|
+
[[package]]
|
|
73
|
+
name = "libsqlite3-sys"
|
|
74
|
+
version = "0.38.2"
|
|
75
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
76
|
+
checksum = "f1d20bef17f513b9b3004532233187769cd072d790971f4e4da0e346eb6401e8"
|
|
77
|
+
dependencies = [
|
|
78
|
+
"cc",
|
|
79
|
+
"pkg-config",
|
|
80
|
+
"vcpkg",
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
[[package]]
|
|
84
|
+
name = "memchr"
|
|
85
|
+
version = "2.8.3"
|
|
86
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
87
|
+
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
88
|
+
|
|
89
|
+
[[package]]
|
|
90
|
+
name = "pkg-config"
|
|
91
|
+
version = "0.3.34"
|
|
92
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
93
|
+
checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"
|
|
94
|
+
|
|
95
|
+
[[package]]
|
|
96
|
+
name = "proc-macro2"
|
|
97
|
+
version = "1.0.107"
|
|
98
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
99
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
100
|
+
dependencies = [
|
|
101
|
+
"unicode-ident",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
[[package]]
|
|
105
|
+
name = "quote"
|
|
106
|
+
version = "1.0.47"
|
|
107
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
108
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
109
|
+
dependencies = [
|
|
110
|
+
"proc-macro2",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
[[package]]
|
|
114
|
+
name = "rusqlite"
|
|
115
|
+
version = "0.40.2"
|
|
116
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
117
|
+
checksum = "23f2a97da3e3873c73cb2a2e71b35c40ff95e0b1eefa8d72d8499a6928c3b5b3"
|
|
118
|
+
dependencies = [
|
|
119
|
+
"bitflags",
|
|
120
|
+
"fallible-iterator",
|
|
121
|
+
"fallible-streaming-iterator",
|
|
122
|
+
"libsqlite3-sys",
|
|
123
|
+
"smallvec",
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
[[package]]
|
|
127
|
+
name = "serde"
|
|
128
|
+
version = "1.0.229"
|
|
129
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
130
|
+
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
|
131
|
+
dependencies = [
|
|
132
|
+
"serde_core",
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
[[package]]
|
|
136
|
+
name = "serde_core"
|
|
137
|
+
version = "1.0.229"
|
|
138
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
139
|
+
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
|
140
|
+
dependencies = [
|
|
141
|
+
"serde_derive",
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
[[package]]
|
|
145
|
+
name = "serde_derive"
|
|
146
|
+
version = "1.0.229"
|
|
147
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
148
|
+
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
|
149
|
+
dependencies = [
|
|
150
|
+
"proc-macro2",
|
|
151
|
+
"quote",
|
|
152
|
+
"syn",
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
[[package]]
|
|
156
|
+
name = "serde_json"
|
|
157
|
+
version = "1.0.151"
|
|
158
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
159
|
+
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
|
160
|
+
dependencies = [
|
|
161
|
+
"itoa",
|
|
162
|
+
"memchr",
|
|
163
|
+
"serde",
|
|
164
|
+
"serde_core",
|
|
165
|
+
"zmij",
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
[[package]]
|
|
169
|
+
name = "shlex"
|
|
170
|
+
version = "2.0.1"
|
|
171
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
172
|
+
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
|
173
|
+
|
|
174
|
+
[[package]]
|
|
175
|
+
name = "signal-hook"
|
|
176
|
+
version = "0.4.4"
|
|
177
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
178
|
+
checksum = "b2a0c28ca5908dbdbcd52e6fdaa00358ab88637f8ab33e1f188dd510eb44b53d"
|
|
179
|
+
dependencies = [
|
|
180
|
+
"libc",
|
|
181
|
+
"signal-hook-registry",
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
[[package]]
|
|
185
|
+
name = "signal-hook-registry"
|
|
186
|
+
version = "1.4.8"
|
|
187
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
188
|
+
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
|
|
189
|
+
dependencies = [
|
|
190
|
+
"errno",
|
|
191
|
+
"libc",
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
[[package]]
|
|
195
|
+
name = "smallvec"
|
|
196
|
+
version = "1.15.2"
|
|
197
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
198
|
+
checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
|
|
199
|
+
|
|
200
|
+
[[package]]
|
|
201
|
+
name = "syn"
|
|
202
|
+
version = "3.0.4"
|
|
203
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
204
|
+
checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f"
|
|
205
|
+
dependencies = [
|
|
206
|
+
"proc-macro2",
|
|
207
|
+
"quote",
|
|
208
|
+
"unicode-ident",
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
[[package]]
|
|
212
|
+
name = "unicode-ident"
|
|
213
|
+
version = "1.0.24"
|
|
214
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
215
|
+
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
216
|
+
|
|
217
|
+
[[package]]
|
|
218
|
+
name = "vcpkg"
|
|
219
|
+
version = "0.2.15"
|
|
220
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
221
|
+
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|
222
|
+
|
|
223
|
+
[[package]]
|
|
224
|
+
name = "windows-link"
|
|
225
|
+
version = "0.2.1"
|
|
226
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
227
|
+
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
|
228
|
+
|
|
229
|
+
[[package]]
|
|
230
|
+
name = "windows-sys"
|
|
231
|
+
version = "0.61.2"
|
|
232
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
233
|
+
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
|
234
|
+
dependencies = [
|
|
235
|
+
"windows-link",
|
|
236
|
+
]
|
|
237
|
+
|
|
238
|
+
[[package]]
|
|
239
|
+
name = "zmij"
|
|
240
|
+
version = "1.0.23"
|
|
241
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
242
|
+
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
agcoord-0.3.2/Cargo.toml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[workspace]
|
|
2
|
+
members = ["native/agcoord-broker"]
|
|
3
|
+
resolver = "2"
|
|
4
|
+
|
|
5
|
+
[workspace.package]
|
|
6
|
+
version = "0.3.2"
|
|
7
|
+
edition = "2024"
|
|
8
|
+
rust-version = "1.94.1"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
repository = "https://github.com/xu-hao/agcoord"
|
|
11
|
+
|
|
12
|
+
[profile.release]
|
|
13
|
+
codegen-units = 1
|
|
14
|
+
lto = "fat"
|
|
15
|
+
panic = "abort"
|
|
16
|
+
strip = "symbols"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
include AGENTS.md
|
|
2
|
+
include CHANGELOG.md
|
|
3
|
+
include Cargo.lock
|
|
4
|
+
include Cargo.toml
|
|
5
|
+
include LICENSE
|
|
6
|
+
include rust-toolchain.toml
|
|
7
|
+
recursive-include conformance *.json
|
|
8
|
+
recursive-include docs *.md *.png
|
|
9
|
+
recursive-include native *.rs *.toml *.tsv
|
|
10
|
+
recursive-include packaging *
|
|
11
|
+
include scripts/*native*
|
|
12
|
+
include scripts/check-conformance
|
|
13
|
+
include scripts/verify-release-candidate
|
|
14
|
+
recursive-include tests *.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agcoord
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Machine-local gate and publication coordinator for development agents
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/xu-hao/agcoord
|
|
@@ -50,33 +50,52 @@ core package is forge-neutral; GitHub support is an optional adapter.
|
|
|
50
50
|
|
|
51
51
|
## Install and start
|
|
52
52
|
|
|
53
|
-
Install the published
|
|
53
|
+
Install the published Python client in a tool environment and the matching host package, which
|
|
54
|
+
places the native broker at `/usr/libexec/agcoord/agcoord-broker`:
|
|
54
55
|
|
|
55
56
|
```bash
|
|
56
57
|
python -m pip install agcoord
|
|
57
58
|
```
|
|
58
59
|
|
|
60
|
+
The client refuses to search `PATH` or fall back to the old Python broker. Source developers may
|
|
61
|
+
select an absolute current-user-owned development build with the documented
|
|
62
|
+
[`native_broker` configuration](docs/native_broker.md#executable-discovery); release installs
|
|
63
|
+
require the root-owned static artifact.
|
|
64
|
+
Production installation and upgrades use the staged package, long-lived user service, and
|
|
65
|
+
AppArmor policy in the [native host runbook](docs/native_host.md); activation never restarts a
|
|
66
|
+
broker while queued or running work remains.
|
|
67
|
+
|
|
59
68
|
The base package installs the supported Textual 8 release line (`textual>=8.2,<9`) for the
|
|
60
69
|
terminal UI. Textual 1 through 7 are not supported; a future Textual major is admitted only
|
|
61
70
|
after its real-TUI behavior is validated.
|
|
62
71
|
|
|
63
|
-
### Upgrading
|
|
72
|
+
### Upgrading to 0.3.0
|
|
73
|
+
|
|
74
|
+
Version 0.3.0 replaces the production Python queue owner with the fixed, statically linked Rust
|
|
75
|
+
broker and durable protocol 5. Keep the old client and state backup through a tested rollback
|
|
76
|
+
window. Install the matching client, run `agc drain` to atomically close submissions while
|
|
77
|
+
accepted work finishes, and retain its exact drain ID. Then install and activate the matching
|
|
78
|
+
host bundle with that ID, rehearse migrate/rollback against a copy, migrate the guarded live
|
|
79
|
+
spool explicitly, run `agc resume DRAIN_ID`, and start the managed service. The complete
|
|
80
|
+
commands, compatibility matrix, refusal modes, and rollback procedure are in the
|
|
81
|
+
[native migration runbook](docs/native_migration.md). Neither package installation nor service
|
|
82
|
+
activation changes the spool implicitly.
|
|
83
|
+
|
|
84
|
+
If upgrading directly from 0.1.x, first apply the 0.2 command and configuration changes below.
|
|
64
85
|
|
|
65
86
|
Version 0.2.0 removes the `agcoord` console executable. Replace downstream shell commands,
|
|
66
87
|
service units, and automation with `agc`; the PyPI project, Python import, stable state-directory
|
|
67
88
|
name, and `python -m agcoord` entry point remain `agcoord`.
|
|
68
89
|
|
|
69
|
-
|
|
70
|
-
idle spool, and back up the state directory when its history matters. Move capacity, resource
|
|
90
|
+
Let every 0.1.x job finish and move capacity, resource
|
|
71
91
|
binding, and cgroup-root values from `AGCOORD_CAPACITIES`, `AGCOORD_RESOURCE_BINDINGS`, and
|
|
72
92
|
`AGCOORD_CGROUP_ROOT` into that state directory's single `config.json`; those three environment
|
|
73
|
-
variables and the old comma-separated capacity syntax are no longer accepted.
|
|
74
|
-
0.2.0, run `agc migrate` once for the idle default spool (or
|
|
75
|
-
`agc --state-dir /path/to/state migrate`), then use `agc list` to start the new broker. Migration
|
|
93
|
+
variables and the old comma-separated capacity syntax are no longer accepted. The 0.3 migration
|
|
76
94
|
preserves historical meaning and never reinterprets legacy resource names as enforced limits.
|
|
77
95
|
|
|
78
|
-
|
|
79
|
-
|
|
96
|
+
With the production host package configured, the first command asks systemd to start the
|
|
97
|
+
long-lived user service; later shells and repositories join the same user-scoped coordinator.
|
|
98
|
+
Explicit development binaries retain detached on-demand startup:
|
|
80
99
|
|
|
81
100
|
```bash
|
|
82
101
|
agc list
|
|
@@ -155,20 +174,27 @@ agc land 123 \
|
|
|
155
174
|
-- ./scripts/test.sh
|
|
156
175
|
# GitHub is the convenience default and may also be named explicitly.
|
|
157
176
|
agc land 123 --adapter github -- ./scripts/test.sh
|
|
177
|
+
# Opt out when the request must fail instead of merging an advanced target.
|
|
178
|
+
agc land 123 --no-target-sync -- ./scripts/test.sh
|
|
158
179
|
```
|
|
159
180
|
|
|
160
181
|
`land` stores the adapter, request, exact checkout/head, gate command, caller environment,
|
|
161
182
|
and resource claim in one durable repository barrier. The core record keeps adapter and
|
|
162
183
|
request separate even though the current installed adapter uses GitHub pull-request numbers.
|
|
163
|
-
|
|
164
|
-
|
|
184
|
+
If the target advanced while a same-repository request waited, the default GitHub adapter makes
|
|
185
|
+
one ordinary merge commit from the current target into the unchanged request branch, pushes it
|
|
186
|
+
with an exact lease, and records that commit as the durable head before running the gate. It
|
|
187
|
+
then runs the gate once and publishes immediately after a green result without releasing the
|
|
188
|
+
lane or resources. A red gate publishes nothing.
|
|
165
189
|
`--adapter github` is the default when the option is omitted; the core request remains
|
|
166
190
|
forge-neutral.
|
|
167
191
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
192
|
+
Target synchronization never rebases or rewrites existing commits. A merge conflict is aborted
|
|
193
|
+
and reported before the gate, with the checkout restored cleanly. A concurrent source change,
|
|
194
|
+
failed lease-protected push, target movement during the gate, or changed post-gate observation
|
|
195
|
+
ends with a named handback and does not update the target. Use `--no-target-sync` when even the
|
|
196
|
+
pre-gate source merge is unwanted. A separate full-plus-merge sequence is not a landing
|
|
197
|
+
substitute.
|
|
172
198
|
|
|
173
199
|
Inspect or manage jobs from any terminal:
|
|
174
200
|
|
|
@@ -178,10 +204,17 @@ agc show land-0123456789ab
|
|
|
178
204
|
agc log land-0123456789ab --follow
|
|
179
205
|
agc cancel land-0123456789ab
|
|
180
206
|
agc clear
|
|
207
|
+
# For planned maintenance:
|
|
208
|
+
agc drain --reason "native host upgrade"
|
|
209
|
+
agc resume drain-0123456789ab
|
|
181
210
|
```
|
|
182
211
|
|
|
183
212
|
`clear` removes terminal history and its logs only. It refuses while queued or running work
|
|
184
213
|
exists and never removes the spool, broker ownership, or migration history.
|
|
214
|
+
`drain` durably and atomically refuses new submissions without cancelling work already admitted.
|
|
215
|
+
It waits for those rows—including an authoritative land publication—to become terminal and for
|
|
216
|
+
the broker to yield ownership. `list`, `show`, `log`, the TUI, and explicit cancellation remain
|
|
217
|
+
available. Save the returned `drain-…` ID: only `resume` with that exact ID reopens submissions.
|
|
185
218
|
|
|
186
219
|
The full operating contract, recovery behavior, TUI keys, and resource model are in
|
|
187
220
|
[the coordinator guide](docs/coordinator.md). Package maintainers should also read
|
|
@@ -13,33 +13,52 @@ core package is forge-neutral; GitHub support is an optional adapter.
|
|
|
13
13
|
|
|
14
14
|
## Install and start
|
|
15
15
|
|
|
16
|
-
Install the published
|
|
16
|
+
Install the published Python client in a tool environment and the matching host package, which
|
|
17
|
+
places the native broker at `/usr/libexec/agcoord/agcoord-broker`:
|
|
17
18
|
|
|
18
19
|
```bash
|
|
19
20
|
python -m pip install agcoord
|
|
20
21
|
```
|
|
21
22
|
|
|
23
|
+
The client refuses to search `PATH` or fall back to the old Python broker. Source developers may
|
|
24
|
+
select an absolute current-user-owned development build with the documented
|
|
25
|
+
[`native_broker` configuration](docs/native_broker.md#executable-discovery); release installs
|
|
26
|
+
require the root-owned static artifact.
|
|
27
|
+
Production installation and upgrades use the staged package, long-lived user service, and
|
|
28
|
+
AppArmor policy in the [native host runbook](docs/native_host.md); activation never restarts a
|
|
29
|
+
broker while queued or running work remains.
|
|
30
|
+
|
|
22
31
|
The base package installs the supported Textual 8 release line (`textual>=8.2,<9`) for the
|
|
23
32
|
terminal UI. Textual 1 through 7 are not supported; a future Textual major is admitted only
|
|
24
33
|
after its real-TUI behavior is validated.
|
|
25
34
|
|
|
26
|
-
### Upgrading
|
|
35
|
+
### Upgrading to 0.3.0
|
|
36
|
+
|
|
37
|
+
Version 0.3.0 replaces the production Python queue owner with the fixed, statically linked Rust
|
|
38
|
+
broker and durable protocol 5. Keep the old client and state backup through a tested rollback
|
|
39
|
+
window. Install the matching client, run `agc drain` to atomically close submissions while
|
|
40
|
+
accepted work finishes, and retain its exact drain ID. Then install and activate the matching
|
|
41
|
+
host bundle with that ID, rehearse migrate/rollback against a copy, migrate the guarded live
|
|
42
|
+
spool explicitly, run `agc resume DRAIN_ID`, and start the managed service. The complete
|
|
43
|
+
commands, compatibility matrix, refusal modes, and rollback procedure are in the
|
|
44
|
+
[native migration runbook](docs/native_migration.md). Neither package installation nor service
|
|
45
|
+
activation changes the spool implicitly.
|
|
46
|
+
|
|
47
|
+
If upgrading directly from 0.1.x, first apply the 0.2 command and configuration changes below.
|
|
27
48
|
|
|
28
49
|
Version 0.2.0 removes the `agcoord` console executable. Replace downstream shell commands,
|
|
29
50
|
service units, and automation with `agc`; the PyPI project, Python import, stable state-directory
|
|
30
51
|
name, and `python -m agcoord` entry point remain `agcoord`.
|
|
31
52
|
|
|
32
|
-
|
|
33
|
-
idle spool, and back up the state directory when its history matters. Move capacity, resource
|
|
53
|
+
Let every 0.1.x job finish and move capacity, resource
|
|
34
54
|
binding, and cgroup-root values from `AGCOORD_CAPACITIES`, `AGCOORD_RESOURCE_BINDINGS`, and
|
|
35
55
|
`AGCOORD_CGROUP_ROOT` into that state directory's single `config.json`; those three environment
|
|
36
|
-
variables and the old comma-separated capacity syntax are no longer accepted.
|
|
37
|
-
0.2.0, run `agc migrate` once for the idle default spool (or
|
|
38
|
-
`agc --state-dir /path/to/state migrate`), then use `agc list` to start the new broker. Migration
|
|
56
|
+
variables and the old comma-separated capacity syntax are no longer accepted. The 0.3 migration
|
|
39
57
|
preserves historical meaning and never reinterprets legacy resource names as enforced limits.
|
|
40
58
|
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
With the production host package configured, the first command asks systemd to start the
|
|
60
|
+
long-lived user service; later shells and repositories join the same user-scoped coordinator.
|
|
61
|
+
Explicit development binaries retain detached on-demand startup:
|
|
43
62
|
|
|
44
63
|
```bash
|
|
45
64
|
agc list
|
|
@@ -118,20 +137,27 @@ agc land 123 \
|
|
|
118
137
|
-- ./scripts/test.sh
|
|
119
138
|
# GitHub is the convenience default and may also be named explicitly.
|
|
120
139
|
agc land 123 --adapter github -- ./scripts/test.sh
|
|
140
|
+
# Opt out when the request must fail instead of merging an advanced target.
|
|
141
|
+
agc land 123 --no-target-sync -- ./scripts/test.sh
|
|
121
142
|
```
|
|
122
143
|
|
|
123
144
|
`land` stores the adapter, request, exact checkout/head, gate command, caller environment,
|
|
124
145
|
and resource claim in one durable repository barrier. The core record keeps adapter and
|
|
125
146
|
request separate even though the current installed adapter uses GitHub pull-request numbers.
|
|
126
|
-
|
|
127
|
-
|
|
147
|
+
If the target advanced while a same-repository request waited, the default GitHub adapter makes
|
|
148
|
+
one ordinary merge commit from the current target into the unchanged request branch, pushes it
|
|
149
|
+
with an exact lease, and records that commit as the durable head before running the gate. It
|
|
150
|
+
then runs the gate once and publishes immediately after a green result without releasing the
|
|
151
|
+
lane or resources. A red gate publishes nothing.
|
|
128
152
|
`--adapter github` is the default when the option is omitted; the core request remains
|
|
129
153
|
forge-neutral.
|
|
130
154
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
155
|
+
Target synchronization never rebases or rewrites existing commits. A merge conflict is aborted
|
|
156
|
+
and reported before the gate, with the checkout restored cleanly. A concurrent source change,
|
|
157
|
+
failed lease-protected push, target movement during the gate, or changed post-gate observation
|
|
158
|
+
ends with a named handback and does not update the target. Use `--no-target-sync` when even the
|
|
159
|
+
pre-gate source merge is unwanted. A separate full-plus-merge sequence is not a landing
|
|
160
|
+
substitute.
|
|
135
161
|
|
|
136
162
|
Inspect or manage jobs from any terminal:
|
|
137
163
|
|
|
@@ -141,10 +167,17 @@ agc show land-0123456789ab
|
|
|
141
167
|
agc log land-0123456789ab --follow
|
|
142
168
|
agc cancel land-0123456789ab
|
|
143
169
|
agc clear
|
|
170
|
+
# For planned maintenance:
|
|
171
|
+
agc drain --reason "native host upgrade"
|
|
172
|
+
agc resume drain-0123456789ab
|
|
144
173
|
```
|
|
145
174
|
|
|
146
175
|
`clear` removes terminal history and its logs only. It refuses while queued or running work
|
|
147
176
|
exists and never removes the spool, broker ownership, or migration history.
|
|
177
|
+
`drain` durably and atomically refuses new submissions without cancelling work already admitted.
|
|
178
|
+
It waits for those rows—including an authoritative land publication—to become terminal and for
|
|
179
|
+
the broker to yield ownership. `list`, `show`, `log`, the TUI, and explicit cancellation remain
|
|
180
|
+
available. Save the returned `drain-…` ID: only `resume` with that exact ID reopens submissions.
|
|
148
181
|
|
|
149
182
|
The full operating contract, recovery behavior, TUI keys, and resource model are in
|
|
150
183
|
[the coordinator guide](docs/coordinator.md). Package maintainers should also read
|