instar 1.3.205 → 1.3.207

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 (34) hide show
  1. package/dist/commands/init.d.ts +12 -0
  2. package/dist/commands/init.d.ts.map +1 -1
  3. package/dist/commands/init.js +20 -2
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/commands/server.d.ts.map +1 -1
  6. package/dist/commands/server.js +10 -2
  7. package/dist/commands/server.js.map +1 -1
  8. package/dist/core/AutoUpdater.d.ts.map +1 -1
  9. package/dist/core/AutoUpdater.js +22 -5
  10. package/dist/core/AutoUpdater.js.map +1 -1
  11. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  12. package/dist/core/PostUpdateMigrator.js +15 -0
  13. package/dist/core/PostUpdateMigrator.js.map +1 -1
  14. package/dist/core/UpgradeGuideProcessor.d.ts.map +1 -1
  15. package/dist/core/UpgradeGuideProcessor.js +13 -3
  16. package/dist/core/UpgradeGuideProcessor.js.map +1 -1
  17. package/dist/core/UpgradeNotifyManager.d.ts.map +1 -1
  18. package/dist/core/UpgradeNotifyManager.js +49 -24
  19. package/dist/core/UpgradeNotifyManager.js.map +1 -1
  20. package/dist/core/upgradeAnnouncement.d.ts +66 -0
  21. package/dist/core/upgradeAnnouncement.d.ts.map +1 -0
  22. package/dist/core/upgradeAnnouncement.js +143 -0
  23. package/dist/core/upgradeAnnouncement.js.map +1 -0
  24. package/dist/scaffold/templates.d.ts.map +1 -1
  25. package/dist/scaffold/templates.js +1 -0
  26. package/dist/scaffold/templates.js.map +1 -1
  27. package/package.json +1 -1
  28. package/scripts/analyze-release.js +59 -1
  29. package/src/data/builtin-manifest.json +20 -20
  30. package/src/scaffold/templates.ts +1 -0
  31. package/upgrades/1.3.206.md +46 -0
  32. package/upgrades/1.3.207.md +47 -0
  33. package/upgrades/side-effects/gemini-scaffold-leak-fix.md +114 -0
  34. package/upgrades/side-effects/mature-update-announcements.md +149 -0
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-02T20:04:00.495Z",
5
- "instarVersion": "1.3.205",
4
+ "generatedAt": "2026-06-02T21:28:59.172Z",
5
+ "instarVersion": "1.3.207",
6
6
  "entryCount": 195,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -11,7 +11,7 @@
11
11
  "domain": "identity",
12
12
  "sourcePath": "src/core/PostUpdateMigrator.ts",
13
13
  "installedPath": ".instar/hooks/instar/session-start.sh",
14
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
14
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
15
15
  "since": "2025-01-01"
16
16
  },
17
17
  "hook:dangerous-command-guard": {
@@ -20,7 +20,7 @@
20
20
  "domain": "safety",
21
21
  "sourcePath": "src/core/PostUpdateMigrator.ts",
22
22
  "installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
23
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
23
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
24
24
  "since": "2025-01-01"
25
25
  },
26
26
  "hook:grounding-before-messaging": {
@@ -29,7 +29,7 @@
29
29
  "domain": "safety",
30
30
  "sourcePath": "src/core/PostUpdateMigrator.ts",
31
31
  "installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
32
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
32
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
33
33
  "since": "2025-01-01"
34
34
  },
35
35
  "hook:compaction-recovery": {
@@ -38,7 +38,7 @@
38
38
  "domain": "identity",
39
39
  "sourcePath": "src/core/PostUpdateMigrator.ts",
40
40
  "installedPath": ".instar/hooks/instar/compaction-recovery.sh",
41
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
41
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
42
42
  "since": "2025-01-01"
43
43
  },
