instar 1.3.56 → 1.3.57

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 (39) hide show
  1. package/dist/commands/test-as-self.d.ts.map +1 -1
  2. package/dist/commands/test-as-self.js +2 -1
  3. package/dist/commands/test-as-self.js.map +1 -1
  4. package/dist/core/PostUpdateMigrator.d.ts +33 -0
  5. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  6. package/dist/core/PostUpdateMigrator.js +117 -0
  7. package/dist/core/PostUpdateMigrator.js.map +1 -1
  8. package/dist/scaffold/templates.d.ts.map +1 -1
  9. package/dist/scaffold/templates.js +4 -0
  10. package/dist/scaffold/templates.js.map +1 -1
  11. package/dist/scheduler/MentorOnboardingRunner.d.ts +10 -1
  12. package/dist/scheduler/MentorOnboardingRunner.d.ts.map +1 -1
  13. package/dist/scheduler/MentorOnboardingRunner.js.map +1 -1
  14. package/dist/server/AgentServer.d.ts +8 -0
  15. package/dist/server/AgentServer.d.ts.map +1 -1
  16. package/dist/server/AgentServer.js +34 -7
  17. package/dist/server/AgentServer.js.map +1 -1
  18. package/dist/server/routes.d.ts.map +1 -1
  19. package/dist/server/routes.js +1 -0
  20. package/dist/server/routes.js.map +1 -1
  21. package/dist/threadline/AgentDiscovery.d.ts +6 -1
  22. package/dist/threadline/AgentDiscovery.d.ts.map +1 -1
  23. package/dist/threadline/AgentDiscovery.js +3 -0
  24. package/dist/threadline/AgentDiscovery.js.map +1 -1
  25. package/dist/threadline/ThreadlineBootstrap.d.ts.map +1 -1
  26. package/dist/threadline/ThreadlineBootstrap.js +20 -2
  27. package/dist/threadline/ThreadlineBootstrap.js.map +1 -1
  28. package/dist/threadline/ThreadlineEndpoints.d.ts +2 -0
  29. package/dist/threadline/ThreadlineEndpoints.d.ts.map +1 -1
  30. package/dist/threadline/ThreadlineEndpoints.js +13 -1
  31. package/dist/threadline/ThreadlineEndpoints.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/data/builtin-manifest.json +64 -64
  34. package/src/scaffold/templates.ts +4 -0
  35. package/upgrades/1.3.56.md +16 -17
  36. package/upgrades/1.3.57.md +49 -0
  37. package/upgrades/side-effects/mentee-agent-name-and-botid-coercion.md +55 -0
  38. package/upgrades/side-effects/test-as-self-skill-demote.md +38 -0
  39. package/upgrades/side-effects/threadline-identity-discovery-unification.md +100 -0
