1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Agent families — the verdict surface (R2, charter 2026-08-20-r2-agent-families).
//!
//! One home for the two per-family verdict concerns that used to be scattered:
//! payload normalization (the `normalize_*` fns, re-exported from the family
//! submodules for the single `super::normalize` dispatch) and the three native
//! verdict encoders (moved down here from `verbs/hook.rs`, which is the verbs
//! layer — these depend only on `Agent` + `serde_json`, so they belong in the
//! leaf `agents` layer).
//!
//! The families are the GENUINE boundaries, not one-per-agent: Claude, Codex,
//! and Auggie form a lineage (`claude_lineage`) that shares the payload shape
//! and shares verdict encodings in DIFFERENT groupings per surface — see §3a of
//! the charter and the grouped `match` arms below, which are preserved verbatim
//! so a divergence between lineage members stays a one-line, reviewable edit.
use Agent;
pub use ;
pub use normalize_hermes;
pub use normalize_opencode;
/// Agent-native allow encodings (addendum §4 verdict matrix).
/// Agent-native deny encodings for a **Stop** event (F68).
///
/// Separate from `encode_deny` because Stop is a different hook event with a
/// different documented schema on every host — not a variation on `PreToolUse`.
/// Rendering a Stop verdict in `PreToolUse`'s dialect is why Stop findings were
/// silently discarded: the host does not recognise the shape, so the agent
/// stopped with violations on the floor.
///
/// The three dialects, as documented (checked 2026-08-18):
///
/// - **Claude** — top-level `{"decision":"block","reason":…}`. The docs state
/// Stop/SubagentStop do NOT use `hookSpecificOutput` or `permissionDecision`.
/// - **Codex** — top-level `{"decision":"block","reason":…}`. `hookSpecificOutput`
/// is not a supported structure at Stop, and an unsupported field invalidates
/// the payload outright (openai/codex#18887), so the legacy double-encoding
/// `encode_deny` uses for `PreToolUse` would be worse than redundant here.
/// - **Auggie** — `{"`hookSpecificOutput`":{"`hookEventName`":"Stop",…}}`, with
/// `decision`/`reason` rather than `permissionDecision`. **Not** Claude's
/// shape, despite the two sharing a `PreToolUse` deny dialect.
///
/// Hermes and opencode return `None`: neither normalizer produces `is_stop`, so
/// there is no Stop traffic to encode and inventing a dialect for one would be
/// N13 groundwork. `None` means "keep the existing deny encoding", which is the
/// honest no-op rather than a silent drop.
///
/// Every host documents JSON-on-stdout with **exit 0** as Stop's structured
/// control channel; exit 2 is `PreToolUse`'s and carries no reason.
/// Agent-native deny encodings (addendum §4 verdict matrix).