instar 1.3.138 → 1.3.140
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +88 -53
- package/dist/commands/server.js.map +1 -1
- package/dist/core/LeaseCoordinator.d.ts.map +1 -1
- package/dist/core/LeaseCoordinator.js +12 -1
- package/dist/core/LeaseCoordinator.js.map +1 -1
- package/dist/core/LocalLeaseStore.d.ts +55 -0
- package/dist/core/LocalLeaseStore.d.ts.map +1 -0
- package/dist/core/LocalLeaseStore.js +103 -0
- package/dist/core/LocalLeaseStore.js.map +1 -0
- package/dist/core/SafeGitExecutor.d.ts.map +1 -1
- package/dist/core/SafeGitExecutor.js +30 -3
- package/dist/core/SafeGitExecutor.js.map +1 -1
- package/dist/monitoring/agentWorktreeGit.d.ts.map +1 -1
- package/dist/monitoring/agentWorktreeGit.js +17 -1
- package/dist/monitoring/agentWorktreeGit.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.139.md +57 -0
- package/upgrades/1.3.140.md +47 -0
- package/upgrades/side-effects/source-tree-guard-reaper-readtier.md +132 -0
- package/upgrades/side-effects/standby-lease-holder-sync.md +70 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**Multi-machine: a standby machine can now actually receive a transferred session.**
|
|
8
|
+
When you run one agent across two machines, the machines agree on which one is "in
|
|
9
|
+
charge" via a lease (a who-is-the-captain token). Cross-machine commands — like
|
|
10
|
+
moving a conversation to the other machine — are only accepted from the recognized
|
|
11
|
+
captain. A live two-machine test surfaced that the standby machine had no idea who
|
|
12
|
+
the captain was, so it refused every hand-off. Root cause: the code that runs the
|
|
13
|
+
captain-tracking system was bundled with git backup, and on machines where git
|
|
14
|
+
backup is blocked or off (including an agent whose home is the instar source tree),
|
|
15
|
+
the whole system silently never started. This change runs the captain-tracking
|
|
16
|
+
system over the machines' existing secure connection whenever multi-machine is on,
|
|
17
|
+
independent of git — so a standby learns the captain and accepts the hand-off. A
|
|
18
|
+
second, latent bug (the standby discarding the captain's announcements due to an
|
|
19
|
+
over-strict duplicate check) is fixed too. Single-machine agents are unaffected.
|
|
20
|
+
|
|
21
|
+
## What to Tell Your User
|
|
22
|
+
|
|
23
|
+
If you run on one machine, nothing changes. If you run one agent across two
|
|
24
|
+
machines, moving a conversation to the other machine now works end to end —
|
|
25
|
+
previously the second machine would quietly refuse the hand-off because it never
|
|
26
|
+
learned which machine was in charge. Nothing to configure.
|
|
27
|
+
|
|
28
|
+
## Summary of New Capabilities
|
|
29
|
+
|
|
30
|
+
| Capability | How to Use |
|
|
31
|
+
|-----------|-----------|
|
|
32
|
+
| Git-less lease coordination | Automatic. A machine with no git medium (a credential-less standby, or an agent home that is the instar source tree) now coordinates the lease over the existing HTTP channel and learns the holder, so cross-machine transfer is authorized. No configuration. |
|
|
33
|
+
|
|
34
|
+
## Evidence
|
|
35
|
+
|
|
36
|
+
- New `LocalLeaseStore` (git-less lease store) unit tests:
|
|
37
|
+
`tests/unit/LocalLeaseStore.test.ts` (5 cases — strict-advance CAS, durable
|
|
38
|
+
persistence across instances, refresh/supersede, corrupt-file self-heal).
|
|
39
|
+
- Regression: `tests/unit/StandbyLeaseObservation.test.ts` (3 cases — a git-less
|
|
40
|
+
standby resolves the holder from a real HttpLeaseTransport broadcast; the holder
|
|
41
|
+
acquires + broadcasts). This is the gap the mocked suites missed.
|
|
42
|
+
- Existing `LeaseCoordinator` (16), `FencedLease` (21), `HttpLeaseTransport` (6)
|
|
43
|
+
suites stay green — no replay-semantic regression. `server` (17) + `middleware`
|
|
44
|
+
(27) green — boot wiring unaffected. `tsc --noEmit` + repo lint clean.
|
|
45
|
+
- Live Tier-3: re-run the two-machine "move this to the other machine" transfer
|
|
46
|
+
after deploy; the standby accepts the forwarded message and serves the session.
|
|
47
|
+
- Side-effects: `upgrades/side-effects/standby-lease-holder-sync.md`.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Side-Effects Review — SourceTreeGuard read-tier + worktree-remove for the AgentWorktreeReaper
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `source-tree-guard-reaper-readtier`
|
|
4
|
+
**Date:** `2026-05-31`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required (single-author safety-guard fix; review is exhaustive below)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The AgentWorktreeReaper (v1.3.133) runs inside the instar server, whose working
|
|
11
|
+
directory IS a checkout of the instar source tree. Every git call it makes was
|
|
12
|
+
blocked by the SourceTreeGuard, so it reported 0 reclaimable in production. This
|
|
13
|
+
change makes three precise, shape-checked widenings in `src/core/SafeGitExecutor.ts`
|
|
14
|
+
— add `cherry` to `READONLY_GIT_VERBS`; add `status` + `cherry` to
|
|
15
|
+
`SOURCE_TREE_READ_TIER_VERBS`; extend the worktree-manager source-tree allowlist
|
|
16
|
+
(`isAllowedWorktreeManagerSubcommand`) to permit `worktree list` and non-forced
|
|
17
|
+
`worktree remove` alongside `add`/`prune` — and passes the corresponding bypass
|
|
18
|
+
flags from the reaper's git wrapper (`src/monitoring/agentWorktreeGit.ts`). It
|
|
19
|
+
interacts with one decision point: the SourceTreeGuard source-tree bypass.
|
|
20
|
+
|
|
21
|
+
## Decision-point inventory
|
|
22
|
+
|
|
23
|
+
- `SafeGitExecutor.isSourceTreeCheckBypassed` (via `SOURCE_TREE_READ_TIER_VERBS`) — modify — add two pure-read verbs (`status`, `cherry`) to the read-tier allowlist.
|
|
24
|
+
- `SafeGitExecutor.isAllowedWorktreeManagerSubcommand` (renamed from `isWorktreeManagerMutation`) — modify — add `list` + non-forced `remove` to the worktree-manager allowlist; explicitly deny `--force`/`-f`.
|
|
25
|
+
- `SafeGitExecutor.readSync` verb classification (via `READONLY_GIT_VERBS`) — modify — recognize `cherry` as read-only (root cause of the silent failure).
|
|
26
|
+
- `agentWorktreeGit.ts` `defaultReadGit` / `removeWorktree` — modify — pass the bypass flags.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 1. Over-block
|
|
31
|
+
|
|
32
|
+
After the change the guard is slightly *more* permissive, not less, so over-block
|
|
33
|
+
risk is unchanged for everyone except the reaper. The one thing that could be
|
|
34
|
+
called "over-block" is intentional: `worktree remove --force` against the source
|
|
35
|
+
tree is still rejected even with `sourceTreeWorktreeManagerOk`. That is by design —
|
|
36
|
+
the forced form is the only one that can delete a dirty worktree, and the reaper
|
|
37
|
+
never needs it. No legitimate caller is newly rejected.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Under-block
|
|
42
|
+
|
|
43
|
+
The relevant question for a guard-*widening* is "does this newly ALLOW something
|
|
44
|
+
dangerous?" The widenings are: two pure reads (`status`, `cherry` — cannot mutate)
|
|
45
|
+
and `worktree remove` without `--force` (which git itself refuses to run against a
|
|
46
|
+
dirty/locked worktree). The residual under-block surface: a caller holding
|
|
47
|
+
`sourceTreeWorktreeManagerOk` could now run `worktree remove` (non-forced) against
|
|
48
|
+
the source tree. That flag is opt-in per call and currently set only by
|
|
49
|
+
`instar worktree create` and this reaper; the non-forced form is self-protecting
|
|
50
|
+
(refuses dirty/locked), so even a misuse cannot delete uncommitted work. `--force`
|
|
51
|
+
stays blocked, which closes the only data-loss path.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 3. Level-of-abstraction fit
|
|
56
|
+
|
|
57
|
+
Correct layer. These are pure reads plus one narrowly-shaped, self-protecting
|
|
58
|
+
mutation, expressed as additions to existing closed allowlists (the established
|
|
59
|
+
pattern for `fetch`/`rev-parse`/`add`/`prune`). The reaper continues to USE the
|
|
60
|
+
`SafeGitExecutor` primitive rather than re-implementing git access, and the
|
|
61
|
+
merged/clean/in-use reasoning stays in the reaper classifier — this change only
|
|
62
|
+
unblocks the reads/remove it already wanted to make.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 4. Signal vs authority compliance
|
|
67
|
+
|
|
68
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
69
|
+
|
|
70
|
+
- [x] No — this change has no block/allow surface over messages or user-facing
|
|
71
|
+
actions. It widens an internal git safety allowlist for one internal consumer.
|
|
72
|
+
|
|
73
|
+
The SourceTreeGuard does hold blocking authority, but its logic here is a closed,
|
|
74
|
+
shape-checked allowlist (not brittle heuristic), and the change makes it recognize
|
|
75
|
+
two harmless reads and one self-protecting mutation. No new blocking authority is
|
|
76
|
+
introduced; the reaper itself remains signal-only (dark + dry-run by default).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 5. Interactions
|
|
81
|
+
|
|
82
|
+
- **Shadowing:** none. The bypass check runs in the same place it always has
|
|
83
|
+
(`isSourceTreeCheckBypassed` inside `readSync`/`execSync`); we add entries to its
|
|
84
|
+
allowlists, we don't reorder checks. `readSync` still rejects destructive shapes
|
|
85
|
+
before the source-tree check, so the read-path widening cannot enable a mutation.
|
|
86
|
+
- **Double-fire:** none. The reaper is the only new consumer; the immediate manual
|
|
87
|
+
reclaim used direct shell `git` (not via SafeGitExecutor) and is unaffected.
|
|
88
|
+
- **Races:** the reaper's `worktree remove` and a concurrent session inside the same
|
|
89
|
+
worktree — covered by the reaper's existing not-in-use gate (lock file + live
|
|
90
|
+
process cwd) AND by git's own non-forced refusal if the worktree is locked. Two
|
|
91
|
+
layers.
|
|
92
|
+
- **Feedback loops:** none.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 6. External surfaces
|
|
97
|
+
|
|
98
|
+
- **Other agents on the same machine:** the guard widening is per-call opt-in via
|
|
99
|
+
flags only this reaper and `instar worktree create` set, so other code paths are
|
|
100
|
+
unchanged. The reaper ships dark + dry-run, so no agent's worktrees are touched
|
|
101
|
+
until explicitly enabled.
|
|
102
|
+
- **Install base:** pure source change, no config/migration/agent-installed files —
|
|
103
|
+
every agent picks it up on the normal update; behavior is identical until the
|
|
104
|
+
reaper is enabled.
|
|
105
|
+
- **External systems:** none.
|
|
106
|
+
- **Persistent state:** none added. When enabled, the reaper removes worktree
|
|
107
|
+
*checkouts* (disk) but never branches/commits — the work is preserved in the
|
|
108
|
+
branch ref and in main.
|
|
109
|
+
- **Timing:** none we don't control.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 7. Rollback cost
|
|
114
|
+
|
|
115
|
+
- **Hot-fix release:** revert the one commit, ship as the next patch. The reaper
|
|
116
|
+
reverts to reporting 0 (blocked); no functional regression elsewhere.
|
|
117
|
+
- **Data migration:** none — no persistent state introduced.
|
|
118
|
+
- **Agent state repair:** none — no agent needs notification or reset.
|
|
119
|
+
- **User visibility:** none — the reaper is dark by default, so no user sees a
|
|
120
|
+
change during a rollback window.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Conclusion
|
|
125
|
+
|
|
126
|
+
This review confirmed the change is a tightly-scoped guard widening: two pure reads
|
|
127
|
+
and one self-protecting mutation, with the only data-loss path (`worktree remove
|
|
128
|
+
--force`) explicitly kept blocked. The review reinforced the decision to deny
|
|
129
|
+
`--force` in the allowlist (not just rely on the reaper never passing it) and to
|
|
130
|
+
add a real-git integration test against a promoted source tree — the test the
|
|
131
|
+
original fake-git suite lacked, which is why the reaper shipped non-functional.
|
|
132
|
+
Clear to ship; verify live via `GET /worktrees/agent-reaper` reporting non-zero.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Side-Effects Review — Standby lease-holder propagation
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `standby-lease-holder-sync`
|
|
4
|
+
**Date:** `2026-05-31`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Decouple cross-machine lease coordination from git. The lease coordinator +
|
|
11
|
+
`HttpLeaseTransport` (and the handoff / reply-marker / live-tail transports) now
|
|
12
|
+
run whenever `coordinator.enabled && coordinator.identity`, instead of being
|
|
13
|
+
nested inside a single `try` gated on `gitBackupEnabled` whose first statement
|
|
14
|
+
(`new GitSyncManager`) throws on an instar-source-tree home (SourceTreeGuard) and
|
|
15
|
+
discarded everything. Git-sync is now an internal best-effort optional; when no
|
|
16
|
+
git medium exists the lease uses a new `LocalLeaseStore` (local-file backed) and
|
|
17
|
+
the HTTP transport carries cross-machine propagation. Also fixes a self-rejection
|
|
18
|
+
in `LeaseCoordinator.effectiveView` (it passed the transport's self-inclusive
|
|
19
|
+
nonce watermark to `acceptTunnelLease`, rejecting the very lease it validated).
|
|
20
|
+
|
|
21
|
+
## Decision-point inventory
|
|
22
|
+
|
|
23
|
+
1. **`gitSyncRef` defined vs undefined** → `GitLeaseStore` vs `LocalLeaseStore`.
|
|
24
|
+
2. **`effectiveView` tunnel-fold** → accept the observed lease iff sig + git-floor
|
|
25
|
+
+ epoch-newer pass (nonce floor now excludes the lease's own holder).
|
|
26
|
+
|
|
27
|
+
## 1. Over-block
|
|
28
|
+
|
|
29
|
+
**What legitimate inputs does this reject?** None added. The lease coordinator now
|
|
30
|
+
runs in MORE cases (git-less machines) than before, not fewer. `acceptTunnelLease`
|
|
31
|
+
still rejects forged/below-floor/older-nonce leases (signature + git-floor +
|
|
32
|
+
replay checks all run); excluding the observed lease's own holder from the nonce
|
|
33
|
+
floor does not weaken this — the transport's `recordObserved` already dropped
|
|
34
|
+
replays on receive, and a forged lease is still caught by the signature check
|
|
35
|
+
before it is ever folded.
|
|
36
|
+
|
|
37
|
+
## 2. Under-block
|
|
38
|
+
|
|
39
|
+
**What does this still miss?** A git-less mesh inherits the tunnel's coordination
|
|
40
|
+
(RTT-bounded acquisition + observe-before-acquire), not git's shared CAS — so its
|
|
41
|
+
split-brain guarantees are exactly the documented tunnel-path guarantees, no
|
|
42
|
+
stronger. This matches the spec non-goal. In the current 1-awake/1-standby
|
|
43
|
+
topology the standby never acquires, so there is no acquisition contention to
|
|
44
|
+
resolve. When git IS available, `GitLeaseStore` (shared CAS) is still used.
|
|
45
|
+
|
|
46
|
+
## 3. Blast radius
|
|
47
|
+
|
|
48
|
+
- New file `LocalLeaseStore.ts` is only constructed when `gitSyncRef` is undefined
|
|
49
|
+
(no git medium). On any git-backed agent the behavior is byte-identical to today
|
|
50
|
+
(`GitLeaseStore` path unchanged).
|
|
51
|
+
- The `effectiveView` change runs for ALL lease-coordinator users (git and
|
|
52
|
+
git-less). It only RELAXES a redundant nonce self-check; existing
|
|
53
|
+
`LeaseCoordinator`/`FencedLease`/`HttpLeaseTransport` unit suites (51 tests
|
|
54
|
+
across these + the new ones) stay green, confirming no replay-semantic
|
|
55
|
+
regression.
|
|
56
|
+
- The server.ts restructure moves the lease/handoff/live-tail setup out of the
|
|
57
|
+
git-gated `try`. A failure in lease setup is still caught (now with a
|
|
58
|
+
"Lease/transport setup" message) so a single-machine agent is unaffected.
|
|
59
|
+
|
|
60
|
+
## 4. Rollback
|
|
61
|
+
|
|
62
|
+
Pure code (no migration, no config default, no schema). Rollback = revert the PR;
|
|
63
|
+
`lease-local.json` becomes inert (no reader). No data is mutated or deleted.
|
|
64
|
+
|
|
65
|
+
## 5. Failure modes
|
|
66
|
+
|
|
67
|
+
- `LocalLeaseStore` persist fails (disk) → logged, in-memory view still serves;
|
|
68
|
+
cross-machine propagation continues over the tunnel. Never blocks boot.
|
|
69
|
+
- Git medium unavailable → caught, lease falls back to LocalLeaseStore. This is
|
|
70
|
+
the intended path, not an error.
|