instar 1.3.256 → 1.3.258

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.
@@ -0,0 +1,46 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ Finishes Phase 4 of the multi-machine arc: cross-machine secret sync. A secret given to the
9
+ agent on one machine can now be distributed, encrypted, to its other machines — so the same
10
+ agent can use it everywhere without the user re-entering it per machine.
11
+
12
+ - **`SecretSync` module** — `SecretProvisioner` (sender side: encrypts the secret set per
13
+ recipient to that machine's X25519 key and pushes a signed `secret-share` over the mesh) +
14
+ `SecretShareHandler` (receiver side: decrypts with this machine's own key and stores into
15
+ the local encrypted vault) + `secretKeyPaths` (names-only flattening for status).
16
+ - **Reuses the existing forward-secret crypto** (`encryptForSync`/`decryptFromSync`,
17
+ ephemeral-key-per-payload X25519 → AES-GCM); the mesh already enforces TLS, Ed25519
18
+ signing, and the registered-peer gate, so this adds application-layer confidentiality.
19
+ - **Two routes** (both behind auth): `GET /secrets/sync-status` reports which secret key
20
+ NAMES this machine holds plus the peers it would sync to (never a value); `POST
21
+ /secrets/sync-now` is the deterministic push lever (encrypts per online peer and pushes).
22
+ - **Config flag** `multiMachine.secretSync.enabled` — ships dark; defaults on only for the
23
+ development agent. A single-machine agent is a no-op.
24
+
25
+ ## What to Tell Your User
26
+
27
+ - **A secret you give me on one machine can become usable on your other machines** — a bot
28
+ token, an API key, a login — without you setting it up again on each computer. It travels
29
+ encrypted to each of your machines and is never written down in plain text along the way.
30
+ - This is an early capability and ships turned off by default. When it is on, if you ever
31
+ start re-entering something you already gave me elsewhere, I can tell you it already synced.
32
+
33
+ ## Summary of New Capabilities
34
+
35
+ - Cross-machine secret distribution: drop a secret once, use it on every paired machine.
36
+ - A read-only status view of which secrets a machine holds (names only, never values).
37
+ - A deterministic push lever to sync secrets on demand.
38
+
39
+ ## Evidence
40
+
41
+ 15 tests across all three tiers: 8 unit (real-crypto round-trip, per-recipient sealing,
42
+ wrong-key-fails confidentiality, best-effort fan-out, names-only flattening), 4 integration
43
+ (real SecretStore + real crypto encrypt→ship→decrypt through the HTTP routes, asserting no
44
+ secret value ever appears in a response, plus the 503-when-disabled paths), and 3 e2e (the
45
+ routes alive through the real AgentServer with a genuine round-trip into a peer vault, behind
46
+ auth). Spec: docs/specs/cross-machine-secret-sync-spec.md (approved).
@@ -0,0 +1,112 @@
1
+ # Side-Effects Review — Cross-Machine Secret Sync
2
+
3
+ **Version / slug:** `cross-machine-secret-sync`
4
+ **Date:** `2026-06-04`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required` (Tier 2; single-author under Justin's explicit signoff)
7
+
8
+ ## Summary of the change
9
+
10
+ Implements Phase 4 of the multi-machine arc: a secret given to the agent on one machine is
11
+ distributed, encrypted per-recipient, to its other registered machines so the same agent can
12
+ use it everywhere without re-entry. New `src/core/SecretSync.ts` holds a `SecretProvisioner`
13
+ (sender: encrypt the secret set to each online peer's X25519 key, push a signed `secret-share`
14
+ over the mesh), a `SecretShareHandler` (receiver: decrypt with this machine's own key, store
15
+ into the local encrypted vault), and `secretKeyPaths` (names-only flattening for status). The
16
+ inbound dispatcher handler was already wired in `src/commands/server.ts`; this change adds the
17
+ OUTBOUND provisioner (constructed after the MeshRpcClient), a route-facing `_secretSyncHandle`,
18
+ two routes in `src/server/routes.ts` (`GET /secrets/sync-status`, `POST /secrets/sync-now`)
19
+ plumbed through `AgentServer` + `RouteContext`, the `multiMachine.secretSync` config type, and
20
+ agent-awareness (CLAUDE.md template + `PostUpdateMigrator` section). Crypto is reused, not new
21
+ (`encryptForSync`/`decryptFromSync`, forward-secret ephemeral-key X25519→AES-GCM).
22
+
23
+ ## Decision-point inventory
24
+
25
+ - `multiMachine.secretSync.enabled` gate (server.ts) — **add** — enables inbound handler +
26
+ outbound provisioner; resolves to `config.multiMachine.secretSync.enabled ?? !!developmentAgent`
27
+ (dark for normal agents, on for the dev agent).
28
+ - `SecretProvisioner.listPeers` online filter — **add** — only online, registered peers with a
29
+ resolvable encryption key receive a push.
30
+ - `secret-share` mesh acceptance — **pass-through** — authenticity, signing, registered-peer
31
+ gate, and nonce replay are already enforced by the existing MeshRpcDispatcher verify/RBAC
32
+ layer; this change adds only application-layer confidentiality on top.
33
+
34
+ ## 1. Over-block
35
+
36
+ No block/allow surface — over-block not applicable. The two routes 503 only when the feature
37
+ is disabled or the handle is absent; they never reject a legitimate request when enabled.
38
+
39
+ ## 2. Under-block
40
+
41
+ No block/allow surface — under-block not applicable. (Security property of note instead: a
42
+ `secret-share` payload sealed to machine A cannot be decrypted by machine B — GCM auth fails —
43
+ covered by the "wrong key fails" unit test.)
44
+
45
+ ## 3. Level-of-abstraction fit
46
+
47
+ Right layer. The transport-level guarantees (TLS, Ed25519 signing, registered-peer gate, nonce
48
+ replay) live in the mesh and are reused, not re-implemented. This change is purely the
49
+ application-layer secret-distribution logic over that transport, plus thin route/handle wiring.
50
+ It USES the existing `encryptForSync`/`decryptFromSync` primitive rather than rolling new crypto,
51
+ and USES `SecretStore.read()`/`set()` rather than re-implementing vault access. No higher-level
52
+ gate is duplicated.
53
+
54
+ ## 4. Signal vs authority compliance
55
+
56
+ - [x] No — this change has no block/allow surface.
57
+
58
+ The routes are read (status) and an explicit push lever; neither holds block authority over any
59
+ message or operation. The mesh acceptance layer (the existing smart authority) owns
60
+ accept/reject for `secret-share`.
61
+
62
+ ## 5. Interactions
63
+
64
+ - **Shadowing:** none. The two new routes are new paths (`/secrets/sync-status`,
65
+ `/secrets/sync-now`) that don't sit before/after any existing check.
66
+ - **Double-fire:** the inbound `secret-share` handler is idempotent at the vault level — a
67
+ re-delivered share just re-writes the same decrypted value (rotate=overwrite, per spec).
68
+ Boot best-effort push + the deterministic route can both push the same set; the receiver
69
+ storing the same value twice is harmless.
70
+ - **Races:** `SecretStore.read`/`set` is read-modify-write to one encrypted file via an atomic
71
+ temp-file rename. Concurrent shares writing different key-paths could interleave a read with a
72
+ write; v1 syncs the whole set on provision and overwrites, so a lost interleaved write is
73
+ re-converged by the next push. Flagged as a known v1 limitation, not a correctness break for
74
+ the single-writer-at-a-time provision pattern.
75
+ - **Feedback loops:** none. A received share does not itself trigger a re-push (no boot/provision
76
+ event fires on inbound store), so shares don't ping-pong between machines.
77
+
78
+ ## 6. External surfaces
79
+
80
+ - **Other agents on the same machine:** none — keyed to this agent's own mesh + vault.
81
+ - **Install base:** ships DARK; a normal agent and a single-machine agent are no-ops.
82
+ - **External systems:** none new. Uses the existing mesh transport between the user's own paired
83
+ machines; no third-party service involved.
84
+ - **Persistent state:** writes decrypted secrets into the RECEIVING machine's existing encrypted
85
+ vault (`config.secrets.enc`) — the same store Secret Drop / SecretMigrator already write. No
86
+ new on-disk plaintext; the wire payload is forward-secret encrypted.
87
+ - **Timing:** boot best-effort push is fire-and-forget and never blocks startup.
88
+
89
+ ## 7. Rollback cost
90
+
91
+ Pure code change behind a dark flag — revert and ship a patch; no user-visible regression during
92
+ the rollback window (the feature is off for everyone except the dev agent). The only persistent
93
+ side effect is that secrets already pushed to a peer remain in that peer's vault after rollback —
94
+ which is the intended end-state (the user wanted them there) and requires no cleanup. No schema
95
+ or migration to unwind.
96
+
97
+ ## Conclusion
98
+
99
+ The review surfaced one honest v1 limitation (whole-set overwrite means an interleaved partial
100
+ write is re-converged on the next push rather than merged) which is acceptable for the
101
+ push-on-provision model and is documented. No design changes were required. Crypto is reused, the
102
+ transport gate is reused, the feature ships dark, and rollback is a clean revert. Clear to ship
103
+ through the ceremony, with live-verification on the real laptop+mini pair as the final gate
104
+ before enabling it beyond the dev agent.
105
+
106
+ ## Evidence pointers
107
+
108
+ - 15 tests green: `tests/unit/secret-sync.test.ts` (8), `tests/integration/secret-sync-routes.test.ts`
109
+ (4, real crypto round-trip through HTTP + no-value-leak asserts), `tests/e2e/secret-sync-alive.test.ts`
110
+ (3, real AgentServer alive + round-trip into a peer vault + auth).
111
+ - `tsc --noEmit` clean; `npm run lint` clean.
112
+ - Spec: `docs/specs/cross-machine-secret-sync-spec.md` (approved).
@@ -0,0 +1,45 @@
1
+ # Side-Effects Review — pre-push gate diffs against the main ref, not @{u}
2
+
3
+ **Version / slug:** `prepush-gate-diff-base-main-ref`
4
+ **Date:** `2026-06-04`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (build-gate diff base; safe-by-construction)`
7
+
8
+ ## Summary
9
+
10
+ `scripts/pre-push-gate.js` computed `changedFiles` via `git diff --name-only ${remoteBranch}...HEAD`
11
+ where `remoteBranch = @{u}` (the branch's OWN upstream). That breaks when a PR is updated by
12
+ MERGING main in (the no-force-push path used to resolve conflicts): `@{u}...HEAD` then includes
13
+ ALL of main's already-shipped changes, so the gate's section-3/3b checks see 173+ unrelated `src/`
14
+ files → false "src changed without a release-note fragment" errors, forcing `INSTAR_PRE_PUSH_SKIP=1`
15
+ (hit live on #663). The fix computes the diff against the PR's MERGE TARGET — the first resolvable
16
+ of `JKHeadley/main`/`origin/main`/`upstream/main`/`main` — falling back to the old `@{u}` behaviour
17
+ only when no main ref resolves.
18
+
19
+ ## 1. Over-block (what it still flags)
20
+
21
+ Unchanged for the normal incremental-push case: `main...HEAD` (three-dot, from the merge-base =
22
+ the branch point) == the PR's commits == what `@{u}...HEAD` gave for a never-merged-main branch.
23
+ The src→tests, src→fragment (#23), and internal-only (§3c) checks all still fire on the PR's real
24
+ `src/` changes. The "chore: release" commit (upgrades/ + version, no `src/`) still doesn't trip
25
+ section-3b, same as before.
26
+
27
+ ## 2. Under-block (what it now lets through)
28
+
29
+ Nothing it shouldn't. A three-dot diff against main can NEVER under-report the PR's own changes
30
+ (the merge-base of main and HEAD is the branch point, so all the PR's commits are in the diff). The
31
+ only direction it can err is OVER-reporting (if a branch is based off another branch, not main) —
32
+ the safe direction (extra false-positives, never a missed src-change-without-fragment). The fix
33
+ specifically REMOVES the merge-from-main false-positive without weakening any check.
34
+
35
+ ## 3. Blast radius
36
+
37
+ One file: `scripts/pre-push-gate.js` (the `changedFiles` computation feeding sections 3/3b/3c) +
38
+ its unit test. No `src/`, no runtime, no agent surface. `pickRef` is a local helper; on any error
39
+ it falls through to the prior `@{u}` logic, so a clone without a `main` remote behaves exactly as
40
+ before.
41
+
42
+ ## 4. Reversibility
43
+
44
+ Fully reversible: revert the one hunk. No state. Verified: `node --check` clean; 16 pre-push-gate
45
+ unit tests pass.