instar 1.3.560 → 1.3.562

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-14T09:02:12.574Z",
5
- "instarVersion": "1.3.560",
4
+ "generatedAt": "2026-06-14T11:06:11.902Z",
5
+ "instarVersion": "1.3.562",
6
6
  "entryCount": 201,
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
14
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
23
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
32
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
41
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
50
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
59
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
68
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
77
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
86
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
95
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
104
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
113
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
122
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
131
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
140
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
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": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
149
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
150
150
  "since": "2025-01-01"
151
151
  },
152
152
  "job:health-check": {
@@ -1554,7 +1554,7 @@
1554
1554
  "type": "subsystem",
1555
1555
  "domain": "updates",
1556
1556
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1557
- "contentHash": "aeb4daa33c893c34809e18e462677e357018f6ca71faae1c5c95ab4290388b56",
1557
+ "contentHash": "e0ddbc39521447ae1bfecddfc98b2bd579400889d5fac37cf7df7d380e6a2fb7",
1558
1558
  "since": "2025-01-01"
1559
1559
  },
1560
1560
  "subsystem:scheduler": {
@@ -0,0 +1,31 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ **This release is the feedback-factory sender repoint** (docs/specs/feedback-factory-migration.md §2.5 Phase 4): the fleet's canonical feedback endpoint moves from Portal's receiver (`dawn.bot-me.ai/api/instar/feedback`) to the Instar operated instance's canonical front (`feedback.dawn-tunnel.dev/api/feedback`) — a live, verified Vercel receiver whose DNS zone is operator-controlled. (`feedback.instar.sh` is the intended long-term name; its DNS was not reachable at repoint time, so the operated endpoint went live on `feedback.dawn-tunnel.dev` first. A later re-point to instar.sh, if that becomes serviceable, is a one-line constant change + an idempotent migration.)
9
+
10
+ - **Single-source constant.** `src/core/canonicalFeedback.ts` now defines `CANONICAL_FEEDBACK_URL` + `LEGACY_FEEDBACK_URLS`; the Config loader default and both init shapes consume it (the literal URL can never drift across call sites again — pinned by test).
11
+ - **Migration Parity (the actual fleet repoint).** An idempotent `PostUpdateMigrator.migrateConfig` block rewrites a deployed agent's `feedback.webhookUrl` to the canonical front **only when it exactly equals a known legacy canonical default**. A custom operator webhook URL is structurally untouched (exact-match allowlist). Variant spellings that miss the match keep working through the old receiver's 301/proxy-forward (spec Phase 5) — the long tail loses nothing.
12
+ - **Unchanged:** the HMAC signing model and shared secret (same key through cutover, spec §2.9), the sender code itself, and `dispatches.dispatchUrl` (the dispatch move is sequenced separately).
13
+
14
+ ## What to Tell Your User
15
+
16
+ - "The address I send Instar bug reports and feedback to has moved to its new home (run by the Instar maintainer). This happened automatically with this update — nothing for you to do, and no reports were lost: the old address keeps forwarding while the fleet rolls over."
17
+ - "If you ever configured a CUSTOM feedback webhook of your own, it was not touched."
18
+
19
+ ## Summary of New Capabilities
20
+
21
+ | Capability | How to Use |
22
+ |-----------|-----------|
23
+ | Canonical feedback endpoint (stable) | Automatic — `feedback.webhookUrl` repoints on update; new installs get it via `init` |
24
+ | Single-source endpoint constant | `src/core/canonicalFeedback.ts` (`CANONICAL_FEEDBACK_URL`) |
25
+
26
+ ## Evidence
27
+
28
+ - `tests/unit/PostUpdateMigrator-feedbackUrlRepoint.test.ts`: both sides of the rewrite decision boundary (legacy URL repointed / custom URL untouched), idempotency (second run = no change), no-invention on absent config, legacy-list regression pin, and the canonical URL passing the sender's own `validateWebhookUrl` gate.
29
+ - `tests/unit/feedback-webhook.test.ts` updated: Config loader resolves through the constant; the legacy literal is banned from the loader source.
30
+ - Full unit suite green; side-effects artifact `upgrades/side-effects/feedback-sender-repoint.md` with independent second-pass review.
31
+ - Live pre-merge gate (operational): a signed HMAC round-trip against `https://feedback.dawn-tunnel.dev/api/feedback` was verified green before this repoint — `200 {received:true}` with the report landing durably in the operated instance's Blob inbox marked `verified:true`.
@@ -0,0 +1,46 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The boot helpers that auto-create the Slack "Updates" and "Attention" channels
9
+ (`ensureSlackUpdatesChannel` / `ensureSlackAttentionChannel` in
10
+ `src/commands/server.ts`) passed a raw, workspace-derived name straight into
11
+ `SlackAdapter.createChannel`. When the workspace name contained spaces or
12
+ uppercase (e.g. "SageMind Live Test"), that produced an invalid Slack channel
13
+ name like `SageMind Live Test-sys-updates`, which `createChannel` rejects via
14
+ `validateChannelName` — so the channel never got created and the boot logged
15
+ `Failed to create Slack Updates channel: Invalid channel name`.
16
+
17
+ Both callers now slugify the name first through a new shared
18
+ `slugifyChannelName` helper in `src/messaging/slack/sanitize.ts` (lowercase,
19
+ collapse non-`[a-z0-9]` runs to a single hyphen, trim edge hyphens, clamp to
20
+ Slack's 80-char limit) — mirroring the per-session channel slug logic the
21
+ adapter already used on its `-sess-` path. The `createChannel` /
22
+ `validateChannelName` contract other callers rely on is untouched.
23
+
24
+ ## What to Tell Your User
25
+
26
+ If your Slack workspace name has spaces or capital letters and your agent failed
27
+ to create its Updates or Attention channel (an "Invalid channel name" error on
28
+ startup), that's now fixed — the channel name is cleaned into a valid Slack
29
+ slug before creation. Workspaces whose name was already lowercase-and-dashes see
30
+ no change at all.
31
+
32
+ ## Summary of New Capabilities
33
+
34
+ - New `slugifyChannelName(name)` helper in the Slack sanitize module — a single
35
+ source of truth for turning an arbitrary name into a valid Slack channel name.
36
+ - The Slack Updates and Attention boot channels now create reliably regardless
37
+ of workspace-name casing or spaces.
38
+
39
+ ## Evidence
40
+
41
+ - `tests/unit/slack-channel-slug.test.ts` — the exact failing name
42
+ ("SageMind Live Test-sys-updates") now slugifies to a name `validateChannelName`
43
+ accepts; covers lowercasing, space-collapse, punctuation stripping, edge-hyphen
44
+ trim, already-valid passthrough, 80-char clamp, and a regression assertion that
45
+ the raw un-slugified name is rejected.
46
+ - `npx tsc --noEmit` clean; 9/9 new unit tests green.
@@ -0,0 +1,16 @@
1
+ # Why the Slack Updates channel failed to create (and now doesn't)
2
+
3
+ ## The one-sentence version
4
+ When your Slack workspace had a space or a capital letter in its name (like "SageMind Live Test"), the agent tried to make a Slack channel literally named "SageMind Live Test-sys-updates" — but Slack only allows lowercase, no-spaces channel names, so the creation crashed every time. Now the name is cleaned up first.
5
+
6
+ ## Picture it
7
+ Imagine a mailroom that will only accept package labels written in lowercase with dashes instead of spaces. The agent was handing it a label that said "SageMind Live Test-sys-updates" — capital letters, spaces and all — and the mailroom kept rejecting it. The fix is a tiny label-printer that rewrites the label as "sagemind-live-test-sys-updates" before handing it over.
8
+
9
+ ## What changed, precisely
10
+ - The two callers that auto-create the Slack "Updates" and "Attention" channels were passing a raw, workspace-derived name straight into channel creation.
11
+ - That raw name kept its spaces and capitals, which Slack rejects — so the channel never got made and you saw "Invalid channel name".
12
+ - Now both callers run the name through a small slugifier first (lowercase it, turn anything that isn't a-z/0-9 into a single dash, trim stray dashes, cap at Slack's 80-char limit) — exactly the same cleanup the per-session Slack channels already used.
13
+
14
+ ## Why this is safe
15
+ - It only changes how the name is *built* before creation; it does not touch the channel-creation rule that other code relies on (that rule still rejects bad names — it just never sees one now).
16
+ - A name that was already valid passes through unchanged.
@@ -0,0 +1,61 @@
1
+ # Side-Effects Review — Canonical feedback URL repoint (Phase-4 cutover flip)
2
+
3
+ **Version / slug:** `feedback-sender-repoint`
4
+ **Date:** `2026-06-11`
5
+ **Author:** `Echo (instar-dev agent)`
6
+ **Second-pass reviewer:** `required (fleet-wide sender repoint — the one-way door) — see appended response`
7
+
8
+ ## Summary of the change
9
+
10
+ The migration spec's Phase-4 sender repoint (docs/specs/feedback-factory-migration.md §2.5): **merging this PR repoints the entire fleet's feedback sender** to the Echo-operated canonical front, an operator-authorized fleet-wide change. Introduces `src/core/canonicalFeedback.ts` (the single source for the fleet's canonical feedback endpoint: `CANONICAL_FEEDBACK_URL = https://feedback.dawn-tunnel.dev/api/feedback` — the live operated receiver, its DNS zone operator-controlled; `feedback.instar.sh` is the intended long-term name, not DNS-reachable at repoint time — plus the `LEGACY_FEEDBACK_URLS` rewrite allowlist), repoints the three in-code default sites (`src/core/Config.ts` loader default, `src/commands/init.ts` ×2 new-install shapes), and adds the **Migration Parity** arm: an idempotent `PostUpdateMigrator.migrateConfig` block that rewrites a deployed agent's `feedback.webhookUrl` to the canonical front **only when it exactly equals a known legacy canonical default** — an operator's custom URL is structurally untouchable. `dispatches.dispatchUrl` is deliberately NOT flipped (spec sequences the dispatch move separately; the old receiver's Phase-5 proxy-forward covers continuity). Tests: new `PostUpdateMigrator-feedbackUrlRepoint.test.ts` (both sides of the rewrite boundary, idempotency, no-invention, regression pins, sender-validation gate) and the updated `feedback-webhook.test.ts` (single-source + legacy-literal-banned pins).
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `migrateConfig` webhookUrl rewrite — **add** — a string-equality membership check against `LEGACY_FEEDBACK_URLS`. Deliberately brittle-and-cheap by design: exact-match-only is the conservative direction (a non-match means NO action), and it holds no blocking authority — it rewrites a default, never gates a flow.
15
+ - Sender POST target (`FeedbackManager`) — **pass-through** — unchanged code; its destination value changes at config level. `validateWebhookUrl` (https + non-internal) passes the new URL (pinned by test).
16
+
17
+ ---
18
+
19
+ ## 1. Over-block
20
+
21
+ No block/allow surface — over-block not applicable. The closest analogue: the rewrite could "over-fire" on an operator who deliberately pointed at Dawn's legacy URL as a *custom* choice — indistinguishable from the shipped default by construction. Post-cutover that URL is a 301/proxy-forward to the canonical front (spec Phase 5), so even that case lands at the same place. No issue identified.
22
+
23
+ ## 2. Under-block
24
+
25
+ The rewrite "under-fires" for an agent whose config carries a variant spelling (trailing slash, http://, different casing) — exact-match misses it. Those agents keep posting to the old URL, which is exactly what the Phase-5 proxy-forward exists for: they keep landing on the canonical front via the forward, losing nothing. The long tail is covered structurally, not by widening the match (widening would risk touching custom URLs — the wrong trade).
26
+
27
+ ## 3. Level-of-abstraction fit
28
+
29
+ The constant lives at the core layer (one definition, three consumers + the migrator — no string drift possible again); the repoint of deployed agents lives in the migration layer (`PostUpdateMigrator`), which is the system's designated mechanism for exactly this (Migration Parity standard names this very case: "the sender's canonical feedback URL must flip for EXISTING agents via PostUpdateMigrator"). No layer inversion.
30
+
31
+ ## 4. Signal vs authority compliance
32
+
33
+ Compliant — the change adds no detector and no authority. The migration is a one-shot data rewrite with an exact-match guard whose failure mode is "do nothing" (deny-safe in the conservative direction). Reference: docs/signal-vs-authority.md.
34
+
35
+ ## 5. Interactions
36
+
37
+ - Composes with the receiver-persistence PR (the canonical front + inbox + drainer must be live and verified BEFORE this merges — preflight-gated in the cutover runbook/windows, not by code coupling; this PR is inert until published + agents update).
38
+ - The migrator block runs inside `migrateConfig` after the PIN block; it touches only `feedback.webhookUrl` and cannot race the ConfigDefaults registry (which only ADDS missing fields, never rewrites existing values — the reason a dedicated block is required at all).
39
+ - `QuotaTracker` (`dawn.bot-me.ai/api/instar/quota`) and `paritySubmitClient`/`integrityPassRunner` (parity tooling) deliberately keep their own URLs — different services, out of Phase-4 scope.
40
+ - The CLAUDE.md "API Authentication" prose in agent templates mentions the old webhook host; the canonical front uses the SAME auth model (User-Agent/X-Instar-Version + HMAC), so the prose stays accurate in mechanism; the host mention is updated by the template's normal regeneration path, not load-bearing.
41
+
42
+ ## 6. External surfaces
43
+
44
+ This is the maximal external surface: every deployed agent's feedback sender repoints on its next update. Mitigations are the spec's own: (a) the merge is held to Dawn's freeze window (PR title carries `[HOLD: merge = cutover flip]`); (b) the flip is gradual by nature — agents repoint as they update; the old receiver's Phase-5 proxy-forward catches every not-yet-updated sender; (c) the new URL must pass a live signed HMAC round-trip BEFORE the window opens (preflight gate); (d) the shared `INSTAR_WEBHOOK_SECRET` is unchanged through cutover (spec §2.9), so signed reports verify identically on both receivers.
45
+
46
+ ## 7. Rollback cost
47
+
48
+ The spec's own rollback path (Part-3 §5): re-pointing BACK is the same mechanism in reverse — a follow-up release moves `CANONICAL_FEEDBACK_URL` back and the legacy list gains the new URL; deployed agents re-migrate on update. During any gap, Dawn's old receiver is still warm (Phase 5 keeps it as proxy-forward, not dark), so no report is lost in either direction. No data migration, no schema, no state created at merge time beyond config rewrites that are themselves reversible.
49
+
50
+ ---
51
+
52
+ ## Second-pass review response (independent reviewer subagent, 2026-06-11)
53
+
54
+ Concur with the review.
55
+
56
+ 1. **The rewrite is genuinely conservative.** `PostUpdateMigrator.ts` gates the rewrite on an exact-string membership check against the one-entry allowlist (`canonicalFeedback.ts`); a custom/variant URL falls through to no action, absent `feedback`/`webhookUrl` invents nothing (ConfigDefaults has no `feedback.webhookUrl` entry — only the unrelated `feedbackPostDelayMs` — so there is no second path that could write a URL), and the write is atomic with a `.bak` backup. Idempotency holds by construction (the canonical URL is pinned out of the legacy list by test).
57
+ 2. **No missed in-code default site.** `git grep` over `src/` returns only `paritySubmitClient.ts` (a DIFFERENT endpoint — `/api/instar/feedback-factory/parity-submit`) plus the legacy-list entry; the remaining host mentions (init dispatchUrl ×2, integrityPassRunner, QuotaTracker comment, a grounding-gate doc example) are the deliberate out-of-scope set §5 names. No agent-installed template surface carries the URL.
58
+ 3. **Inert before merge, real rollback.** The diff is pure source + tests + docs — nothing executes from an unmerged branch; the repoint only reaches agents via a published release + their next migration run. The rollback claim matches the spec verbatim (Phase-4 repoint "itself reversible (re-migrate to old URL)"). All 9 tests in the two test files pass, covering both sides of the decision boundary, idempotency, and the `validateWebhookUrl` gate.
59
+ 4. **Artifact and fragment honesty.** The seven sections match the code; the fragment publishes only at merge (the cutover itself), so it announces nothing as live early. One non-blocking nit: §5 attributed the stale old-host prose to "agent templates" — it actually lives in the repo's own `CLAUDE.md`; substance correct.
60
+
61
+ **Resolution (author, same session):** the nit was fixed in this PR — the repo `CLAUDE.md` webhook line now names the canonical front + the constant module. Iterated and closed.
@@ -0,0 +1,46 @@
1
+ # Side-Effects Review — Slack Updates/Attention channel name slugify
2
+
3
+ ## Change summary
4
+ Caller-side fix in `src/commands/server.ts`: the `ensureSlackUpdatesChannel` and
5
+ `ensureSlackAttentionChannel` boot helpers now slugify the workspace-derived
6
+ channel name before calling `SlackAdapter.createChannel`, via a new shared
7
+ `slugifyChannelName` helper in `src/messaging/slack/sanitize.ts`. Mirrors the
8
+ existing per-session channel slug logic in `SlackAdapter` (`-sess-` path).
9
+
10
+ ## Tier
11
+ Tier 1 — small, low-risk, single-machine Slack-adapter boot-path bugfix. No
12
+ converged spec required.
13
+
14
+ ## Files touched
15
+ - `src/messaging/slack/sanitize.ts` — adds exported `slugifyChannelName(name)`.
16
+ - `src/commands/server.ts` — imports the helper; wraps both `-sys-updates` and
17
+ `-sys-attention` channel names with it before `createChannel`.
18
+ - `tests/unit/slack-channel-slug.test.ts` — new focused unit test.
19
+
20
+ ## Behavioral side-effects
21
+ - **Channel names on FRESH creation**: a workspace name containing spaces or
22
+ uppercase now yields a slugified channel (e.g. "SageMind Live Test" →
23
+ `sagemind-live-test-sys-updates`) instead of a hard failure. For workspaces
24
+ whose name was already slug-clean (lowercase, no spaces), the produced name is
25
+ byte-identical to before — no change.
26
+ - **No change to `createChannel` / `validateChannelName`**: the validate-and-throw
27
+ behavior other callers depend on is untouched; the fix only ensures these two
28
+ callers never hand it an invalid name.
29
+ - **Idempotent at the state layer**: both helpers early-return when their
30
+ `slack-*-channel` state key is already set, so this only affects the one-time
31
+ creation path; existing installs that already created a channel are unaffected.
32
+
33
+ ## Migration parity
34
+ - No agent-installed file changed (no `.claude/settings.json` hooks, no
35
+ `.instar/config.json` defaults, no CLAUDE.md template, no hook scripts, no
36
+ built-in skills). This is server-side runtime code shipped in the normal
37
+ build — existing agents receive it on their next update with no migration.
38
+
39
+ ## Rollback
40
+ - Revert the squash commit. The change is self-contained (one helper + two call
41
+ sites + one test); no data migration, no state schema change, nothing to undo.
42
+
43
+ ## Blast radius
44
+ - Limited to the Slack adapter boot path. Telegram / WhatsApp / iMessage and all
45
+ non-Slack code paths are untouched. Dark-gate config line-map unchanged (no
46
+ ConfigDefaults edit).