44
44
  "hook:external-operation-gate": {
@@ -47,7 +47,7 @@
47
47
  "domain": "safety",
48
48
  "sourcePath": "src/core/PostUpdateMigrator.ts",
49
49
  "installedPath": ".instar/hooks/instar/external-operation-gate.js",
50
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
50
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
51
51
  "since": "2025-01-01"
52
52
  },
53
53
  "hook:deferral-detector": {
@@ -56,7 +56,7 @@
56
56
  "domain": "safety",
57
57
  "sourcePath": "src/core/PostUpdateMigrator.ts",
58
58
  "installedPath": ".instar/hooks/instar/deferral-detector.js",
59
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
59
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
60
60
  "since": "2025-01-01"
61
61
  },
62
62
  "hook:self-stop-guard": {
@@ -65,7 +65,7 @@
65
65
  "domain": "coherence",
66
66
  "sourcePath": "src/core/PostUpdateMigrator.ts",
67
67
  "installedPath": ".instar/hooks/instar/self-stop-guard.js",
68
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
68
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
69
69
  "since": "2025-01-01"
70
70
  },
71
71
  "hook:post-action-reflection": {
@@ -74,7 +74,7 @@
74
74
  "domain": "evolution",
75
75
  "sourcePath": "src/core/PostUpdateMigrator.ts",
76
76
  "installedPath": ".instar/hooks/instar/post-action-reflection.js",
77
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
77
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
78
78
  "since": "2025-01-01"
79
79
  },
80
80
  "hook:external-communication-guard": {
@@ -83,7 +83,7 @@
83
83
  "domain": "safety",
84
84
  "sourcePath": "src/core/PostUpdateMigrator.ts",
85
85
  "installedPath": ".instar/hooks/instar/external-communication-guard.js",
86
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
86
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
87
87
  "since": "2025-01-01"
88
88
  },
89
89
  "hook:scope-coherence-collector": {
@@ -92,7 +92,7 @@
92
92
  "domain": "coherence",
93
93
  "sourcePath": "src/core/PostUpdateMigrator.ts",
94
94
  "installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
95
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
95
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
96
96
  "since": "2025-01-01"
97
97
  },
98
98
  "hook:scope-coherence-checkpoint": {
@@ -101,7 +101,7 @@
101
101
  "domain": "coherence",
102
102
  "sourcePath": "src/core/PostUpdateMigrator.ts",
103
103
  "installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
104
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
104
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
105
105
  "since": "2025-01-01"
106
106
  },
107
107
  "hook:free-text-guard": {
@@ -110,7 +110,7 @@
110
110
  "domain": "safety",
111
111
  "sourcePath": "src/core/PostUpdateMigrator.ts",
112
112
  "installedPath": ".instar/hooks/instar/free-text-guard.sh",
113
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
113
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
114
114
  "since": "2025-01-01"
115
115
  },
116
116
  "hook:claim-intercept": {
@@ -119,7 +119,7 @@
119
119
  "domain": "coherence",
120
120
  "sourcePath": "src/core/PostUpdateMigrator.ts",
121
121
  "installedPath": ".instar/hooks/instar/claim-intercept.js",
122
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
122
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
123
123
  "since": "2025-01-01"
124
124
  },
125
125
  "hook:claim-intercept-response": {
@@ -128,7 +128,7 @@
128
128
  "domain": "coherence",
129
129
  "sourcePath": "src/core/PostUpdateMigrator.ts",
130
130
  "installedPath": ".instar/hooks/instar/claim-intercept-response.js",
131
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
131
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
132
132
  "since": "2025-01-01"
133
133
  },
134
134
  "hook:stop-gate-router": {
@@ -137,7 +137,7 @@
137
137
  "domain": "safety",
138
138
  "sourcePath": "src/core/PostUpdateMigrator.ts",
139
139
  "installedPath": ".instar/hooks/instar/stop-gate-router.js",
140
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
140
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
141
141
  "since": "2025-01-01"
142
142
  },
