mavend: centralize action validation boundary (slice 4)

This commit is contained in:
2026-09-06 12:53:54 +04:00
parent 6a402bf556
commit 356766bce1
32 changed files with 2061 additions and 178 deletions
+11 -11
View File
@@ -73,7 +73,7 @@ func TestHexisMutatingRequiresConfirm(t *testing.T) {
caps := `[{"id":"cap_restart","name":"restart","read_only":false,"risk":"high"}]`
h, executed := newHexisTestHandler(t, resolved, caps)
reply := h.handleHexisAct(ctx, actDec("muzick indexer"))
reply := h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
if !strings.Contains(reply, "да") {
t.Fatalf("mutating cap should ask to confirm, got %q", reply)
}
@@ -103,7 +103,7 @@ func TestHexisConfirmNoDoesNotExecute(t *testing.T) {
caps := `[{"id":"cap_restart","name":"restart","read_only":false}]`
h, executed := newHexisTestHandler(t, resolved, caps)
_ = h.handleHexisAct(ctx, actDec("muzick indexer"))
_ = h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
reply, handled := h.resolveConfirm(ctx, "нет")
if !handled || !strings.Contains(reply, "отменила") {
t.Fatalf("no should cancel, got handled=%v reply=%q", handled, reply)
@@ -119,7 +119,7 @@ func TestHexisReadOnlyExecutesImmediately(t *testing.T) {
caps := `[{"id":"cap_status","name":"restart","read_only":true}]`
h, executed := newHexisTestHandler(t, resolved, caps)
reply := h.handleHexisAct(ctx, actDec("muzick indexer"))
reply := h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
if !*executed {
t.Fatal("read-only cap should execute without confirmation")
}
@@ -136,7 +136,7 @@ func TestHexisAmbiguousAsksClarification(t *testing.T) {
ambiguous := `{"status":"ambiguous","candidates":[{"entity_id":"ent_muzick","display_name":"Muzick indexer"},{"entity_id":"ent_manga","display_name":"Manga indexer"}]}`
h, executed := newHexisTestHandler(t, ambiguous, `[]`)
reply := h.handleHexisAct(ctx, actDec("the indexer"))
reply := h.handleHexisAct(ctx, actDec("the indexer"), routeCandidate("restart"))
if !strings.Contains(reply, "Muzick indexer") || !strings.Contains(reply, "Manga indexer") {
t.Fatalf("ambiguous should list candidates, got %q", reply)
}
@@ -154,7 +154,7 @@ func TestHexisResolveFlatShapeAccepted(t *testing.T) {
caps := `[{"id":"cap_status","name":"restart","read_only":true}]`
h, executed := newHexisTestHandler(t, flat, caps)
reply := h.handleHexisAct(ctx, actDec("muzick indexer"))
reply := h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
if !*executed {
t.Fatalf("flat-shaped resolved entity should still execute, got reply %q", reply)
}
@@ -183,7 +183,7 @@ func TestHexisNexusErrorFailsClosed(t *testing.T) {
ecosystem: stubEcosystem(nexus.URL, hexis.URL),
}
reply := h.handleHexisAct(ctx, actDec("muzick indexer"))
reply := h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
if reply == "" {
t.Fatal("nexus dependency failure must not fall through with an empty reply")
}
@@ -216,7 +216,7 @@ func TestHexisUnavailableFailsClosed(t *testing.T) {
ecosystem: stubEcosystem(nexus.URL, hexis.URL),
}
reply := h.handleHexisAct(ctx, actDec("muzick indexer"))
reply := h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
if reply == "" {
t.Fatal("hexis dependency failure must not fall through with an empty reply")
}
@@ -234,7 +234,7 @@ func TestHexisNotFoundStillFallsThrough(t *testing.T) {
notFound := `{"status":"not_found"}`
h, executed := newHexisTestHandler(t, notFound, `[]`)
reply := h.handleHexisAct(ctx, actDec("turn off the lights"))
reply := h.handleHexisAct(ctx, actDec("turn off the lights"), routeCandidate("restart"))
if reply != "" {
t.Fatalf("not_found resolution should fall through with empty reply, got %q", reply)
}
@@ -264,7 +264,7 @@ func TestHexisIrreversibleCapabilityIsNotRunFromVoice(t *testing.T) {
caps := `[{"id":"cap_wipe","name":"restart","read_only":false,"risk":"irreversible","requires_confirmation":true}]`
h, executed := newHexisTestHandler(t, resolved, caps)
reply := h.handleHexisAct(ctx, actDec("muzick indexer"))
reply := h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
if *executed {
t.Fatal("an irreversible capability ran from the voice path")
}
@@ -284,7 +284,7 @@ func TestHexisSafeCapabilityRunsOnItsDeclaredTier(t *testing.T) {
caps := `[{"id":"cap_status","name":"restart","read_only":true,"risk":"safe"}]`
h, executed := newHexisTestHandler(t, resolved, caps)
reply := h.handleHexisAct(ctx, actDec("muzick indexer"))
reply := h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
if !*executed {
t.Fatal("a capability Hexis calls safe should run")
}
@@ -301,7 +301,7 @@ func TestHexisUndeclaredTierStillConfirms(t *testing.T) {
caps := `[{"id":"cap_restart","name":"restart","read_only":false}]`
h, executed := newHexisTestHandler(t, resolved, caps)
reply := h.handleHexisAct(ctx, actDec("muzick indexer"))
reply := h.handleHexisAct(ctx, actDec("muzick indexer"), routeCandidate("restart"))
if *executed {
t.Fatal("a mutating capability ran without a confirm")
}