tool, mavend: Hexis owns the tier of a Hexis capability (V-523)
read_only was the whole decision on the Hexis act path, which flattened three answers into two. A capability that wipes the thing it names got the same single spoken "да" as one that restarts a service, and requires_confirmation — which the Hexis contract calls server-derived and never settable by a caller — was read by nobody. docs/ecosystem.md §17.3 says confirmation follows risk. RiskOfCapability reads Hexis's risk, read_only and requires_confirmation and returns one of the three tiers internal/tool already had. It takes plain values rather than a Capability, so internal/tool keeps no dependency on the Hexis client. RiskOf keeps deriving, because a shell row the owner ticked on /tools has no upstream to ask. Every disagreement between the three fields goes up, never down: safe and mutating is a contradiction and takes the confirm, an unrecognised tier takes the confirm, and requires_confirmation may only raise. Same default as an unrecognised dispatch shape — argue your way down, never up. The irreversible refusal was a Go literal in two places and is now one deck entry, act_needs_authed_surface. It lost four words to the persona ceiling.
This commit is contained in:
@@ -79,3 +79,33 @@ func TestExecConfirmsAnUnreadableRow(t *testing.T) {
|
||||
t.Errorf("%v; want ErrNeedsConfirm", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Hexis owns the tier of a Hexis capability, so this reads rather than derives
|
||||
// (Vikunja #523). The cases that matter are the ones where the three fields
|
||||
// disagree, or where the tier is a word this package has never seen: every one
|
||||
// of those goes up to a confirm, never down to running freely.
|
||||
func TestRiskOfCapabilityReadsHexis(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
risk string
|
||||
ro bool
|
||||
confirm bool
|
||||
want Risk
|
||||
}{
|
||||
{"hexis says irreversible", "irreversible", false, true, TierIrreversible},
|
||||
{"case and space do not change the tier", " Irreversible ", false, true, TierIrreversible},
|
||||
{"hexis says destructive", "destructive", false, true, TierDestructive},
|
||||
{"a read hexis calls safe", "safe", true, false, TierSafe},
|
||||
{"safe but mutating is a contradiction", "safe", false, false, TierDestructive},
|
||||
{"safe but wants a confirm is a contradiction", "safe", true, true, TierDestructive},
|
||||
{"no tier, read-only, no confirm", "", true, false, TierSafe},
|
||||
{"no tier and mutating", "", false, false, TierDestructive},
|
||||
{"no tier but hexis wants a confirm", "", true, true, TierDestructive},
|
||||
{"a word we have never seen", "spicy", true, false, TierDestructive},
|
||||
} {
|
||||
if got := RiskOfCapability(c.risk, c.ro, c.confirm); got != c.want {
|
||||
t.Errorf("%s: RiskOfCapability(%q, ro=%v, confirm=%v) = %q; want %q",
|
||||
c.name, c.risk, c.ro, c.confirm, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user