143
143
  "hook:auto-approve-permissions": {
@@ -146,7 +146,7 @@
146
146
  "domain": "safety",
147
147
  "sourcePath": "src/core/PostUpdateMigrator.ts",
148
148
  "installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
149
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
149
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
150
150
  "since": "2025-01-01"
151
151
  },
152
152
  "job:health-check": {
@@ -1490,7 +1490,7 @@
1490
1490
  "type": "subsystem",
1491
1491
  "domain": "updates",
1492
1492
  "sourcePath": "src/core/AutoUpdater.ts",
1493
- "contentHash": "9a679f1b322237ea5022657900d1f07cd3c201cd458baa89090c696042b6c1d3",
1493
+ "contentHash": "60802cc5aad744cad139c5f5c0b1e4b27468c0a27b38384804ed09a6aa4e081c",
1494
1494
  "since": "2025-01-01"
1495
1495
  },
1496
1496
  "subsystem:auto-dispatcher": {
@@ -1506,7 +1506,7 @@
1506
1506
  "type": "subsystem",
1507
1507
  "domain": "updates",
1508
1508
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1509
- "contentHash": "90bfb6c540825ac2bf3393e22c4b7ae324159407acaac58b2c464762ef69901a",
1509
+ "contentHash": "797a5827842944d872077473dc0d87a1f99601f33d5f262e272748731d68250b",
1510
1510
  "since": "2025-01-01"
1511
1511
  },
