From 2f08d3663f2aa47e7ede758d216843ca26e96927 Mon Sep 17 00:00:00 2001 From: Vikas Singhal Date: Fri, 31 Jul 2026 16:14:27 +0530 Subject: [PATCH] fix(dreaming): do not compute approval friction against a missing denominator (v0.281.5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.280.0 started recording `approved` so friction could be a rate rather than a raw count. Per-pass entries written BEFORE that carry rejections with no denominator, and recentTally summed them anyway — a window of mostly-legacy entries reads as ~100% rejection. Live instapods was telling every agent "recent actions were rejected at human approval" while its true 7-day rate was 5.4% (35 approved / 2 rejected). Entries lacking the denominator now contribute to neither side of the ratio; their budget/error signals still count. Verified against both live tenants real window shapes: the false instapods nag stops, instawp goes quiet until it has a real denominator (conservative — silence beats wrong advice), genuine friction with a good sample still fires. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 12 ++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- src/edge/dreaming.ts | 10 ++++++++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 880b569..6dab17b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,18 @@ new version heading in the same commit. ## [Unreleased] +## [0.281.5] — 2026-07-31 +### Fixed +- **The approval-friction signal no longer divides by a denominator that isn't there.** v0.280.0 started + recording the `approved` count so friction could be a rate; per-pass entries written before that carry + rejections with **no denominator**, and `recentTally` summed them anyway — so a window of mostly-legacy + entries read as ~100% rejection. Live instapods was nagging every agent that "recent actions were + rejected at human approval" while its true 7-day rate was **5.4%** (35 approved / 2 rejected). Entries + lacking the denominator now contribute to neither side of the ratio (their budget/error signals still + count), so the signal stays quiet until real evidence exists rather than inventing it. Verified against + both live tenants' actual window shapes: the false instapods nag stops; genuine friction with a real + sample still fires. + ## [0.281.4] — 2026-07-31 ### Fixed - **Bump `TOPICS_VERSION` to 3.** v0.281.3 tightened the topic extractor (opaque hex ids) without bumping diff --git a/package-lock.json b/package-lock.json index 6753a20..44fe036 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "agent-os", - "version": "0.281.4", + "version": "0.281.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "agent-os", - "version": "0.281.4", + "version": "0.281.5", "license": "MIT", "bin": { "agent-os": "bin/agent-os" diff --git a/package.json b/package.json index a0c1b83..c6c5f0a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agent-os", - "version": "0.281.4", + "version": "0.281.5", "description": "A generic, governed operating system for running autonomous agents safely across brands. Ships with a local web console.", "license": "MIT", "type": "commonjs", diff --git a/src/edge/dreaming.ts b/src/edge/dreaming.ts index 1090a43..8a88807 100644 --- a/src/edge/dreaming.ts +++ b/src/edge/dreaming.ts @@ -464,8 +464,14 @@ function recentTally(s: DreamState): { sessions: number; success: number; approv for (const e of (s.recent ?? []).slice(0, RECENT_PASSES)) { r.sessions += e.sessions || 0; r.success += e.success || 0; - r.approved += e.approved || 0; - r.rejected += e.rejected || 0; + // Approval friction is a RATIO, so an entry that predates the `approved` denominator must contribute + // NEITHER side — counting its rejections against a missing denominator reads as 100% rejection. Live + // instapods computed 22% (and nagged every agent) while its true rate was 5.4%, because six of seven + // window entries were legacy. Skipping them means the signal stays quiet until real evidence exists. + if (e.approved !== undefined) { + r.approved += e.approved; + r.rejected += e.rejected || 0; + } r.budgetStops += e.budgetStops || 0; r.errors += e.errors || 0; }