feat(backthink): 静默期自排 C 的判定侧(C1-1,切片三之一)
- 追加 TriggerSelfWake(不动既有编号)+ SelfWakeRequest(走既有 urgency 声明通道,不新造第二条) - escalateImport 折算收成唯一 foldDeclared(事件轮与自排轮共用、只上抬取较高档) - DecisionInput.Heartbeat bool → Kind TriggerKind;心跳仍免检、**自排不享心跳豁免**(要求声明 ≥ warning) - push 与档位分离:push.go 零改动即自动正确(eventDriven 对 self_wake 为 false ⇒ 照旧过 PushGate) - 4 个变异自检(折算空操作/删自排分支/常量传心跳/非事件一律豁免) ⚠️ 本片只是判定侧:WakeNow/worker/闸属 C1-2,工具面与提示词属 C1-3 ⇒ **不得写『C 已完成』** ⚠️ 遗留 G-A(建议登记进 design/12 C.4):TriggerKind 零值=TriggerHeartbeat ⇒ 漏填=最宽豁免(fail-open); 本片已在字段注释与单测里显式化,但规格侧应补一句或引入 TriggerUnknown
This commit is contained in:
1 parent
ea43f07bce
commit
94da6bcd6d
8 files changed
+353
-26
No files matched your search
@@ -1,6 +1,7 @@
|
||||
package backthink
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -59,7 +60,7 @@ func TestDecide_DoNotDisturb(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "安静时段_心跳_不打扰",
|
||||
in: DecisionInput{Trigger: "heartbeat", Import: ImportanceLow, At: nightAt(), UserState: UserState{}, ConclusionPush: true, Heartbeat: true},
|
||||
in: DecisionInput{Trigger: "heartbeat", Import: ImportanceLow, At: nightAt(), UserState: UserState{}, ConclusionPush: true, Kind: TriggerHeartbeat},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
@@ -171,7 +172,8 @@ func TestClassifyPush(t *testing.T) {
|
||||
// TestDecide_ActivityGate 验证活动感知软门:刚开始的
|
||||
// 对话会扣下琐碎内容(critical 除外),长期静默的主人只会被
|
||||
// 重要事件唤醒——但心跳轮除外,它永远不会被长期
|
||||
// 静默的间隔拦下(裁决 07.4.3)——而中间地带不会过度抑制。
|
||||
// 静默的间隔拦下(裁决 07.4.3),而她自己排起的一轮**不享**这条豁免
|
||||
// (design/12 §N C.4,见紧随其后的用例)——中间地带不会过度抑制。
|
||||
func TestDecide_ActivityGate(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := testBackthink()
|
||||
@@ -185,6 +187,7 @@ func TestDecide_ActivityGate(t *testing.T) {
|
||||
LastActivity: dayAt().Add(-5 * time.Minute),
|
||||
HasActivity: true,
|
||||
ConclusionPush: true,
|
||||
Kind: TriggerEvent,
|
||||
}
|
||||
if got := b.Decide(fresh); got.ShouldPush {
|
||||
t.Fatalf("fresh conversation should hold a normal push, got %+v", got)
|
||||
@@ -196,6 +199,8 @@ func TestDecide_ActivityGate(t *testing.T) {
|
||||
|
||||
// 离开很久(> longIdleThreshold):只有重要事件值得
|
||||
// 唤醒——但心跳轮仍会通过(裁决 07.4.3 长期静默段不拦心跳)。
|
||||
// Kind 必须显式给出:TriggerKind 的零值是 TriggerHeartbeat,
|
||||
// 省掉它这一档就从「事件」静默变成「心跳豁免」。
|
||||
idle := DecisionInput{
|
||||
Import: ImportanceNormal,
|
||||
At: dayAt(),
|
||||
@@ -203,6 +208,7 @@ func TestDecide_ActivityGate(t *testing.T) {
|
||||
LastActivity: dayAt().Add(-3 * time.Hour),
|
||||
HasActivity: true,
|
||||
ConclusionPush: true,
|
||||
Kind: TriggerEvent,
|
||||
}
|
||||
if got := b.Decide(idle); got.ShouldPush {
|
||||
t.Fatalf("long idle should hold a normal event push, got %+v", got)
|
||||
@@ -212,7 +218,7 @@ func TestDecide_ActivityGate(t *testing.T) {
|
||||
t.Fatalf("long idle high-importance should push, got %+v", got)
|
||||
}
|
||||
idle.Import = ImportanceLow
|
||||
idle.Heartbeat = true
|
||||
idle.Kind = TriggerHeartbeat
|
||||
if got := b.Decide(idle); !got.ShouldPush {
|
||||
t.Fatalf("long idle heartbeat should still push (07.4.3), got %+v", got)
|
||||
}
|
||||
@@ -225,8 +231,58 @@ func TestDecide_ActivityGate(t *testing.T) {
|
||||
LastActivity: dayAt().Add(-30 * time.Minute),
|
||||
HasActivity: true,
|
||||
ConclusionPush: true,
|
||||
Kind: TriggerEvent,
|
||||
}
|
||||
if got := b.Decide(middle); !got.ShouldPush {
|
||||
t.Fatalf("middle-band activity should allow a normal push, got %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDecide_ActivityGate_SelfWakeNeedsDeclaredUrgency 是 design/12 §C.4 的真断言
|
||||
// (判据 4):长期静默段里,她自己排起的一轮要求她说得出理由(折算后 Import ≥ High,
|
||||
// 即声明 ≥ warning)才放行;例常自排被扣下、理由点名「self-initiated wake」;
|
||||
// 而例行心跳的既有豁免**不许回归**(裁决 07.4.3)。把 activityHeld 里的自排分支
|
||||
// 删掉、或把三分支改回「非事件一律豁免」,这条即变红。
|
||||
func TestDecide_ActivityGate_SelfWakeNeedsDeclaredUrgency(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := testBackthink()
|
||||
in := DecisionInput{
|
||||
Trigger: SelfWakeSource,
|
||||
Import: ImportanceNormal,
|
||||
At: dayAt(),
|
||||
UserState: UserState{Boredom: 0.9},
|
||||
LastActivity: dayAt().Add(-3 * time.Hour),
|
||||
HasActivity: true,
|
||||
ConclusionPush: true,
|
||||
Kind: TriggerSelfWake,
|
||||
}
|
||||
|
||||
got := b.Decide(in)
|
||||
if got.ShouldPush {
|
||||
t.Fatalf("undeclared self wake in long silence should be held, got %+v", got)
|
||||
}
|
||||
if !strings.Contains(got.Reason, "self-initiated wake") {
|
||||
t.Fatalf("Reason = %q, want it to name the self-initiated wake hold", got.Reason)
|
||||
}
|
||||
|
||||
// 她声明了 warning ⇒ selfWakeTrigger 折算成 High ⇒ 放行。
|
||||
in.Import = ImportanceHigh
|
||||
if got := b.Decide(in); !got.ShouldPush {
|
||||
t.Fatalf("self wake with a declared reason (>= warning) should push, got %+v", got)
|
||||
}
|
||||
|
||||
// 对照:同样久未回应,例行心跳照旧放行(07.4.3 豁免不许被这次改动带走)。
|
||||
hb := DecisionInput{
|
||||
Trigger: "heartbeat",
|
||||
Import: ImportanceLow,
|
||||
At: dayAt(),
|
||||
UserState: UserState{Boredom: 0.9},
|
||||
LastActivity: dayAt().Add(-3 * time.Hour),
|
||||
HasActivity: true,
|
||||
ConclusionPush: true,
|
||||
Kind: TriggerHeartbeat,
|
||||
}
|
||||
if got := b.Decide(hb); !got.ShouldPush {
|
||||
t.Fatalf("long idle heartbeat should still push (07.4.3), got %+v", got)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user