@@ -0,0 +1,49 @@
1
+ # Instar Upgrade Guide — NEXT
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ **1. Mentor cycle round-trip — final fixes (verified live end-to-end).** Three bugs that only surfaced when the full Echo↔Codey round-trip ran on real servers:
8
+
9
+ 1. **`mentor.menteeAgentName` config.** The mentor derived the mentee's agent name as `instar-${menteeFramework}` (e.g. `instar-codex-cli`), but the mentee registers under its real name (`instar-codey`). The mismatch broke same-machine peer lookup AND the reply allowlist. New optional `mentor.menteeAgentName` (defaults to `instar-${menteeFramework}`) carries the real registry name.
10
+ 2. **botId string coercion.** `mentor.menteeBotId` is often stored as a JSON number, but the a2a marker's `senderBotId` is always a string. The allowlist compares with `===`, so a number/string mismatch silently dropped every reply as `agent-marker-unknown`. All botId allowlist entries are now `String()`-coerced.
11
+ 3. **`senderBotId` = sender's own bot id.** The unified transport sent the *recipient's* bot id as the inbox `senderBotId`; the recipient's allowlist check (`knownAgents[from].botId === senderBotId`) therefore always failed. It now sends the *sender's* own bot id (`ownPrimaryBotId()` for replies, the mentor bot id for sends).
12
+
13
+ With these, the mentor cycle round-trips live: a mentor prompt reaches the mentee, the mentee spawns a session + replies, and the reply lands in the mentor's `mentor-replies.jsonl`.
14
+
15
+ **2. Threadline identity-discovery unification** (spec `docs/specs/threadline-identity-discovery-unification.md`, approved). Fixes a fleet-wide bug where an agent advertised a Threadline identity its own relay does not answer to — so peers who discovered it got a dead address and their messages silently vanished.
16
+
17
+ Discovery (`agent-info.json`) and `/threadline/health` now advertise the **routing fingerprint** — the address the relay actually registers with — plus a `publicKey`/`identityPub` set to the SAME canonical `identity.json` key, so the two are internally consistent (`fingerprint === computeFingerprint(publicKey)`). Both are resolved via `IdentityManager.get()`, the exact read-only call the relay client uses, so discovery and routing can never re-diverge.
18
+
19
+ ## What to Tell Your User
20
+
21
+ - The cross-agent mentor cycle now works fully end-to-end on the same machine — verified with a real round-trip. These were the last three wiring bugs (an agent-name assumption, a number-vs-string comparison, and a sender-identity mixup). No config changes required unless your mentee's registry name differs from the default (instar plus the framework name), in which case set the mentee agent name in config.
22
+ - If another agent's messages to me were vanishing (their side said "sent" but nothing arrived), the Threadline fix addresses it: I was handing out an address my relay doesn't listen on. Now I publish the right one everywhere, and existing agents are repaired automatically on the next update/restart — no action needed.
23
+
24
+ ## Summary of New Capabilities
25
+
26
+ | Capability | How to Use |
27
+ |-----------|-----------|
28
+ | `mentor.menteeAgentName` | Set in `.instar/config.json` when the mentee's agent-registry name differs from `instar-<menteeFramework>` (e.g. `instar-codey`). Defaults to the framework-derived name. |
29
+ | Robust botId matching | botId allowlist entries are string-coerced; `senderBotId` is the sender's own bot id. No action needed — fixes silent reply drops. |
30
+ | `fingerprint` field in `/threadline/health` + `agent-info.json` | `curl localhost:PORT/threadline/health` → `fingerprint` is the routable relay address |
31
+ | Threadline fleet repair migrator | `migrateThreadlineAgentInfoIdentity` runs on update; rewrites a diverged `agent-info.json` to the canonical consistent pair (no-op when already aligned or no routing identity) |
32
+
33
+ ## Behavior Notes (Threadline)
34
+
35
+ - **No fabrication:** an agent with no resolvable routing identity (none on disk, or a locked-encrypted `identity.json`) now OMITS `fingerprint`/`publicKey` from discovery instead of inventing a dead address. It becomes relay-discoverable once it has a routing identity (self-heals on the next boot).
36
+ - **Safe encoding/consumer story:** `publicKey` stays hex and is a valid 32-byte Ed25519 key; `/threadline/health.identityPub` switches to the canonical key only when one resolves. The E2E handshake exchanges keys inline (does not read these fields) and `verifyAgent` does no real crypto challenge, so the switch is safe.
37
+
38
+ ## Evidence
39
+
40
+ - **Mentor cycle:** extended `mentor-reply-via-inbox` E2E with a second case proving the menteeAgentName override + numeric-configured botId (string senderBotId) routes + persists. Both cases green; all prior mentor/mentee/inbox tests green. **Live-verified**: full Echo→Codey→Echo round-trip persisted to `mentor-replies.jsonl`. Side-effects: `upgrades/side-effects/mentee-agent-name-and-botid-coercion.md`.
41
+ - **Threadline — wiring (load-bearing):** boot the Threadline stack with a seeded canonical identity → `agent-info.json.fingerprint` equals `IdentityManager.getOrCreate().fingerprint` (the relay's registration source). `tests/e2e/threadline/identity-discovery-wiring.test.ts`.
42
+ - **Threadline — integration:** `/threadline/health` returns a non-empty `identityPub` + a `fingerprint` equal to the relay-registration fingerprint, internally consistent. `tests/integration/threadline/identity-discovery-health.test.ts`.
43
+ - **Threadline — unit (both-sides):** identity present → consistent pair advertised; no/locked identity → both omitted; orphan `identity-keys.json` present → canonical advertised, never the orphan hex. `ThreadlineBootstrap.test.ts`, `ThreadlineEndpoints.test.ts`.
44
+ - **Threadline — migrator:** diverged → repaired; aligned → no-op; no-identity → no-op (no fabrication); idempotent. `tests/unit/PostUpdateMigrator-threadlineAgentInfoIdentity.test.ts`. Verified end-to-end via test-as-self against the built dist (positive + no-identity boundary).
45
+
46
+ ## Out of Scope (Threadline — tracked separately)
47
+
48
+ - Multi-machine same-fingerprint advertisement coordination (cross-machine seamlessness spec). This fix sets the `machine` field and is neutral for multi-machine.
49
+ - Retiring the orphan `identity-keys.json` / collapsing the keypairs. This fix stops *advertising* the orphan; deleting it touches the handshake layer and needs its own spec.
@@ -0,0 +1,55 @@
1
+ # Side-Effects Review — menteeAgentName + botId coercion + senderBotId fix
2
+
3
+ **Spec:** `docs/specs/MENTOR-LIVE-READINESS-SPEC.md` §Recipient side. Final
4
+ fixes closing the live round-trip (the reply leg landed in #469; these are the
5
+ three remaining wiring bugs found by running it end-to-end).
6
+
7
+ **Change:** `src/scheduler/MentorOnboardingRunner.ts` (+1 optional config
8
+ field) + `src/server/AgentServer.ts` (menteeAgentName usage at 3 derivation
9
+ sites, botId String-coercion at 3 allowlist sites, senderBotId=sender's-own
10
+ via new `ownPrimaryBotId()` helper) + extended E2E test.
11
+
12
+ ## What changed
13
+ 1. `MentorConfig.menteeAgentName?: string` — the mentee's real registry name.
14
+ Used in `deliverToMentee`, `installMentorMessageHook` (mentor side), and
15
+ `installMentorReceiverHook`, each falling back to `instar-${menteeFramework}`.
16
+ 2. botId `String()`-coercion at every knownAgents construction (mentor side,
17
+ mentee side, receiver hook) — config may store a JSON number; the marker
18
+ senderBotId is always a string; the allowlist uses `===`.
19
+ 3. `deliverA2aMessage` now takes `fromBotId` (sender's own bot id) and sends
20
+ it as the inbox `senderBotId`. `ownPrimaryBotId()` derives this agent's bot
21
+ id from its messaging config token. Replies pass `ownPrimaryBotId()`; sends
22
+ pass the mentor bot id.
23
+
24
+ ## The seven questions
25
+ 1. **Over-block.** N/A — these LOOSEN an over-strict (buggy) comparison that
26
+ was dropping legitimate replies. Coercion only makes a number match its
27
+ string form; it does not widen the allowlist to new agents.
28
+ 2. **Under-block.** The allowlist still requires an exact (coerced) botId
29
+ match + known agent name. Spoof defense intact — a wrong botId still drops.
30
+ 3. **Level-of-abstraction fit.** Small, local fixes at the exact sites; one
31
+ tiny helper (`ownPrimaryBotId`). No new infrastructure.
32
+ 4. **Signal vs authority.** Unchanged — allowlist still decides route/drop.
33
+ 5. **Interactions.** `menteeAgentName` defaults preserve back-compat for any
34
+ agent whose registry name already equals `instar-<framework>`. Coercion is
35
+ idempotent on already-string values.
36
+ 6. **External surfaces.** One new optional config key (`mentor.menteeAgentName`).
37
+ No new routes.
38
+ 7. **Rollback cost.** Trivial — revert restores framework-derived names + the
39
+ number/string comparison (re-introducing the silent reply drop).
40
+
41
+ ## Testing
42
+ Extended `mentor-reply-via-inbox` E2E (now 2 cases): the original
43
+ (framework-derived name, string botId) + the new regression (menteeAgentName
44
+ override, numeric-configured botId, string senderBotId) — both route + persist.
45
+ All prior mentor/mentee/inbox tests green. tsc clean.
46
+
47
+ **Live verification (test-as-self):** the worktree build was shadow-deployed to
48
+ the live Echo + Codey pair; a real mentor prompt round-tripped — Codey spawned
49
+ a mentee session, replied via /a2a/inbox, and Echo persisted the reply to
50
+ mentor-replies.jsonl (corr=FULL-…, from=instar-codey, transport=a2a-inbox-local).
51
+
52
+ ## Migration parity
53
+ `mentor.menteeAgentName` is optional with a back-compat default — no migration
54
+ needed. The botId coercion + senderBotId fix are pure code (no config/state
55
+ change). No PostUpdateMigrator change.
@@ -0,0 +1,38 @@
1
+ # Side-Effects Review — test-as-self SKILL Part 2.1 demote + migrator (Track F follow-up)
2
+
3
+ **Scope.** `.claude/skills/test-as-self/SKILL.md` (lead with the one-button
4
+ command, demote the manual recipe to fallback), `src/core/PostUpdateMigrator.ts`
5
+ (`migrateTestAsSelfSkill` + registration), `tests/unit/migrate-test-as-self-skill.test.ts`.
6
+
7
+ **What + why.** Track F shipped the `instar test-as-self` command but left the
8
+ SKILL.md as the v1 manual runbook (deferred, tracked). This closes that loop:
9
+ the SKILL now leads with "## The one-button path (Part 2.1 — use this first)"
10
+ (the command), with the manual recipe demoted to fallback — so an agent reading
11
+ the skill reaches for the command first. Plus a PostUpdateMigrator method so
12
+ EXISTING agents' on-disk SKILL.md gets the update (installBuiltinSkills is
13
+ install-if-missing, so a dedicated migration is the only path per the Migration
14
+ Parity Standard).
15
+
16
+ **Side-effects review.**
17
+ - **Content-only skill change** — no behavior change; the command itself shipped
18
+ in Track F (#472). This just makes it discoverable in the skill surface.
19
+ - **Migration is conservative + idempotent** — re-copies the bundled SKILL only
20
+ when the installed copy LACKS the Part 2.1 marker AND still matches the stock
21
+ fingerprint (`Throwaway-Deploy Harness` + `verify.mjs`). A customized skill is
22
+ left untouched (recorded in result.skipped); an already-updated one is a no-op;
23
+ a not-installed one is a no-op. Mirrors the proven migrateBuildSkillMethodology
24
+ pattern exactly.
25
+ - **No data/secret impact** — pure doc/skill content.
26
+
27
+ **Test coverage.** Unit `tests/unit/migrate-test-as-self-skill.test.ts` (4):
28
+ stock-v1 → updated (marker present, result.upgraded set); idempotent (already-
29
+ marked → unchanged, no upgrade); customized → untouched (result.skipped);
30
+ not-installed → no-op (no error). All green; tsc clean. The test also implicitly
31
+ verifies the bundled SKILL.md carries the new marker.
32
+
33
+ **Migration parity.** This IS the migration-parity fix for Track F's SKILL
34
+ update. New agents get the new SKILL via installBuiltinSkills; existing agents
35
+ get it via `migrateTestAsSelfSkill` on update.
36
+
37
+ **Rollback.** Revert. The SKILL reverts to the v1 manual-first runbook; the
38
+ command still works (it's independent). No data change.
@@ -0,0 +1,100 @@
1
+ # Side-Effects Review — Threadline Identity-Discovery Unification
2
+
3
+ **Slug:** `threadline-identity-discovery-unification`
4
+ **Date:** 2026-05-28
5
+ **Author:** Echo (instar developer)
6
+ **Spec:** `docs/specs/threadline-identity-discovery-unification.md` (converged iter 2, approved)
7
+
8
+ ## Summary of the change
9
+
10
+ Discovery was advertising an identity the agent's own relay does not answer to.
11
+ `announcePresence` wrote `agent-info.json.publicKey` from the orphan
12
+ `threadline/identity-keys.json` hex key, and `/threadline/health` reported
13
+ `identityPub` from the HandshakeManager key (empty on some agents) — while the
14
+ relay client registers (and routes) by the canonical `identity.json`
15
+ fingerprint. A peer who discovered the agent got a non-routable address, so
16
+ their messages vanished (their side `sent=true`, no "Accepted message from …"
17
+ on the receiver). Fleet-wide for any agent whose canonical identity was
18
+ generated independently of its legacy keys.
19
+
20
+ The fix advertises the **routing identity** everywhere, internally consistent:
21
+ `agent-info.json` and `/threadline/health` now publish a `fingerprint`
22
+ (routable relay address) plus a `publicKey`/`identityPub` set to the SAME
23
+ canonical key, sourced from `IdentityManager.get()` — the exact read-only API
24
+ the relay client uses, so the two can never re-diverge.
25
+
26
+ **Files changed (source):**
27
+ - `src/threadline/AgentDiscovery.ts` — `fingerprint` field on `AgentInfoFile`,
28
+ `ThreadlineAgentInfo`, `HealthResponse`; `announcePresence` accepts +
29
+ persists it; `pingThreadlineHealth`/`verifyAgent` propagate it.
30
+ - `src/threadline/ThreadlineBootstrap.ts` — resolve `IdentityManager.get()` up
31
+ front; advertise canonical `publicKey`(hex)+`fingerprint`+`machine`; omit both
32
+ when `get()` is null (no fabrication).
33
+ - `src/threadline/ThreadlineEndpoints.ts` — `/threadline/health` sources
34
+ `identityPub`+`fingerprint` from `IdentityManager.get()`; `stateDir` added to
35
+ config; falls back to the handshake key + omits fingerprint when no routing
36
+ identity resolves.
37
+ - `src/server/routes.ts` — pass `stateDir` to `createThreadlineRoutes`.
38
+ - `src/core/PostUpdateMigrator.ts` — `migrateThreadlineAgentInfoIdentity`
39
+ (belt-and-suspenders fleet repair) + `migrateClaudeMd` routing-fingerprint
40
+ guidance section.
41
+ - `src/scaffold/templates.ts` — CLAUDE.md template "What address reaches me"
42
+ section (Agent Awareness).
43
+ - `src/data/builtin-manifest.json` — regenerated by the build (template hashes).
44
+
45
+ **Files changed (tests):** `ThreadlineBootstrap.test.ts`,
46
+ `ThreadlineEndpoints.test.ts` (+3 new: migrator unit, health integration,
47
+ bootstrap wiring e2e).
48
+
49
+ **Drive-by (unrelated, green-keeping):** `src/commands/test-as-self.ts` line 60
50
+ — `new URL(import.meta.url).pathname` → `fileURLToPath(import.meta.url)`. This
51
+ is the URL-pathname-path-encoding pattern (breaks when the project path
52
+ contains spaces) that the pre-push gate (`scripts/pre-push-gate.js`) flags; it
53
+ was introduced into `test-as-self.ts` by an earlier merge and the pre-push gate
54
+ blocks any push until it is fixed (the check is pre-push-only, not in CI, which
55
+ is why it landed). One-line fix to the documented-correct pattern; no behavior
56
+ change.
57
+
58
+ ## Blast radius / consumers
59
+
60
+ - **`agent-info.json.publicKey` encoding** is unchanged (hex) and now sourced
61
+ from the canonical key. Consumers (`verifyAgent` does `Buffer.from(.., 'hex')`
62
+ + 32-byte length check) still work; the key is a valid 32-byte Ed25519 key.
63
+ - **`/threadline/health.identityPub`** switches from the handshake key to the
64
+ canonical routing key WHEN one resolves. Safe: `verifyAgent` does not perform
65
+ a real cryptographic challenge (nonce generated, never exchanged), and the E2E
66
+ handshake exchanges keys inline — it does not read `agent-info.json` or the
67
+ health `identityPub`. Verified by reading `ThreadlineEndpoints.ts` handshake
68
+ paths + `AgentDiscovery.verifyAgent`.
69
+ - **No-fabrication boundary:** a relay-disabled / no-identity / locked-encrypted
70
+ agent now OMITS `fingerprint`+`publicKey` instead of advertising a key for an
71
+ identity on no relay. This is a behavior change for brand-new agents on their
72
+ very first announce (before the relay client creates an identity) — correct
73
+ per spec (not relay-discoverable until a routing identity exists), self-heals
74
+ on the next boot once the identity is created.
75
+ - **Migrator** only rewrites `agent-info.json` when `get()` resolves AND the
76
+ file is misaligned; no-ops otherwise (idempotent, atomic write, never
77
+ fabricates).
78
+
79
+ ## Migration parity
80
+
81
+ Existing agents: the in-`announcePresence` rewrite self-heals on the
82
+ post-update server restart; `migrateThreadlineAgentInfoIdentity` closes the
83
+ narrow update-without-restart window; `migrateClaudeMd` adds the guidance for
84
+ agents whose CLAUDE.md predates this. New agents get all of it via `init` +
85
+ the template.
86
+
87
+ ## Out of scope (tracked, not deferred)
88
+
89
+ - Multi-machine same-fingerprint advertisement coordination →
90
+ `project_cross_machine_seamlessness_spec`. This fix sets the `machine` field
91
+ (attributable) and is neutral for multi-machine.
92
+ - Retiring the orphan `identity-keys.json` / collapsing the 3–4 keypairs →
93
+ `bug_threadline_identity_divergence_discovery`. This fix stops *advertising*
94
+ the orphan; deleting it touches the handshake layer and needs its own spec.
95
+
96
+ ## Risk
97
+
98
+ Low. Additive at the field level; `agent-info.json` is regenerated on every
99
+ boot regardless. Reverting removes the field + migrator with no data loss. All
100
+ three test tiers + wiring + both-sides green; full `test:push` suite green.