1512
1512
  "subsystem:scheduler": {
@@ -466,6 +466,7 @@ This routes feedback to the Instar maintainers automatically. Valid types: \`bug
466
466
  - The endpoint resolves the Updates topic from state server-side; you cannot specify a topic and you should not try to.
467
467
  - If Updates is not configured, the endpoint returns 400 — do NOT fall back to sending in the active topic. Update-class messages belong in Updates or they don't go out at all.
468
468
  - **When to use** (PROACTIVE — this is the trigger): the moment I am about to author a conversational message whose subject is *me* shipping, updating, or restarting — including post-restart "I'm back" confirmations — I use this endpoint. Authoring such a message via the standard Telegram reply path puts release chatter into whatever conversation the user was last in, which is the bug this routing closes.
469
+ - **Maturity honesty (silent-by-default user announcements)**: user-facing update announcements are *opt-in and maturity-tagged*, authored in the release's upgrade guide (\`user_announcement\` front-matter: each change is \`audience: user|agent-only\` + \`maturity: experimental|preview|stable\`). The post-update notifier stays SILENT unless a change was explicitly promoted to \`audience: user\`, and experimental/preview features are announced as such (⚗️ Experimental / 🧪 Preview) — never implied to be finished. When I narrate my own ship here, I mirror that honesty: I do NOT announce a feature that ships dark/disabled as if it works, and I don't dress up an infra change as a finished capability. Patch-level "restarting…" notices are suppressed (only deferral warnings — "your work is holding a restart" — still surface).
469
470
 
470
471
  **Secret Drop** — Securely collect secrets (API keys, passwords, tokens) from users without exposing them in chat history.
471
472
  - Request a secret: \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/secrets/request -H 'Content-Type: application/json' -d '{"label":"OpenAI API Key","description":"Needed for GPT integration","topicId":TOPIC_ID}'\`
@@ -0,0 +1,46 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ `refreshHooksAndSettings()` (and the sibling resolver in init) read the persisted
9
+ `enabledFrameworks` from config.json through a hardcoded filter
10
+ `f === 'claude-code' || f === 'codex-cli'` that silently DROPPED `gemini-cli`. For a
11
+ gemini-only agent (`enabledFrameworks: ['gemini-cli']`) the filtered list came back
12
+ empty, so the code fell through to its `['claude-code']` default, `claudeEnabled`
13
+ became true, and `installClaudeSettings()` wrote a full Claude `.claude/settings.json`
14
+ into an agent that does not run Claude Code. Both filter sites now validate through a
15
+ single canonical `isKnownFramework` guard (backed by a `KNOWN_FRAMEWORKS` list kept in
16
+ sync with `IntelligenceFramework`), so no installed framework is dropped and a new one
17
+ cannot silently regress this again. New gemini-only and codex-only installs no longer
18
+ get a stray Claude settings file; claude-code installs are unchanged.
19
+
20
+ ## What to Tell Your User
21
+
22
+ - **Cleaner non-Claude installs**: "If you set me up as a Gemini-only or Codex-only
23
+ agent, I was accidentally dropping a Claude configuration file into your project even
24
+ though I don't use Claude there. That's fixed — a Gemini agent now stays a Gemini
25
+ agent, with no stray Claude settings."
26
+
27
+ ## Summary of New Capabilities
28
+
29
+ | Capability | How to Use |
30
+ |-----------|-----------|
31
+ | Framework-correct scaffolding | Automatic (gemini/codex-only installs skip Claude settings) |
32
+
33
+ ## Evidence
34
+
35
+ - **Live before:** the gemini agent installed during dogfooding
36
+ (`~/.instar/agents/gemini`, `enabledFrameworks: ['gemini-cli']`) contained a
37
+ 7559-byte `.claude/settings.json` plus `.claude/skills`/`.claude/scripts` — Claude
38
+ hook config it can never use. Confirmed by direct inspection of the agent home.
39
+ - **After (code path):** a behavioral test drives `refreshHooksAndSettings()` against a
40
+ temp project with `enabledFrameworks: ['gemini-cli']` and asserts no
41
+ `.claude/settings.json` is written; `['codex-cli']` likewise; `['claude-code']` and
42
+ `['claude-code','gemini-cli']` still write it (no regression). A fresh gemini-only
43
+ install therefore no longer leaks the file.
44
+ - **Residue note:** agents installed BEFORE this fix keep their already-written stray
45
+ `.claude/settings.json` (the fix stops re-writing it but does not delete the residue);
46
+ cleaning that inert leftover is a separate follow-up.
@@ -0,0 +1,47 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ User-facing update announcements are now **opt-in and maturity-tagged**. A new
9
+ pure helper (`src/core/upgradeAnnouncement.ts`) parses a `user_announcement`
10
+ front-matter block in the release upgrade guide — each notable change carries an
11
+ `audience` (`user` or `agent-only`) and a `maturity` (`experimental` / `preview`
12
+ / `stable`).
13
+
14
+ - **UpgradeNotifyManager** is now silent-by-default: with no `audience: user`
15
+ entry it skips the user message entirely (still updating MEMORY.md and
16
+ acknowledging), and with entries it composes only from them using honest
17
+ maturity framing + badges (⚗️ Experimental / 🧪 Preview). The old "lead with
18
+ the biggest user-visible feature" instruction is gone.
19
+ - **UpgradeGuideProcessor** hoists and merges each guide's `user_announcement`
20
+ block to the top of the concatenated pending guide, so the decision survives
21
+ multi-guide batches (a no-op when no guide carries a block).
22
+ - **AutoUpdater + the restart handshake** suppress the bare patch-level "Just
23
+ updated… restarting" narration while keeping the restart-hold warnings;
24
+ restart verification is preserved via an empty deferred notification.
25
+ - **analyze-release.js** scaffolds the block (defaulting every entry to
26
+ `agent-only`) on `--draft-guide`, and warns at authoring time when a
27
+ user-relevant release carries no block at all.
28
+ - Existing agents receive the maturity-honesty guidance through a
29
+ `PostUpdateMigrator` CLAUDE.md migration (new agents get it from the template).
30
+
31
+ Parent principle: **Near-Silent Notifications**. Spec:
32
+ `docs/specs/mature-update-announcements.md`.
33
+
34
+ ## What to Tell Your User
35
+
36
+ - **Quieter, more honest updates**: "I'll only message you about an update when
37
+ it's genuinely relevant and ready for you, and I'll be upfront when something
38
+ is still experimental instead of making it sound finished. You'll get fewer
39
+ pings and clearer ones."
40
+
41
+ ## Summary of New Capabilities
42
+
43
+ | Capability | How to Use |
44
+ |-----------|-----------|
45
+ | Maturity-tagged, opt-in update announcements | Authored in the release upgrade guide's `user_announcement` front-matter; the notifier stays silent unless a change is promoted to the user |
46
+ | Honest maturity framing | Experimental and preview features are labeled as such, never narrated as finished |
47
+ | Quieter restarts | Patch-level "restarting" notices are suppressed; restart-hold warnings still surface |
@@ -0,0 +1,114 @@
1
+ # Side-Effects Review — fix gemini/codex-only scaffold leak
2
+
3
+ **Version / slug:** `gemini-scaffold-leak-fix`
4
+ **Date:** `2026-06-02`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (Tier-1 surgical bug fix; the change is strictly more permissive)`
7
+
8
+ ## Summary of the change
9
+
10
+ `src/commands/init.ts`: replace two hardcoded `enabledFrameworks` filters
11
+ (`f === 'claude-code' || f === 'codex-cli'`) — which dropped `gemini-cli` and caused
12
+ gemini-only agents to fall through to the `['claude-code']` default and scaffold a
13
+ Claude `.claude/settings.json` — with a single canonical `isKnownFramework` guard
14
+ (+ exported `KNOWN_FRAMEWORKS`, kept in sync with `IntelligenceFramework`). Adds a
15
+ unit test proving gemini/codex-only installs skip Claude settings while claude-code
16
+ installs are unchanged.
17
+
18
+ ## Decision-point inventory
19
+
20
+ - `refreshHooksAndSettings: claudeEnabled?` (init.ts:~3524) — **modify** — the input
21
+ (`enabledFrameworks` parsed from config) is now framework-complete; the gate logic is
22
+ unchanged.
23
+ - `initStandalone framework resolution` (init.ts:~3707) — **modify** — same filter fix.
24
+
25
+ ---
26
+
27
+ ## 1. Over-block
28
+
29
+ **What legitimate inputs does this change reject that it shouldn't?** None. The change
30
+ is strictly MORE permissive than before: the old filter kept `{claude-code, codex-cli}`;
31
+ the new guard keeps `{claude-code, codex-cli, gemini-cli}`. Nothing that previously
32
+ passed is now dropped. Garbage values (non-framework strings) are still dropped, as
33
+ before.
34
+
35
+ ---
36
+
37
+ ## 2. Under-block
38
+
39
+ **What failure modes does this still miss?** A future framework added to
40
+ `IntelligenceFramework` must also be added to `KNOWN_FRAMEWORKS` (they are co-located
41
+ with a doc comment to make the coupling obvious). It does NOT retroactively clean the
42
+ stray `.claude/settings.json` already written into agents installed before the fix —
43
+ that inert residue is a separate follow-up (a destructive cleanup migration deserving
44
+ its own careful gating).
45
+
46
+ ---
47
+
48
+ ## 3. Level-of-abstraction fit
49
+
50
+ Correct layer — a data-validation guard at the config-read boundary, replacing an
51
+ inline literal with a named, type-safe, single-source-of-truth predicate. It does not
52
+ add a gate or authority; it fixes the INPUT to an existing gate (`claudeEnabled`).
53
+
54
+ ---
55
+
56
+ ## 4. Signal vs authority compliance
57
+
58
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
59
+
60
+ - [x] No — this change has no block/allow surface. It corrects which frameworks survive
61
+ a config-parse filter; the downstream `claudeEnabled` gate already existed.
62
+
63
+ ---
64
+
65
+ ## 5. Interactions
66
+
67
+ - **Shadowing:** none — single in-function filter, no ordering with other checks.
68
+ - **Double-fire:** none.
69
+ - **Races:** none — pure synchronous config parse.
70
+ - **Feedback loops:** none.
71
+
72
+ The only behavioral change: for a gemini-only or codex-only config, `claudeEnabled` is
73
+ now correctly `false`, so `installClaudeSettings()` / `refreshClaudeMd()` are skipped.
74
+ For claude-code (alone or among multiple frameworks) behavior is identical.
75
+
76
+ ---
77
+
78
+ ## 6. External surfaces
79
+
80
+ - Persistent state: a NEW gemini/codex-only install no longer creates a stray
81
+ `projectDir/.claude/settings.json`. Existing agents: on their next update,
82
+ `refreshHooksAndSettings` stops re-writing the file for non-claude configs (the
83
+ pre-existing file is left in place — inert, see §2).
84
+ - Other agents / external systems: none.
85
+ - Timing: none.
86
+
87
+ ---
88
+
89
+ ## 7. Rollback cost
90
+
91
+ Pure code change — revert the two filter lines + the guard, ship a patch. No persistent
92
+ state created by this change to clean up (it REMOVES an unwanted write; it does not add
93
+ state). No user-visible regression during rollback.
94
+
95
+ ---
96
+
97
+ ## Conclusion
98
+
99
+ The review produced no design changes. The fix is a minimal, strictly-more-permissive
100
+ correction of a framework-blind filter (the same drift class as the Step-2 resolver
101
+ bugs), with a behavioral test that proves both sides of the boundary. Clear to ship as
102
+ a Tier-1 bug fix. One honest residual logged: the inert leftover file on
103
+ already-installed agents is a separate, carefully-gated cleanup follow-up.
104
+
105
+ ## Second-pass review (if required)
106
+
107
+ Not required (Tier-1, strictly-more-permissive). Discovered via live dogfooding (Codey's
108
+ gemini install) — the empirical "before" is itself an independent confirmation.
109
+
110
+ ## Evidence pointers
111
+
112
+ - `tests/unit/gemini-scaffold-leak.test.ts` — 5 tests, both sides of the boundary.
113
+ - Live before: `~/.instar/agents/gemini/.claude/settings.json` (7559 bytes) on a
114
+ `['gemini-cli']` config.
@@ -0,0 +1,149 @@
1
+ # Side-Effects Review — Maturity-aware, silent-by-default user update announcements
2
+
3
+ **Version / slug:** `mature-update-announcements`
4
+ **Date:** `2026-06-02`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `3 independent adversarial reviewers (design / correctness / integration) — internal convergence`
7
+
8
+ ## Summary of the change
9
+
10
+ Stops the post-update notifier from overselling unfinished features (the trigger:
11
+ infancy-stage Gemini CLI support narrated as "just got more reliable"). User-facing
12
+ update announcements become OPT-IN + maturity-tagged, authored in the release's
13
+ upgrade guide (`user_announcement` front-matter). Touches: `src/core/upgradeAnnouncement.ts`
14
+ (new pure helper), `src/core/UpgradeNotifyManager.ts` (silent-by-default compose),
15
+ `src/core/UpgradeGuideProcessor.ts` (hoist/merge blocks to byte 0), `src/core/AutoUpdater.ts`
16
+ + `src/commands/server.ts` (Fork 3: suppress patch-level restart narration, preserve
17
+ handshake verification), `scripts/analyze-release.js` (draft block + forgot-block advisory),
18
+ `src/scaffold/templates.ts` + `src/core/PostUpdateMigrator.ts` (agent-awareness guidance).
19
+ Decision points touched: the post-update *announce/skip* decision and the *restart-narrate/suppress*
20
+ decision.
21
+
22
+ ## Decision-point inventory
23
+
24
+ - `UpgradeNotifyManager.buildPrompt announce-vs-skip` — **modify** — was "always compose, lead with the biggest feature"; now composes only from `audience: user` entries, skips entirely when there are none.
25
+ - `AutoUpdater restart-narration` — **modify** — was "narrate on every active-session restart"; now suppresses the bare narration for patch-only bumps (deferral warnings unchanged).
26
+ - `analyze-release forgot-block advisory` — **add** — a non-blocking author-facing warning when a user-relevant release carries no announcement block.
27
+ - `UpgradeGuideProcessor block hoist` — **add** — assembles a merged front-matter block at byte 0 (no decision authority; pure data-flow plumbing).
28
+
29
+ ---
30
+
31
+ ## 1. Over-block
32
+
33
+ **What legitimate inputs does this change reject that it shouldn't?**
34
+
35
+ The "block" surface here is the announce/skip decision. Silent-by-default means a
36
+ *genuinely user-ready* feature is "over-blocked" (not announced) if the release author
37
+ forgets to add a `user_announcement` block. This is the one real over-block risk and was
38
+ raised by the design reviewer. Mitigations: (a) `analyze-release --draft-guide` scaffolds
39
+ the block for every feature/enhancement, so the author is structurally prompted to promote
40
+ the user-facing ones; (b) the main-path forgot-block advisory fires when a user-relevant
41
+ release has no block at all. The fail-safe direction is deliberate: silence (recoverable
42
+ with a follow-up note) is preferable to today's failure of a misleading announcement.
43
+
44
+ ## 2. Under-block
45
+
46
+ **What failure modes does this still miss?**
47
+
48
+ An author can still *mislabel* maturity — mark an experimental feature `stable, audience: user` —
49
+ and the system will compose a confident message. The forgot-block advisory only catches total
50
+ absence of the block, not a wrong maturity inside it. This is accepted: maturity is a human
51
+ judgment authored with the release notes (the Body-and-Mind "author decides" layer); we
52
+ deliberately did NOT add a brittle headline→rollout-stage map in CI to police it (it would be
53
+ fragile and is the wrong layer). The restart-suppression "under-block": a patch bump that is
54
+ secretly disruptive gets no narration — but the deferral warnings and the failed-restart
55
+ escalation still fire, so a genuinely stuck restart is still surfaced.
56
+
57
+ ## 3. Level-of-abstraction fit
58
+
59
+ **Is this at the right layer?**
60
+
61
+ Yes. The announce decision is authored at release time (in the upgrade guide), not improvised
62
+ by a throwaway notify session — that was the core design move. The notify-side helper
63
+ (`upgradeAnnouncement.ts`) is a pure renderer/parser (a low-level primitive). The forgot-block
64
+ guard lives in the release analyzer (the only layer with the "brand-new feature" signal and the
65
+ author's attention) — during convergence we *moved* the coherence check there and removed an
66
+ orphaned TS function that would have been a parallel implementation. The hoist lives in the
67
+ processor (the layer that already assembles the pending guide). No re-implementation of an
68
+ existing primitive; no gate running parallel to a smarter one.
69
+
70
+ ## 4. Signal vs authority compliance
71
+
72
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
73
+
74
+ **Does this change hold blocking authority with brittle logic?**
75
+
76
+ - [x] No — the brittle pieces are signals; the only authorities are deterministic, fully-enumerable policy.
77
+
78
+ The forgot-block advisory is a **signal** (a non-blocking `log()` line; the author decides). The
79
+ announce/skip decision is a deterministic policy over a fully-enumerable input ("are there
80
+ `audience: user` entries?") — not brittle pattern-matching. The restart-suppression decision is
81
+ deterministic over `crossesBreaking(prev, next)` (a pure semver observation that fails safe to
82
+ "narrate" on malformed input). No LLM-free brittle check holds blocking authority. All three
83
+ adversarial reviewers independently affirmed signal-vs-authority compliance.
84
+
85
+ ## 5. Interactions
86
+
87
+ - **Shadowing:** the announcement front-matter is hoisted to byte 0 *above* the existing
88
+ `# Instar Upgrade Guide` header and `<!-- bump: -->` marker. Verified the bump-marker regex,
89
+ the publish-gate validator (`validateGuideContent` uses `includes`, no first-line requirement),
90
+ `assemble-next-md.mjs`, and `check-upgrade-guide.js` all tolerate leading front-matter.
91
+ - **Double-fire:** the notify session's Step-1 send and the AutoUpdater restart narration are
92
+ distinct topics/paths; no overlap. The handshake is written once per version (existing dedup
93
+ guard unchanged).
94
+ - **Races:** none introduced — the processor assembly is single-pass synchronous; no shared
95
+ mutable state added.
96
+ - **Feedback loops:** none.
97
+
98
+ ## 6. External surfaces
99
+
100
+ - **Other agents:** the CLAUDE.md template + `migrateClaudeMd` change is the only agent-visible
101
+ surface; it adds guidance, removes nothing.
102
+ - **Users:** fewer/quieter update messages (the intended UX change). Patch-level "restarting…"
103
+ messages disappear; deferral warnings remain.
104
+ - **External systems (Telegram):** the post-update topic receives fewer messages; format of any
105
+ message that DOES send is unchanged except for the experimental/preview badges.
106
+ - **Persistent state:** none. No new files/columns/ledgers. The handshake file is written exactly
107
+ as before (only its `deferredNotification` may now be empty for patch bumps; the server skips
108
+ empty emits and still clears the file).
109
+ - **Timing:** none beyond the existing restart timing.
110
+
111
+ ## 7. Rollback cost
112
+
113
+ **Pure code change — revert the commit, ship as next patch.** No persistent state, no data
114
+ migration, no agent-state repair. The `migrateClaudeMd` addition is idempotent and additive
115
+ (reverting simply stops adding the section to new updates; already-patched CLAUDE.md files keep a
116
+ harmless guidance paragraph). No user-visible regression during the rollback window — worst case
117
+ reverts to the prior (louder, less honest) announcement behavior.
118
+
119
+ ## Conclusion
120
+
121
+ The review (three independent adversarial passes — design, correctness, integration) returned a
122
+ unanimous SHIP-WITH-MINOR-FIXES with no blockers. Three findings were acted on before commit:
123
+ (1) added the required `migrateClaudeMd` migration parity for the maturity-honesty guidance;
124
+ (2) added the author-facing forgot-block advisory to mitigate the silent-by-default over-block
125
+ risk; (3) removed the orphaned `announcementCoherenceWarnings` TS helper (un-wired dead code) and
126
+ relocated the coherence concern to the release analyzer where the signal actually exists — keeping
127
+ `upgradeAnnouncement.ts` focused on the notify path. A correctness reviewer's serialize↔parse
128
+ round-trip gap was closed with an explicit unit test. The change is clear to ship.
129
+
130
+ ---
131
+
132
+ ## Second-pass review (if required)
133
+
134
+ **Reviewer:** internal multi-reviewer convergence (design / correctness / integration)
135
+ **Independent read of the artifact: concur**
136
+
137
+ All three reviewers concurred the design is sound (signal-vs-authority + Body-and-Mind compliant,
138
+ correct level of abstraction) and the implementation is correct and alive end-to-end. The minor
139
+ fixes they raised are incorporated above; no residual concerns block the ship.
140
+
141
+ ---
142
+
143
+ ## Evidence pointers
144
+
145
+ - Affected-set test run: 11 files / 134 tests green (unit helper, compose branches, processor
146
+ hoist + no-op, analyze-release round-trip + forgot-block advisory, migration parity, AutoUpdater
147
+ Fork-3 patch-suppression + minor-narrates, e2e upgrade-guide lifecycle).
148
+ - Spec: `docs/specs/mature-update-announcements.md` (`review-convergence: internal-multi-reviewer-2026-06-02`, `approved: true`).
149
+ - ELI16: `docs/specs/mature-update-announcements.eli16.md`.