instar 1.3.448 → 1.3.450

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.
@@ -34,8 +34,24 @@ function emptyProfile(slackUserId, now) {
34
34
  urgentCount: 0,
35
35
  firstSeen: now,
36
36
  lastSeen: now,
37
+ buckets: [],
37
38
  };
38
39
  }
40
+ function emptyBucket(startMs) {
41
+ return {
42
+ startMs,
43
+ count: 0,
44
+ actionCounts: {},
45
+ tierCounts: [0, 0, 0, 0, 0],
46
+ hourCounts: new Array(24).fill(0),
47
+ lengthSum: 0,
48
+ lengthSqSum: 0,
49
+ urgentCount: 0,
50
+ };
51
+ }
52
+ export const DEFAULT_BUCKET_MS = 24 * 60 * 60 * 1000; // 1 day
53
+ export const DEFAULT_MAX_OBSERVATIONS_PER_WINDOW = 50;
54
+ export const DEFAULT_MAX_BUCKETS = 90;
39
55
  /** Validate a slackUserId for safe use as a filename key (prevents path traversal). */
40
56
  function isSafeKey(id) {
41
57
  return /^[A-Za-z0-9_-]{1,64}$/.test(id);
@@ -43,10 +59,24 @@ function isSafeKey(id) {
43
59
  export class RelationshipBehaviorStore {
44
60
  file;
45
61
  now;
46
- constructor(stateDir, now = () => new Date().toISOString()) {
62
+ bucketMs;
63
+ maxObservationsPerWindow;
64
+ maxBuckets;
65
+ onCapDrop;
66
+ constructor(stateDir, now = () => new Date().toISOString(), options = {}) {
47
67
  /* state-registry: slack-relationship-baselines */
48
68
  this.file = path.join(stateDir, 'slack-relationship-baselines.json');
49
69
  this.now = now;
70
+ // Nullish-coalescing (not ||) so a deliberate 0 disables the cap (per Dawn key-pattern).
71
+ this.bucketMs = options.bucketMs && options.bucketMs > 0 ? options.bucketMs : DEFAULT_BUCKET_MS;
72
+ this.maxObservationsPerWindow =
73
+ options.maxObservationsPerWindow ?? DEFAULT_MAX_OBSERVATIONS_PER_WINDOW;
74
+ this.maxBuckets = options.maxBuckets && options.maxBuckets > 0 ? options.maxBuckets : DEFAULT_MAX_BUCKETS;
75
+ this.onCapDrop = options.onCapDrop;
76
+ }
77
+ /** The bucket-window length (ms) this store records into — read by the scorer for decay. */
78
+ get bucketWindowMs() {
79
+ return this.bucketMs;
50
80
  }
51
81
  get path() {
52
82
  return this.file;
@@ -62,19 +92,49 @@ export class RelationshipBehaviorStore {
62
92
  try {
63
93
  const all = this.readAll();
64
94
  const now = this.now();
95
+ const nowMs = Date.parse(now);
65
96
  const prof = all[slackUserId] ?? emptyProfile(slackUserId, now);
97
+ // ── #3b: per-window observation-rate cap ──────────────────────────────────────
98
+ // Resolve the current bucket. If recording this observation would exceed the
99
+ // per-window cap, DROP it (log via onCapDrop) — the cumulative counts are NOT
100
+ // touched either, so the buckets-sum invariant holds and the cap actually bites.
101
+ const bucket = this.currentBucket(prof, nowMs);
102
+ if (this.maxObservationsPerWindow > 0 &&
103
+ bucket.count >= this.maxObservationsPerWindow) {
104
+ // Over the cap for this window — drop, don't record. lastSeen is intentionally
105
+ // NOT advanced for a dropped observation (a dropped obs is not "an interaction").
106
+ try {
107
+ this.onCapDrop?.(slackUserId, bucket.startMs, 1);
108
+ }
109
+ catch {
110
+ /* logging must never break the path */
111
+ }
112
+ all[slackUserId] = prof; // persist any bucket pruning done while resolving
113
+ this.writeAll(all);
114
+ return;
115
+ }
116
+ const tier = Math.max(0, Math.min(4, Math.floor(obs.tier)));
117
+ const hour = Math.max(0, Math.min(23, Math.floor(obs.hour)));
118
+ const len = Math.max(0, Math.floor(obs.length));
119
+ // Cumulative counts (backward-compat — old readers see the same numbers).
66
120
  prof.interactionCount += 1;
67
121
  prof.actionCounts[obs.action] = (prof.actionCounts[obs.action] ?? 0) + 1;
68
- const tier = Math.max(0, Math.min(4, Math.floor(obs.tier)));
69
122
  prof.tierCounts[tier] = (prof.tierCounts[tier] ?? 0) + 1;
70
- const hour = Math.max(0, Math.min(23, Math.floor(obs.hour)));
71
123
  prof.hourCounts[hour] = (prof.hourCounts[hour] ?? 0) + 1;
72
- const len = Math.max(0, Math.floor(obs.length));
73
124
  prof.lengthSum += len;
74
125
  prof.lengthSqSum += len * len;
75
126
  if (obs.urgent)
76
127
  prof.urgentCount += 1;
77
128
  prof.lastSeen = now;
129
+ // Time-bucketed counts (kept in lock-step with the cumulative totals).
130
+ bucket.count += 1;
131
+ bucket.actionCounts[obs.action] = (bucket.actionCounts[obs.action] ?? 0) + 1;
132
+ bucket.tierCounts[tier] = (bucket.tierCounts[tier] ?? 0) + 1;
133
+ bucket.hourCounts[hour] = (bucket.hourCounts[hour] ?? 0) + 1;
134
+ bucket.lengthSum += len;
135
+ bucket.lengthSqSum += len * len;
136
+ if (obs.urgent)
137
+ bucket.urgentCount += 1;
78
138
  all[slackUserId] = prof;
79
139
  this.writeAll(all);
80
140
  }
@@ -82,6 +142,30 @@ export class RelationshipBehaviorStore {
82
142
  // Observe-only baseline must NEVER break the message path.
83
143
  }
84
144
  }
145
+ /**
146
+ * Resolve (and lazily migrate) the bucket covering `nowMs`, pruning to `maxBuckets`.
147
+ * Backfills a missing `buckets` array on a pre-hardening profile WITHOUT moving its
148
+ * cumulative counts into a bucket (those counts predate bucketing and have unknown
149
+ * timestamps — they keep weight as the un-decayable "legacy" base; see the scorer's
150
+ * decay logic). New observations land in fresh, timestamped buckets.
151
+ */
152
+ currentBucket(prof, nowMs) {
153
+ if (!Array.isArray(prof.buckets))
154
+ prof.buckets = [];
155
+ const ms = Number.isFinite(nowMs) ? nowMs : Date.now();
156
+ const start = Math.floor(ms / this.bucketMs) * this.bucketMs;
157
+ let bucket = prof.buckets.find((b) => b.startMs === start);
158
+ if (!bucket) {
159
+ bucket = emptyBucket(start);
160
+ prof.buckets.push(bucket);
161
+ prof.buckets.sort((a, b) => a.startMs - b.startMs);
162
+ // Prune oldest buckets beyond the retention bound (file-growth guard).
163
+ if (prof.buckets.length > this.maxBuckets) {
164
+ prof.buckets.splice(0, prof.buckets.length - this.maxBuckets);
165
+ }
166
+ }
167
+ return bucket;
168
+ }
85
169
  /** The current baseline for a principal, or undefined if none recorded yet. */
86
170
  profileFor(slackUserId) {
87
171
  if (!slackUserId || !isSafeKey(slackUserId))
@@ -138,6 +222,111 @@ export function hourFraction(prof, hour) {
138
222
  const h = Math.max(0, Math.min(23, Math.floor(hour)));
139
223
  return (prof.hourCounts[h] ?? 0) / prof.interactionCount;
140
224
  }
225
+ /** Baseline calendar age in milliseconds (now − firstSeen), or 0 when unknown. */
226
+ export function baselineAgeMs(prof, nowMs) {
227
+ const first = Date.parse(prof.firstSeen);
228
+ if (!Number.isFinite(first) || !Number.isFinite(nowMs))
229
+ return 0;
230
+ return Math.max(0, nowMs - first);
231
+ }
232
+ /**
233
+ * Compute the decay-weighted effective baseline. The legacy base = cumulative totals
234
+ * MINUS the sum of all buckets (i.e. the part of history that predates bucketing). That
235
+ * base keeps full weight (weight 1.0); each bucket is weighted by 0.5^(ageWindows/halfLife).
236
+ *
237
+ * A profile with no buckets → its entire cumulative form is the legacy base at full
238
+ * weight → the decayed view equals the cumulative view (perfect backward-compat). A
239
+ * fully-bucketed profile decays purely on bucket age.
240
+ */
241
+ export function decayedView(prof, opts) {
242
+ const halfLife = opts.halfLifeWindows && opts.halfLifeWindows > 0 ? opts.halfLifeWindows : 30;
243
+ const bucketMs = opts.bucketMs && opts.bucketMs > 0 ? opts.bucketMs : DEFAULT_BUCKET_MS;
244
+ const buckets = Array.isArray(prof.buckets) ? prof.buckets : [];
245
+ const view = {
246
+ effectiveCount: 0,
247
+ actionCounts: {},
248
+ tierCounts: [0, 0, 0, 0, 0],
249
+ hourCounts: new Array(24).fill(0),
250
+ lengthSum: 0,
251
+ lengthSqSum: 0,
252
+ urgentCount: 0,
253
+ };
254
+ // ── Legacy (pre-bucketing) base: cumulative totals minus what the buckets hold ──
255
+ // Kept at full weight so old established behavior is never decayed away.
256
+ const bucketedCount = buckets.reduce((s, b) => s + b.count, 0);
257
+ const legacyCount = Math.max(0, prof.interactionCount - bucketedCount);
258
+ if (legacyCount > 0 && prof.interactionCount > 0) {
259
+ // Reconstruct the legacy base by subtracting bucket sums from cumulative sums.
260
+ const legacyActions = { ...prof.actionCounts };
261
+ const legacyTiers = prof.tierCounts.slice();
262
+ const legacyHours = prof.hourCounts.slice();
263
+ let legacyLenSum = prof.lengthSum;
264
+ let legacyLenSq = prof.lengthSqSum;
265
+ let legacyUrgent = prof.urgentCount;
266
+ for (const b of buckets) {
267
+ for (const [a, c] of Object.entries(b.actionCounts)) {
268
+ legacyActions[a] = (legacyActions[a] ?? 0) - c;
269
+ }
270
+ for (let t = 0; t < 5; t++)
271
+ legacyTiers[t] = (legacyTiers[t] ?? 0) - (b.tierCounts[t] ?? 0);
272
+ for (let h = 0; h < 24; h++)
273
+ legacyHours[h] = (legacyHours[h] ?? 0) - (b.hourCounts[h] ?? 0);
274
+ legacyLenSum -= b.lengthSum;
275
+ legacyLenSq -= b.lengthSqSum;
276
+ legacyUrgent -= b.urgentCount;
277
+ }
278
+ accumulate(view, 1.0, {
279
+ count: legacyCount,
280
+ actionCounts: legacyActions,
281
+ tierCounts: legacyTiers,
282
+ hourCounts: legacyHours,
283
+ lengthSum: Math.max(0, legacyLenSum),
284
+ lengthSqSum: Math.max(0, legacyLenSq),
285
+ urgentCount: Math.max(0, legacyUrgent),
286
+ startMs: 0,
287
+ });
288
+ }
289
+ // ── Decayed buckets ──
290
+ for (const b of buckets) {
291
+ const ageWindows = Math.max(0, (opts.nowMs - b.startMs) / bucketMs);
292
+ const weight = Math.pow(0.5, ageWindows / halfLife);
293
+ accumulate(view, weight, b);
294
+ }
295
+ return view;
296
+ }
297
+ function accumulate(view, weight, b) {
298
+ view.effectiveCount += b.count * weight;
299
+ for (const [a, c] of Object.entries(b.actionCounts)) {
300
+ if (c > 0)
301
+ view.actionCounts[a] = (view.actionCounts[a] ?? 0) + c * weight;
302
+ }
303
+ for (let t = 0; t < 5; t++)
304
+ view.tierCounts[t] += (b.tierCounts[t] ?? 0) * weight;
305
+ for (let h = 0; h < 24; h++)
306
+ view.hourCounts[h] += (b.hourCounts[h] ?? 0) * weight;
307
+ view.lengthSum += b.lengthSum * weight;
308
+ view.lengthSqSum += b.lengthSqSum * weight;
309
+ view.urgentCount += b.urgentCount * weight;
310
+ }
311
+ /** Mean message length from a decayed view, or undefined when there is no weight. */
312
+ export function decayedMeanLength(view) {
313
+ return view.effectiveCount > 0 ? view.lengthSum / view.effectiveCount : undefined;
314
+ }
315
+ /** Population std of message length from a decayed view, or undefined when <2 effective. */
316
+ export function decayedStdLength(view) {
317
+ if (view.effectiveCount < 2)
318
+ return undefined;
319
+ const mean = view.lengthSum / view.effectiveCount;
320
+ const variance = view.lengthSqSum / view.effectiveCount - mean * mean;
321
+ return variance > 0 ? Math.sqrt(variance) : 0;
322
+ }
323
+ /** Fraction of decayed interactions in a given hour (0..1). */
324
+ export function decayedHourFraction(view, hour) {
325
+ if (view.effectiveCount <= 0)
326
+ return 0;
327
+ const h = Math.max(0, Math.min(23, Math.floor(hour)));
328
+ return (view.hourCounts[h] ?? 0) / view.effectiveCount;
329
+ }
141
330
  export class StoreBaselineProvider {
142
331
  store;
143
332
  constructor(store) {
@@ -1 +1 @@
1
- {"version":3,"file":"RelationshipBehaviorStore.js","sourceRoot":"","sources":["../../src/permissions/RelationshipBehaviorStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RelationshipBehaviorStore.js","sourceRoot":"","sources":["../../src/permissions/RelationshipBehaviorStore.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.448",
3
+ "version": "1.3.450",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-09T18:24:57.311Z",
5
- "instarVersion": "1.3.448",
4
+ "generatedAt": "2026-06-09T19:51:52.286Z",
5
+ "instarVersion": "1.3.450",
6
6
  "entryCount": 199,
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
14
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
23
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
32
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
41
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
50
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
59
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
68
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
77
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
86
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
95
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
104
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
113
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
122
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
131
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
140
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
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": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
149
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
150
150
  "since": "2025-01-01"
151
151
  },
152
152
  "job:health-check": {
@@ -370,7 +370,7 @@
370
370
  "type": "skill",
371
371
  "domain": "skills",
372
372
  "sourcePath": ".claude/skills/autonomous/SKILL.md",
373
- "contentHash": "9f257c5e5365a39e85090458381ca99430047af6cbb65178f3b9f6215c50d7e8",
373
+ "contentHash": "d1ba5ef088651ea37af1c50a0c9a6b4a0efe66a7dcf483daa2e963df8b6b7fea",
374
374
  "since": "2025-01-01"
375
375
  },
376
376
  "skill:build": {
@@ -1538,7 +1538,7 @@
1538
1538
  "type": "subsystem",
1539
1539
  "domain": "updates",
1540
1540
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1541
- "contentHash": "8201a824e666b27d0eda3d8f316eff4a4d362a0942c2b553b279d57d3a5aa021",
1541
+ "contentHash": "826317d6f3c0c5bdd67b3f88dbdafa3ce7012628c1422747862e0dfe0656a879",
1542
1542
  "since": "2025-01-01"
1543
1543
  },
1544
1544
  "subsystem:scheduler": {
@@ -0,0 +1,26 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ feat(permissions): deeper **baseline-poisoning resistance** for the Slack relationship anomaly detector — the pre-enforce follow-ups (#2/#3) from the Phase-3 adversarial review. **Observe-only / dark, additive, backward-compatible.**
9
+
10
+ - **Recency/decay (dual-view max):** the behavior store keeps optional day-bucketed counts; the scorer computes a decay-weighted view AND keeps the cumulative view, and scores each signal as the **more-suspicious of the two** (max anomaly / lower normal-ceiling / lower normal-rate). Decay can only ADD suspicion, never disarm a cumulative signal — so the never-lower invariant holds; its real job is durability (a one-time burst fades once genuine traffic resumes). Default half-life 30 day-windows.
11
+ - **Minimum-baseline-age (#3a):** "established" now requires `firstSeen` older than `minBaselineAgeDays` (default 7) AND `interactionCount >= establishedMin` — a high-count-but-young burst stays low-confidence (action/tier/style signals suppressed). `0` restores legacy count-only behavior.
12
+ - **Per-principal rate cap (#3b):** `maxObservationsPerWindow` (default 50/day-window); excess observations are dropped + logged (`onCapDrop`), never recorded — cumulative + bucket counts stay in lock-step. `0` disables.
13
+ - All under `permissionGate.relationshipAnomaly.poisoningResistance`; absence preserves shipped behavior. Decay is read-time only (raw counts persist) → retune/revert needs no migration. Legacy profiles (no `buckets` field) score identically (decayed view degrades to cumulative).
14
+
15
+ ## What to Tell Your User
16
+
17
+ Nothing changes by default. This hardens the (still-dark) relationship anomaly detector against a patient attacker who tries to "train" the baseline — by slowly feeding normal-looking activity, or a burst of it — so a later out-of-character request looks normal. Three additive defenses: recent activity can't durably overwrite long-standing behavior, a freshly-created baseline isn't trusted until it's both old enough and large enough, and no single account can flood the baseline faster than a capped rate. It can still only ever ask for *more* verification, never less. Needed before the anomaly layer is ever switched from observe-only to enforcing.
18
+
19
+ ## Summary of New Capabilities
20
+
21
+ - **`permissionGate.relationshipAnomaly.poisoningResistance: { decayHalfLifeWindows, minBaselineAgeDays, maxObservationsPerWindow, bucketMs }`** (opt-in; the whole anomaly feature stays dark by default) — recency-decay + minimum-baseline-age + per-principal observation-rate-cap, so a poisoned baseline can't disarm the detector.
22
+
23
+ ## Evidence
24
+
25
+ - 32 anomaly tests (12 new): rate-cap burst / per-window / opt-out; min-age young-vs-aged / opt-out; decay durability + a "without the rate cap" counter-test proving the cap is load-bearing; backward-compat (legacy-profile decay/scoring/backfill). Counterfactuals confirm each hardening is load-bearing (with it off, the poisoning attack succeeds; on, it's caught). 61/61 with the permission-gate + routes integration. `tsc --noEmit` clean; full lint chain clean (state-registry, silent-fallback ratchet, topic-creation). (Full unit suite runs in CI, sharded — local run blocked by host CPU starvation.)
26
+ - Side-effects review (`upgrades/side-effects/slack-anomaly-poisoning-resistance.md`); deterministic (no LLM-in-gate-path) so reviewed by me + the counterfactual tests, never-lower preserved by the dual-view-max design.
@@ -0,0 +1,24 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ feat(autonomous): add an explicit **"Legitimate Stop Conditions" allowlist** to the autonomous skill, so an agent in a pre-approved autonomous session doesn't exit early for reversible decisions, milestones, late-hour, or "the operator might have an opinion."
9
+
10
+ - New `## Legitimate Stop Conditions (the ONLY valid reasons to exit)` section in `.claude/skills/autonomous/SKILL.md`: the only valid stops are (a) a genuine HARD external blocker the agent can't resolve, (b) duration expiry, (c) the completion-condition/promise genuinely met — with a NON-stops table naming each early-exit rationalization (decisions/milestones/2 AM/"needs your steer"/quiet off-ramp) and why it's a *continue*. Quotes the operator's own framing ("decisions are not that critical … ship dark … use best judgment").
11
+ - Two new anti-pattern entries ("This Needs Your Steer", "Quiet Off-Ramp"); cross-referenced into the existing Defer-to-Future-Self trap.
12
+ - **Migration Parity:** reuses the existing `migrateAutonomousStopHookTopicKeyed` migration (marker bumped to `LEGITIMATE_STOP_CONDITIONS`), so existing agents receive the section on update. Content-sniffing + idempotent: deploys only when the section is absent AND the SKILL.md still matches the stock fingerprint; a customized SKILL.md is left untouched.
13
+
14
+ ## What to Tell Your User
15
+
16
+ Autonomous sessions now run to completion more reliably. Previously an agent in a pre-approved autonomous run could talk itself into stopping early — "this is a clean milestone," "this decision needs your steer," "it's late." The autonomous skill now spells out, in the agent's own playbook, that the only valid reasons to stop are a genuine external blocker it can't resolve, the time running out, or the work actually being done — and that reversible, dark-shipped decisions are for it to make and keep moving. Nothing for you to configure; existing agents pick it up on their next update.
17
+
18
+ ## Summary of New Capabilities
19
+
20
+ - The autonomous skill carries an explicit legitimate-stops allowlist + NON-stops table, reinforcing "make the reversible call and keep going" in a pre-approved autonomous session. Reaches existing agents via a content-sniffing `PostUpdateMigrator` migration that never clobbers a customized skill.
21
+
22
+ ## Evidence
23
+
24
+ - `tests/unit/PostUpdateMigrator-autonomousStopHook.test.ts` — 12 pass (incl. re-deploys-to-existing-agent, idempotent-on-second-run, leaves-customized-untouched, no-op-when-absent). Related suites (autonomous-skill-deployment, migration-parity, autonomousHookPath, idle-backoff): 52 pass. `tsc --noEmit` clean; lint clean. Tier 1 (skill content + a marker bump on an existing tested migration; gate signaled Tier 2 for the migration surface → declared Tier 1, recorded `belowFloor` in the decision audit).
@@ -0,0 +1,108 @@
1
+ # Side-Effects Review — Autonomous "Legitimate Stop Conditions" allowlist
2
+
3
+ **Version / slug:** `autonomous-legitimate-stops`
4
+ **Date:** `2026-06-09`
5
+ **Author:** `Instar Agent (echo)`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ Adds a new top-level section to the autonomous skill's instruction file — **"## Legitimate Stop Conditions (the ONLY valid reasons to exit)"** — enumerating the only three valid reasons a pre-approved autonomous session may exit: (a) a genuine hard external blocker the agent cannot resolve, (b) duration expiry, (c) the completion condition/promise genuinely met. It pairs that with an explicit NON-stops table (reversible decisions, milestones, late-hour, "needs your steer/opinion," "good stopping point," quiet off-ramp-with-no-reply) and reinforces the existing Anti-Patterns list with two new entries ("This Needs Your Steer" and "Quiet Off-Ramp"). Files touched: `.claude/skills/autonomous/SKILL.md` (the bundled shipping source — new agents get it via `init`/`installAutonomousSkill`), `src/core/PostUpdateMigrator.ts` (bumps the existing `migrateAutonomousStopHookTopicKeyed` SKILL.md marker from `PER-TOPIC (setup-race hardening)` to `LEGITIMATE_STOP_CONDITIONS` so existing agents receive the section on update), and `tests/unit/PostUpdateMigrator-autonomousStopHook.test.ts` (four new migration tests). This is prompt/skill CONTENT plus its Migration-Parity migration — NOT a change to any decision-point code logic.
11
+
12
+ ## Decision-point inventory
13
+
14
+ The change touches **no runtime decision point.** It does NOT modify the autonomous stop hook's blocking logic (`autonomous-stop-hook.sh`), the completion-condition judge, the emergency-stop check, or any gate/sentinel/watchdog. The stop hook continues to decide exit exactly as before; this change only edits the prose the agent reads and adds a content-sniffing migration that re-deploys that prose to existing installs.
15
+
16
+ - `migrateAutonomousStopHookTopicKeyed` (SKILL.md upgrade arm) — modify (marker bump only) — re-deploys the bundled SKILL.md to existing agents whose installed copy lacks the new sentinel.
17
+
18
+ ---
19
+
20
+ ## 1. Over-block
21
+
22
+ **What legitimate inputs does this change reject that it shouldn't?**
23
+
24
+ No block/allow surface — over-block not applicable. The migration's `upgrade()` helper writes a file only when the installed copy lacks the new marker AND matches the stock fingerprint (`ALL_TASKS_COMPLETE`); a customized SKILL.md is left untouched (reported as `skipped`), so it cannot "over-write" operator customizations.
25
+
26
+ ---
27
+
28
+ ## 2. Under-block
29
+
30
+ **What failure modes does this still miss?**
31
+
32
+ No block/allow surface — under-block not applicable. As prose guidance, the section is advisory: the structural stop hook is what actually enforces continuation. An agent could still rationalize an early stop despite the guidance — but that is the stop-hook's job to catch (out of scope here, tracked as the separate Tier-2 stop-hook logic change). This change strengthens the guidance the agent reads each iteration; it does not claim to be the enforcement layer.
33
+
34
+ ---
35
+
36
+ ## 3. Level-of-abstraction fit
37
+
38
+ **Is this at the right layer?**
39
+
40
+ Yes. This is skill CONTENT (prompt-level guidance), which is the correct layer for "here are the only valid reasons to exit." The structural enforcement (the stop hook) is a separate, lower layer that this content complements. The migration rides the EXISTING `migrateAutonomousStopHookTopicKeyed` path — the established, correct home for autonomous SKILL.md content updates — rather than introducing a parallel migration. The marker-bump mechanism is the same content-sniffing pattern already used for the prior SKILL.md fixes (per-topic write, registration-path fix), so it reuses rather than re-implements.
41
+
42
+ ---
43
+
44
+ ## 4. Signal vs authority compliance
45
+
46
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
47
+
48
+ **Does this change hold blocking authority with brittle logic?**
49
+
50
+ - [x] No — this change has no block/allow surface.
51
+
52
+ This is documentation/skill-content plus an idempotent file-deployment migration. It makes no allow/block decision, holds no authority over message flow or session lifecycle, and adds no brittle detector. The migration only writes a markdown file under content-sniffing guards.
53
+
54
+ ---
55
+
56
+ ## 5. Interactions
57
+
58
+ **Does this interact with existing checks, recovery paths, or infrastructure?**
59
+
60
+ - **Shadowing:** None. The migration's SKILL.md arm shares the same `upgrade()` helper as the stop-hook and setup-script arms within `migrateAutonomousStopHookTopicKeyed`; each arm targets a distinct file path, so they cannot shadow each other. The marker bump on the SKILL.md arm does not affect the hook/setup arms (independent markers).
61
+ - **Double-fire:** None. `installAutonomousSkill()` (init path) is install-if-missing and won't overwrite; the migration is the single content-update path. They do not both write the same file in the same run (init only writes when absent).
62
+ - **Races:** None. The migration runs synchronously inside the PostUpdateMigrator sequence at update time; no shared concurrent state.
63
+ - **Feedback loops:** None.
64
+
65
+ One real interaction verified: the existing test `PostUpdateMigrator-autonomousStopHook.test.ts` already exercises this migration; the marker bump from `PER-TOPIC (setup-race hardening)` to `LEGITIMATE_STOP_CONDITIONS` required no change to the existing hook/setup test cases (those assert their own markers, not the SKILL.md marker), and the new SKILL.md tests were added alongside. Verified the bundled SKILL.md contains BOTH the new marker (so `next.includes(marker)` passes and the upgrade actually writes) AND the fingerprint.
66
+
67
+ ---
68
+
69
+ ## 6. External surfaces
70
+
71
+ **Does this change anything visible outside the immediate code path?**
72
+
73
+ - Other agents on the same machine: only their autonomous SKILL.md content updates on their next PostUpdateMigrator run — the intended Migration-Parity effect.
74
+ - Other users of the install base: same — they get the new guidance on update.
75
+ - External systems (Telegram, Slack, GitHub, Cloudflare): none.
76
+ - Persistent state: none beyond rewriting the one markdown file the migration targets (only when stale + stock).
77
+ - Timing/runtime conditions: none.
78
+
79
+ ---
80
+
81
+ ## 7. Rollback cost
82
+
83
+ **If this turns out wrong in production, what's the back-out?**
84
+
85
+ Pure content change — revert the SKILL.md edit and the marker bump, ship as the next patch. No persistent state to clean up, no data migration, no agent-state repair. Existing agents that already received the re-deployed SKILL.md would simply receive the reverted version on a subsequent marker bump (or keep the harmless prose section). No user-visible regression during the rollback window.
86
+
87
+ ---
88
+
89
+ ## Conclusion
90
+
91
+ This review confirms the change is content-only with no decision-point surface. It adds the operator-requested "Legitimate Stop Conditions" allowlist + NON-stops table to the autonomous skill, ships it to new agents via the bundled source, and reaches existing agents via the established content-sniffing SKILL.md migration arm (marker bump, idempotent, customization-preserving). No design changes were required by the review. Clear to ship pending human review.
92
+
93
+ ---
94
+
95
+ ## Second-pass review (if required)
96
+
97
+ **Reviewer:** not required
98
+
99
+ Tier 1, content-only, no block/allow or session-lifecycle decision logic touched — the Phase 5 second-pass triggers do not apply.
100
+
101
+ ---
102
+
103
+ ## Evidence pointers
104
+
105
+ - `npx tsc --noEmit` → exit 0 (clean).
106
+ - `npx vitest run tests/unit/PostUpdateMigrator-autonomousStopHook.test.ts` → 12 passed (8 prior + 4 new SKILL.md cases).
107
+ - `npx vitest run tests/unit/autonomous-skill-deployment.test.ts tests/unit/migration-parity.test.ts tests/unit/PostUpdateMigrator-autonomousHookPath.test.ts tests/unit/autonomous-stop-hook-idle-backoff.test.ts` → 52 passed.
108
+ - Bundled SKILL.md verified to contain both `LEGITIMATE_STOP_CONDITIONS` (marker) and `ALL_TASKS_COMPLETE` (fingerprint).