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.
Files changed (99) hide show
  1. {agcoord-0.2.2 → agcoord-0.3.2}/AGENTS.md +8 -4
  2. {agcoord-0.2.2 → agcoord-0.3.2}/CHANGELOG.md +86 -0
  3. agcoord-0.3.2/Cargo.lock +242 -0
  4. agcoord-0.3.2/Cargo.toml +16 -0
  5. agcoord-0.3.2/MANIFEST.in +14 -0
  6. {agcoord-0.2.2 → agcoord-0.3.2}/PKG-INFO +49 -16
  7. {agcoord-0.2.2 → agcoord-0.3.2}/README.md +48 -15
  8. agcoord-0.3.2/conformance/manifest-v1.json +306 -0
  9. agcoord-0.3.2/docs/conformance.md +67 -0
  10. {agcoord-0.2.2 → agcoord-0.3.2}/docs/contributing.md +58 -8
  11. {agcoord-0.2.2 → agcoord-0.3.2}/docs/coordinator.md +172 -44
  12. {agcoord-0.2.2 → agcoord-0.3.2}/docs/index.md +8 -0
  13. agcoord-0.3.2/docs/native_broker.md +475 -0
  14. agcoord-0.3.2/docs/native_host.md +239 -0
  15. agcoord-0.3.2/docs/native_migration.md +219 -0
  16. agcoord-0.3.2/docs/releasing.md +169 -0
  17. agcoord-0.3.2/native/THIRD_PARTY_LICENSES.tsv +30 -0
  18. agcoord-0.3.2/native/agcoord-broker/Cargo.toml +24 -0
  19. agcoord-0.3.2/native/agcoord-broker/build.rs +24 -0
  20. agcoord-0.3.2/native/agcoord-broker/src/broker.rs +2110 -0
  21. agcoord-0.3.2/native/agcoord-broker/src/cgroup.rs +3266 -0
  22. agcoord-0.3.2/native/agcoord-broker/src/error.rs +36 -0
  23. agcoord-0.3.2/native/agcoord-broker/src/host.rs +796 -0
  24. agcoord-0.3.2/native/agcoord-broker/src/main.rs +1088 -0
  25. agcoord-0.3.2/native/agcoord-broker/src/platform.rs +303 -0
  26. agcoord-0.3.2/native/agcoord-broker/src/project_quota.rs +1556 -0
  27. agcoord-0.3.2/native/agcoord-broker/src/resources.rs +524 -0
  28. agcoord-0.3.2/native/agcoord-broker/src/store.rs +3349 -0
  29. agcoord-0.3.2/native/agcoord-broker/src/worker.rs +1411 -0
  30. agcoord-0.3.2/native/agcoord-broker/tests/client_compatibility.rs +1587 -0
  31. agcoord-0.3.2/native/agcoord-broker/tests/host_deployment.rs +686 -0
  32. agcoord-0.3.2/native/agcoord-broker/tests/identity.rs +125 -0
  33. agcoord-0.3.2/native/agcoord-broker/tests/scheduler.rs +6202 -0
  34. agcoord-0.3.2/packaging/apparmor/usr.libexec.agcoord.agcoord-broker +74 -0
  35. agcoord-0.3.2/packaging/systemd/agcoord-broker.service +21 -0
  36. agcoord-0.3.2/rust-toolchain.toml +5 -0
  37. agcoord-0.3.2/scripts/audit-native-broker +75 -0
  38. agcoord-0.3.2/scripts/build-native-broker +102 -0
  39. agcoord-0.3.2/scripts/build-native-host-package +87 -0
  40. agcoord-0.3.2/scripts/check-conformance +338 -0
  41. agcoord-0.3.2/scripts/check-native-host-package +123 -0
  42. agcoord-0.3.2/scripts/check-native-licenses +51 -0
  43. agcoord-0.3.2/scripts/check-native-reproducible +34 -0
  44. agcoord-0.3.2/scripts/install-native-host +196 -0
  45. agcoord-0.3.2/scripts/native-source-id +28 -0
  46. agcoord-0.3.2/scripts/rehearse-native-migration +467 -0
  47. agcoord-0.3.2/scripts/test-native-host-enforcement +57 -0
  48. agcoord-0.3.2/scripts/verify-release-candidate +574 -0
  49. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/__init__.py +1 -1
  50. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/cgroup.py +47 -10
  51. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/cli.py +93 -6
  52. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/config.py +75 -1
  53. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/github.py +372 -6
  54. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/land.py +30 -7
  55. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/merge.py +4 -2
  56. agcoord-0.3.2/src/agcoord/native_client.py +376 -0
  57. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/pytest_xdist.py +1 -1
  58. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/queue.py +1898 -115
  59. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/tui.py +10 -1
  60. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/PKG-INFO +49 -16
  61. agcoord-0.3.2/src/agcoord.egg-info/SOURCES.txt +94 -0
  62. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup.py +61 -3
  63. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cli.py +190 -27
  64. agcoord-0.3.2/tests/test_conformance_gate.py +112 -0
  65. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_distribution.py +2 -0
  66. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_merge.py +407 -4
  67. agcoord-0.3.2/tests/test_native_client.py +602 -0
  68. agcoord-0.3.2/tests/test_native_host_assets.py +120 -0
  69. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_project_quota.py +5 -2
  70. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_queue.py +593 -65
  71. agcoord-0.3.2/tests/test_release_candidate.py +299 -0
  72. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_tui.py +26 -0
  73. agcoord-0.2.2/MANIFEST.in +0 -4
  74. agcoord-0.2.2/docs/releasing.md +0 -72
  75. agcoord-0.2.2/src/agcoord.egg-info/SOURCES.txt +0 -50
  76. {agcoord-0.2.2 → agcoord-0.3.2}/LICENSE +0 -0
  77. {agcoord-0.2.2 → agcoord-0.3.2}/docs/assets/README.md +0 -0
  78. {agcoord-0.2.2 → agcoord-0.3.2}/docs/assets/agcoord-gourd-mascot.png +0 -0
  79. {agcoord-0.2.2 → agcoord-0.3.2}/docs/session_handoff_format.md +0 -0
  80. {agcoord-0.2.2 → agcoord-0.3.2}/pyproject.toml +0 -0
  81. {agcoord-0.2.2 → agcoord-0.3.2}/setup.cfg +0 -0
  82. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/__main__.py +0 -0
  83. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/frame.py +0 -0
  84. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/project_quota.py +0 -0
  85. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/py.typed +0 -0
  86. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/resources.py +0 -0
  87. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord/worker.py +0 -0
  88. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/dependency_links.txt +0 -0
  89. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/entry_points.txt +0 -0
  90. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/requires.txt +0 -0
  91. {agcoord-0.2.2 → agcoord-0.3.2}/src/agcoord.egg-info/top_level.txt +0 -0
  92. {agcoord-0.2.2 → agcoord-0.3.2}/tests/conftest.py +0 -0
  93. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup_compute.py +0 -0
  94. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup_io.py +0 -0
  95. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup_memory.py +0 -0
  96. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_cgroup_tmpfs.py +0 -0
  97. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_github_adapter.py +0 -0
  98. {agcoord-0.2.2 → agcoord-0.3.2}/tests/test_leases.py +0 -0
  99. {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
- - After bootstrap, route checks and publication through the local coordinator, declare
19
- every scarce resource, and never submit coordinated work from an admitted job. Gate
20
- and publish through one `agc land` request; never bypass or separate its verdict
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
@@ -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"
@@ -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.2.2
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 package in a tool environment:
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 from 0.1.x
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
- Before upgrading, let every 0.1.x job finish, wait for its on-demand broker to relinquish the
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. After installing
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
- There is no separate service-install step. The first command starts the detached broker on
79
- demand; later shells and repositories join the same user-scoped coordinator:
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
- It rejects a stale target before the gate, runs the gate once, and publishes immediately
164
- after a green result without releasing the lane or resources. A red gate publishes nothing.
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
- AGCoord never refreshes, rebases, or rewrites the checkout. If the source head or target
169
- branch moves before or during the gate, the same job ends with a named handback and does not
170
- publish. Update the branch yourself, push it, and submit a fresh `agc land` request; a
171
- separate full-plus-merge sequence is not a landing substitute.
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 package in a tool environment:
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 from 0.1.x
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
- Before upgrading, let every 0.1.x job finish, wait for its on-demand broker to relinquish the
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. After installing
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
- There is no separate service-install step. The first command starts the detached broker on
42
- demand; later shells and repositories join the same user-scoped coordinator:
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
- It rejects a stale target before the gate, runs the gate once, and publishes immediately
127
- after a green result without releasing the lane or resources. A red gate publishes nothing.
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
- AGCoord never refreshes, rebases, or rewrites the checkout. If the source head or target
132
- branch moves before or during the gate, the same job ends with a named handback and does not
133
- publish. Update the branch yourself, push it, and submit a fresh `agc land` request; a
134
- separate full-plus-merge sequence is not a landing substitute.
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