instar 1.3.104 → 1.3.106
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 +14 -3
- package/dist/commands/server.js.map +1 -1
- package/dist/monitoring/MentorStageA.d.ts.map +1 -1
- package/dist/monitoring/MentorStageA.js +14 -1
- package/dist/monitoring/MentorStageA.js.map +1 -1
- package/dist/scheduler/MentorOnboardingRunner.d.ts.map +1 -1
- package/dist/scheduler/MentorOnboardingRunner.js +6 -1
- package/dist/scheduler/MentorOnboardingRunner.js.map +1 -1
- package/dist/scheduler/MentorOnboardingTick.d.ts +7 -0
- package/dist/scheduler/MentorOnboardingTick.d.ts.map +1 -1
- package/dist/scheduler/MentorOnboardingTick.js +8 -3
- package/dist/scheduler/MentorOnboardingTick.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +16 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/1.3.105.md +64 -0
- package/upgrades/1.3.106.md +39 -0
- package/upgrades/side-effects/mentor-stage-a-prompt-bound.md +55 -0
- package/upgrades/side-effects/mentor-stage-a-robustness.md +57 -0
- package/upgrades/side-effects/mesh-signing-key-filename-fix.md +54 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**The Framework-Onboarding mentor now reports WHY a tick failed, and its Stage-A
|
|
8
|
+
step is more resilient.** The mentor's Stage-A step spawns a tiny tool-less
|
|
9
|
+
session to compose the next coaching message, then captures it. When that spawn
|
|
10
|
+
failed (common on a busy multi-agent box — session-cap pressure / load), the
|
|
11
|
+
whole tick collapsed to an opaque `stage-a-failed` with the real cause thrown
|
|
12
|
+
away, so it was undiagnosable from `GET /mentor/status`. Now: the real error is
|
|
13
|
+
surfaced into `lastResult.error`, and the Stage-A compose-session spawn retries
|
|
14
|
+
once with a short backoff before failing with a clear, specific message.
|
|
15
|
+
|
|
16
|
+
**Multi-machine: the SEND side of the cross-machine command channel now works on
|
|
17
|
+
a normally-created machine.** The private per-machine key used to sign every
|
|
18
|
+
machine-to-machine command was being loaded from the wrong filename
|
|
19
|
+
(`signing-private.pem`), but a normally-created machine stores it as
|
|
20
|
+
`signing-key.pem`. So a normal machine signed its outbound commands with an empty
|
|
21
|
+
key and the send silently failed — it could receive from peers but never call out
|
|
22
|
+
to them (check a peer's presence, hand off a conversation, move one). The loader
|
|
23
|
+
now reads the canonical filename, falling back to the legacy one. This is the
|
|
24
|
+
send-side companion to the recent command-channel auth fix; together they make
|
|
25
|
+
the cross-machine pool actually work over the network. (Found on real hardware:
|
|
26
|
+
the laptop couldn't see the mini until its signing key loaded.)
|
|
27
|
+
|
|
28
|
+
## What to Tell Your User
|
|
29
|
+
|
|
30
|
+
Only relevant if you run the (off-by-default) Framework-Onboarding mentor. It now
|
|
31
|
+
recovers from a transient compose-session spawn failure, and when it does fail it
|
|
32
|
+
tells you exactly why (visible on the mentor status page) instead of an
|
|
33
|
+
unexplained "stage-a-failed."
|
|
34
|
+
|
|
35
|
+
If you run across two machines: this release fixes the last piece that kept a
|
|
36
|
+
normally-created machine from being able to reach its peers — a second machine
|
|
37
|
+
will now correctly show as online and be eligible to receive conversations, and
|
|
38
|
+
moving a conversation between machines works. Both machines need to update.
|
|
39
|
+
|
|
40
|
+
## Summary of New Capabilities
|
|
41
|
+
|
|
42
|
+
- `GET /mentor/status` → `lastResult.error` now carries the real Stage-A failure
|
|
43
|
+
cause (`MentorTickResult.error`), instead of swallowing it.
|
|
44
|
+
- `spawnStageA` retries the compose-session spawn once (transient resilience) and
|
|
45
|
+
throws a clear `stage-a-spawn-failed: … — <cause>` on persistent failure.
|
|
46
|
+
- The MeshRpcClient signing-key loader reads the canonical `signing-key.pem`
|
|
47
|
+
(falling back to legacy `signing-private.pem`), so a normally-created machine
|
|
48
|
+
can sign — and therefore SEND — cross-machine commands.
|
|
49
|
+
|
|
50
|
+
## Evidence
|
|
51
|
+
|
|
52
|
+
- `tests/unit/MentorOnboardingRunner.test.ts` (+1): a `spawnStageA` that throws
|
|
53
|
+
now yields `lastResult = {ran:false, reason:'stage-a-failed', error:<msg>}` —
|
|
54
|
+
asserts the cause is surfaced (was swallowed by a bare catch in
|
|
55
|
+
`runMentorTick`). Full mentor/stage suite (113 tests / 9 files) green;
|
|
56
|
+
`tsc --noEmit` clean.
|
|
57
|
+
- `tests/unit/mesh-signing-key-resolution.test.ts` — the loader reads the
|
|
58
|
+
canonical `signing-key.pem`, tries it before the legacy `signing-private.pem`,
|
|
59
|
+
and the canonical name matches `MachineIdentity.SIGNING_KEY_FILE`.
|
|
60
|
+
- Found on real hardware (laptop + mini): the laptop's puller recorded the mini
|
|
61
|
+
online over the signed HTTP channel only after its signing key loaded; before,
|
|
62
|
+
it signed with an empty key and the send threw.
|
|
63
|
+
- Side-effects: `upgrades/side-effects/mentor-stage-a-robustness.md`,
|
|
64
|
+
`upgrades/side-effects/mesh-signing-key-filename-fix.md`.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**Fixed the root cause of the Framework-Onboarding mentor's Stage-A failures: the
|
|
8
|
+
compose prompt grew past tmux's command-line limit.** Stage-A spawns a session to
|
|
9
|
+
compose the next coaching message, passing the prompt — which embeds the whole
|
|
10
|
+
growing mentor↔mentee conversation — as a `tmux new-session` command-line
|
|
11
|
+
argument. tmux has a command-length limit (~12-16KB); once the accumulated
|
|
12
|
+
history crossed it, `tmux new-session` failed with "command too long", so the
|
|
13
|
+
step failed and the mentee got nothing (it worked early on, then broke as history
|
|
14
|
+
piled up). The conversation history fed into the Stage-A prompt is now bounded to
|
|
15
|
+
the most-recent ~6KB (with an explicit "older conversation elided" marker), so the
|
|
16
|
+
spawn stays under tmux's limit no matter how long the mentorship runs.
|
|
17
|
+
|
|
18
|
+
## What to Tell Your User
|
|
19
|
+
|
|
20
|
+
Only relevant if you run the (off-by-default) Framework-Onboarding mentor. Its
|
|
21
|
+
Stage-A step is now reliable for long-running mentorships — the prompt can't grow
|
|
22
|
+
past the limit that was making it fail. No behaviour change for short
|
|
23
|
+
conversations.
|
|
24
|
+
|
|
25
|
+
## Summary of New Capabilities
|
|
26
|
+
|
|
27
|
+
- `buildStageAContext` bounds the conversation history at 6000 chars (keeps the
|
|
28
|
+
most-recent exchanges + a marker), keeping the Stage-A prompt under tmux's
|
|
29
|
+
command-line limit — fixes the `stage-a-failed` root cause.
|
|
30
|
+
|
|
31
|
+
## Evidence
|
|
32
|
+
|
|
33
|
+
- `tests/unit/MentorStageA.test.ts` (+1): an ~80KB history produces a prompt
|
|
34
|
+
under 12KB that keeps the most-recent exchange, carries the elision marker, and
|
|
35
|
+
preserves the prompt structure. Full mentor/stage suite (114 tests / 9 files)
|
|
36
|
+
green; `tsc` + `npm run lint` clean.
|
|
37
|
+
- Cold tmux repro: a 120KB argument to `tmux new-session` fails with "command too
|
|
38
|
+
long"; 12KB passes — confirming the 6KB history cap is safely below the limit.
|
|
39
|
+
- Side-effects: `upgrades/side-effects/mentor-stage-a-prompt-bound.md`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Side-effects review — Mentor Stage-A: bound the compose prompt
|
|
2
|
+
|
|
3
|
+
**Spec:** `docs/specs/MENTOR-STAGE-A-PROMPT-BOUND-SPEC.md`
|
|
4
|
+
**Change:** `src/monitoring/MentorStageA.ts` (`buildStageAContext`) + unit test
|
|
5
|
+
**Class:** mentor reliability fix (root cause of `stage-a-failed`).
|
|
6
|
+
|
|
7
|
+
## What changed
|
|
8
|
+
|
|
9
|
+
`buildStageAContext` now caps `surface.threadlineHistory` at `MAX_HISTORY_CHARS =
|
|
10
|
+
6000`, keeping the most-recent tail + an explicit `older conversation elided`
|
|
11
|
+
marker, so the assembled Stage-A prompt can't exceed tmux's `new-session`
|
|
12
|
+
command-line limit (~12-16KB) — the confirmed cause of the spawn failure.
|
|
13
|
+
|
|
14
|
+
## Blast radius
|
|
15
|
+
|
|
16
|
+
- **`buildStageAContext` callers:** only `runMentorTick` (Stage-A). The function
|
|
17
|
+
signature/output shape is unchanged (still returns the prompt string); only the
|
|
18
|
+
history portion is bounded when it exceeds 6000 chars.
|
|
19
|
+
- **Mentor behaviour:** unchanged for short histories (the bound only engages
|
|
20
|
+
above 6000 chars). For long histories, the prompt now contains the recent
|
|
21
|
+
exchanges + a marker instead of the full transcript — the mentor still has the
|
|
22
|
+
agenda + recent state to decide the next action.
|
|
23
|
+
- **Two-hats isolation / leak detection / agenda logic:** untouched.
|
|
24
|
+
- **Public API / DB schema / config / other spawns:** none changed. Regular
|
|
25
|
+
(non-mentor) session spawns are unaffected (their prompts are small and were
|
|
26
|
+
never the growth vector).
|
|
27
|
+
|
|
28
|
+
## What could break (and why it doesn't)
|
|
29
|
+
|
|
30
|
+
- **Mentor lacks older context?** By design — the recent 6KB + agenda + status
|
|
31
|
+
carry the "what's next" decision; older middle history is least relevant.
|
|
32
|
+
- **A single huge recent message?** The hard char cap bounds the history block
|
|
33
|
+
regardless of message boundaries.
|
|
34
|
+
- **Leak detector seeing a truncated transcript?** It runs on the Stage-A
|
|
35
|
+
*output* transcript, not on this input prompt — unaffected.
|
|
36
|
+
|
|
37
|
+
## Security
|
|
38
|
+
|
|
39
|
+
No new external input / network / auth / fs surface. Pure in-memory string bound.
|
|
40
|
+
|
|
41
|
+
## Migration parity
|
|
42
|
+
|
|
43
|
+
Server-internal monitoring code — every agent gets it by running the new build.
|
|
44
|
+
No PostUpdateMigrator entry required.
|
|
45
|
+
|
|
46
|
+
## Rollback
|
|
47
|
+
|
|
48
|
+
Revert the commit. No persisted state, schema, or API contract affected.
|
|
49
|
+
|
|
50
|
+
## Tests
|
|
51
|
+
|
|
52
|
+
`tests/unit/MentorStageA.test.ts` (+1): an ~80KB history → prompt < 12KB, keeps
|
|
53
|
+
the most-recent exchange, carries the elision marker, preserves structure. Full
|
|
54
|
+
mentor/stage suite (114 tests / 9 files) green; `tsc` + `npm run lint` clean.
|
|
55
|
+
Cold tmux repro confirmed the limit (120KB → "command too long"; 12KB passes).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Side-effects review — Mentor Stage-A: surface error + harden spawn
|
|
2
|
+
|
|
3
|
+
**Spec:** `docs/specs/MENTOR-STAGE-A-ROBUSTNESS-SPEC.md`
|
|
4
|
+
**Changes:** `src/scheduler/MentorOnboardingTick.ts`, `src/scheduler/MentorOnboardingRunner.ts`, `src/server/AgentServer.ts` (+ unit test)
|
|
5
|
+
**Class:** mentor reliability + diagnosability fix.
|
|
6
|
+
|
|
7
|
+
## What changed
|
|
8
|
+
|
|
9
|
+
1. `MentorTickResult` gains `error?: string`.
|
|
10
|
+
2. `runMentorTick`'s bare `catch {}` around `spawnStageA` → `catch (err)` that
|
|
11
|
+
captures the message into the returned result (`{…, error}`) + the finding
|
|
12
|
+
title.
|
|
13
|
+
3. `MentorOnboardingRunner.startTick().catch` adds the same `error` field (for a
|
|
14
|
+
rejected `tick()`).
|
|
15
|
+
4. `spawnStageA` (AgentServer.ts) wraps `spawnSession` in a single retry with a
|
|
16
|
+
3s backoff; on persistent failure throws `stage-a-spawn-failed: … — <cause>`.
|
|
17
|
+
|
|
18
|
+
## Blast radius
|
|
19
|
+
|
|
20
|
+
- **`/mentor/status` consumers:** purely additive — `lastResult` may now include
|
|
21
|
+
an `error` string on the failure path. No field removed/renamed.
|
|
22
|
+
- **Healthy mentor ticks:** unchanged — new code runs only on the catch/failure
|
|
23
|
+
path or a throwing spawn.
|
|
24
|
+
- **Stage-A two-hats isolation:** unchanged — still spawns with the empty
|
|
25
|
+
`STAGE_A_ALLOWED_TOOLS` grant; only error handling + a retry added.
|
|
26
|
+
- **Public API / DB schema / config:** none changed. No new route (the
|
|
27
|
+
AgentServer change is inside an existing closure — E2E-PAIRING exempt).
|
|
28
|
+
|
|
29
|
+
## What could break (and why it doesn't)
|
|
30
|
+
|
|
31
|
+
- **The retry doubling spawn load?** Only on a spawn that already failed once,
|
|
32
|
+
and capped at 2 attempts with a 3s gap — negligible, and only on the
|
|
33
|
+
already-failing path.
|
|
34
|
+
- **`error` field typing:** flows through `MentorRunResult extends
|
|
35
|
+
Omit<MentorTickResult,'reason'>` which keeps `error?`. `tsc` clean.
|
|
36
|
+
- **Masking a persistent failure:** no — a persistent failure still throws after
|
|
37
|
+
2 attempts, now with the cause in the message.
|
|
38
|
+
|
|
39
|
+
## Security
|
|
40
|
+
|
|
41
|
+
No new external input / network / auth / fs surface. The surfaced `error` is an
|
|
42
|
+
internal spawn/timeout message (no secrets).
|
|
43
|
+
|
|
44
|
+
## Migration parity
|
|
45
|
+
|
|
46
|
+
Server-internal scheduler/server code — every agent gets it by running the new
|
|
47
|
+
build. No PostUpdateMigrator entry required.
|
|
48
|
+
|
|
49
|
+
## Rollback
|
|
50
|
+
|
|
51
|
+
Revert the commit. No persisted state, schema, or API contract affected.
|
|
52
|
+
|
|
53
|
+
## Tests
|
|
54
|
+
|
|
55
|
+
`tests/unit/MentorOnboardingRunner.test.ts` (+1): a throwing `spawnStageA` now
|
|
56
|
+
surfaces `lastResult.error` with the real message (was swallowed). Full
|
|
57
|
+
mentor/stage suite — 113 tests across 9 files — green; `tsc --noEmit` clean.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Side-effects review — mesh signing-key filename fix (the SEND-side break)
|
|
2
|
+
|
|
3
|
+
## What was happening (real-hardware, 2026-05-30)
|
|
4
|
+
|
|
5
|
+
After the /mesh/rpc auth exemption (v1.3.104) deployed to BOTH machines, the Mac
|
|
6
|
+
mini STILL showed offline on the laptop (the router). The mini→laptop presence
|
|
7
|
+
pull worked (the mini's log: `recorded 1 peer(s) online: m_cc2ec651`), but the
|
|
8
|
+
laptop→mini direction never fired and the mini never even RECEIVED the laptop's
|
|
9
|
+
`session-status` call.
|
|
10
|
+
|
|
11
|
+
Root cause: the server-boot loader for `localSigningKeyPem` — the private key the
|
|
12
|
+
`MeshRpcClient` signs every outbound machine-to-machine command with — hard-coded
|
|
13
|
+
the filename `signing-private.pem`. But `MachineIdentity` writes the signing key
|
|
14
|
+
as `signing-key.pem` (its `SIGNING_KEY_FILE`). So a normally-created install had
|
|
15
|
+
`signing-private.pem` ABSENT → `localSigningKeyPem` stayed `''` → the
|
|
16
|
+
`MeshRpcClient` signed with an empty key → the send threw → the machine could NOT
|
|
17
|
+
pull presence from / deliver to / transfer to any peer. It still RECEIVED fine,
|
|
18
|
+
because the receive path verifies the OTHER machine's key (which it has), not its
|
|
19
|
+
own. That produced the exact asymmetry observed: the mini (propagated with the
|
|
20
|
+
non-canonical `signing-private.pem`) could send; the laptop (canonical
|
|
21
|
+
`signing-key.pem`) could not — two filename bugs lining up.
|
|
22
|
+
|
|
23
|
+
Confirmed by giving the laptop a `signing-private.pem` copy of its own key +
|
|
24
|
+
restarting: the laptop immediately began recording the mini online over HTTP, and
|
|
25
|
+
the pool showed both machines online.
|
|
26
|
+
|
|
27
|
+
## The fix
|
|
28
|
+
|
|
29
|
+
- **`src/commands/server.ts`** — the loader now reads the CANONICAL
|
|
30
|
+
`signing-key.pem` first, falling back to the legacy/propagated
|
|
31
|
+
`signing-private.pem`, so BOTH layouts load a key. (The lease transport already
|
|
32
|
+
used `idMgr.loadSigningKey()`, which reads the canonical name — only this
|
|
33
|
+
MeshRpcClient loader was on the wrong filename.)
|
|
34
|
+
|
|
35
|
+
## Blast radius
|
|
36
|
+
|
|
37
|
+
- **Pure fix to a boot-time read on the multi-machine path.** A single-machine
|
|
38
|
+
agent never constructs a MeshRpcClient, so it is unaffected. A machine that
|
|
39
|
+
already had `signing-private.pem` (propagated) keeps working via the fallback.
|
|
40
|
+
A machine with the canonical `signing-key.pem` (the common case) now loads its
|
|
41
|
+
key and can SEND cross-machine commands — the bug fix.
|
|
42
|
+
- **No new config / route / schema / hook / skill → no migration.** Server code;
|
|
43
|
+
existing agents pick it up on the next release. This is the SEND-side companion
|
|
44
|
+
to the /mesh/rpc auth exemption (the receive-side fix) — both were needed for
|
|
45
|
+
the cross-machine pool to function over the wire.
|
|
46
|
+
- **Separately, the propagation path should write the canonical `signing-key.pem`**
|
|
47
|
+
(it currently writes `signing-private.pem`); that is a propagation-side cleanup
|
|
48
|
+
tracked separately. This fix makes the loader tolerant of both regardless.
|
|
49
|
+
|
|
50
|
+
## Tests
|
|
51
|
+
|
|
52
|
+
- `tests/unit/mesh-signing-key-resolution.test.ts` — the loader reads the
|
|
53
|
+
canonical `signing-key.pem`, tries it BEFORE the legacy `signing-private.pem`
|
|
54
|
+
(fallback order), and the canonical name matches `MachineIdentity.SIGNING_KEY_FILE`.
|