@ssheleg/agent-sync 1.19.0 → 1.19.1

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,38 @@
1
+ ## v1.19.1 — re-acquiring your own lease now refreshes it
2
+
3
+ **`renew` was fixed for exactly this and `acquire` was not, in the same file.**
4
+ `_refresh_lease`'s docstring records the bug it exists to have fixed: *"`renew`
5
+ appended `op=renew` to the RECORD plane — which has not decided a lease since 1.0.0 —
6
+ and touched a throttle file. The lock's own `ts` was written once, by `acquire`. So a
7
+ run holding a lease lost it at TTL while still working."* The repair landed in `renew`.
8
+ The own-lock branch of `acquire` kept doing precisely what that paragraph describes.
9
+
10
+ **Two harms, and the second is the one that bites.** The lock stayed expired, so
11
+ `classify_lock` read it as spent and another run's `acquire` took it over while this one
12
+ believed it held — measured 2026-09-01: a foreign expired lock IS taken over, timestamp
13
+ and host rewritten. And `_touch_renew` resets the marker `renew()` throttles on, so a
14
+ re-acquire **actively suppressed the next real refresh** while refreshing nothing
15
+ itself. That is the mechanism behind a lease expiring three times in one run against a
16
+ 450-step CI job.
17
+
18
+ Measured before and after, on a lock aged past its own TTL:
19
+
20
+ ```
21
+ old: won mykey (…) ts after re-acquire: 2026-08-29T20:59:04Z still expired
22
+ new: won mykey (…) ts after re-acquire: 2026-09-01T12:38:48Z
23
+ ```
24
+
25
+ `check_acquire_refreshes_its_own_lease` is beside `check_renew_extends_the_lease`,
26
+ watched failing against the previous commit with both of its assertions.
27
+
28
+ **One finding retracted in the same run, and it belongs here.** `reap` refuses to clear
29
+ a lock three days past a forty-five-minute TTL when this run's identity is the shared
30
+ fallback, and that reads like a deadlock. It is not: `acquire` takes over an expired
31
+ lock regardless of who wrote it — measured, timestamp and host rewritten — so the
32
+ expired lock blocks nothing, and `reap`'s stricter bar for a *tidying* operation is
33
+ correct as designed. The claim that expiry alone should license a delete was wrong
34
+ about which operation matters.
35
+
1
36
  ## v1.19.0 — the skill now promises the finish it has always performed
2
37
 
3
38
  Wave-4 close-out of the 2026-08-29 family audit (ASY-10), filed by this
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ssheleg/agent-sync",
3
- "version": "1.19.0",
3
+ "version": "1.19.1",
4
4
  "description": "Let concurrent coding agents share one project without colliding — leases with TTL, race-free id reservation, a run journal and a generated board, over a pluggable knowledge cloud.",
5
5
  "bin": {
6
6
  "agent-sync": "bin/agent-sync.js"
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "agent-sync",
4
4
  "displayName": "Agent Sync",
5
- "version": "1.19.0",
5
+ "version": "1.19.1",
6
6
  "description": "Coordination layer for multi-agent repositories — leases with TTL, race-free ID reservation, a run journal, a cross-repo signal feed and a generated board, over a pluggable knowledge cloud.",
7
7
  "author": {
8
8
  "name": "ssheleg",
@@ -4,7 +4,7 @@ description: "Use when several coding agents work one repository at the same tim
4
4
  compatibility: "Requires the task-pipeline skill for its stages (npx sshlg-skills install). Needs python3 3.9+ (stdlib only, HTTP included - nothing to pip install) and bash for the hooks. The knowledge backend is configured per project; with none configured it degrades to git-file leases. Enforcement hooks are Claude Code only - on other agents the same checks run as a self-check."
5
5
  license: MIT
6
6
  metadata:
7
- version: "1.19.0"
7
+ version: "1.19.1"
8
8
  author: ssheleg
9
9
  ---
10
10
 
@@ -33,7 +33,7 @@ from datetime import datetime, timezone
33
33
  from pathlib import Path
34
34
  from typing import Any
35
35
 
36
- VERSION = "1.19.0"
36
+ VERSION = "1.19.1"
37
37
 
38
38
  CONFIG_PATH = Path(".claude/agent-sync.json")
39
39
  ENV_FILE = Path(".env.agent-sync")
@@ -1646,6 +1646,21 @@ class Sync:
1646
1646
  except (json.JSONDecodeError, OSError):
1647
1647
  held = {}
1648
1648
  if held.get("run") == self.rid:
1649
+ # MOVE THE LOCK'S OWN `ts`, not just the throttle marker. This branch did
1650
+ # exactly what `_refresh_lease`'s docstring describes as the bug it exists
1651
+ # to have fixed — touch the throttle file and leave the timestamp the lease
1652
+ # is arbitrated by — and the repair landed in `renew` and not here, in the
1653
+ # same file, four minor versions ago.
1654
+ #
1655
+ # Two harms, and the second is the one that bites. The lock stayed expired,
1656
+ # so `classify_lock` read it as spent and another run's `acquire` took it
1657
+ # over while this one believed it held (measured 2026-09-01: a foreign
1658
+ # expired lock IS taken over, timestamp and host rewritten). And
1659
+ # `_touch_renew` resets the marker `renew()` throttles on — so a re-acquire
1660
+ # actively SUPPRESSED the next real refresh, refreshing nothing itself.
1661
+ # That is the mechanism behind a lease expiring three times in one run
1662
+ # against a 450-step CI job on 2026-09-01.
1663
+ self._refresh_lease(key)
1649
1664
  self._touch_renew()
1650
1665
  return True, self.rid
1651
1666
  if time.time() <= parse_iso(held.get("ts", "")) + int(held.get("ttl", self.ttl)):