You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit b508103
Browse filesBrowse the repository at this point in the historyBrowse files
# ADR-38277: Render AWF Steering Events in the Unified Log Timeline
2
+
3
+
**Date**: 2026-06-10
4
+
**Status**: Draft
5
+
6
+
## Context
7
+
8
+
The `gh aw view` / `gh aw audit` unified timeline merges JSONL events from the MCP Gateway, the AWF firewall, and the agent session into a single wall-clock-ordered view. The AWF API proxy emits steering events (`token_steering`, `timeout_steering`) when a run approaches its token budget or time limit; these were already counted in `TotalSteeringEvents` metrics but were silently dropped from the timeline, so an operator reading the unified log could see neither when nor why a run was steered. The steering records live in `api-proxy-logs/events.jsonl`, whose schema varies by proxy version — the event name appears under one of four field names (`event`, `type`, `event_name`, `eventName`) — and whose log directory exists in both a canonical (`sandbox/firewall/logs/`) and a legacy (`firewall-audit-logs/`) layout.
9
+
10
+
## Decision
11
+
12
+
We will surface AWF steering events as first-class entries in the unified timeline by adding a new `TimelineKindSteering` event kind. Concretely:
13
+
14
+
1. Steering events are collected by a new `collectSteeringTimelineEvents`, parsed via a `proxyEventsEntry` struct whose `eventName()` helper checks all four field-name variants, and validated against the AWF spec message prefixes (`[AWF TOKEN WARNING]` / `[AWF TIME WARNING]`) before admission.
15
+
2. Steering events reuse the existing `TimelineSourceFirewall` source rather than introducing a new source, and encode their subtype in the existing `Status` field (`"token"` / `"time"`) rather than adding new struct fields.
16
+
3. The renderer dispatches the new kind to `renderSteeringRow` (table) and a warning-styled `⚠ <message>` line (stream), and the summary appends `steering=N` to the existing Firewall line only when the count is non-zero.
17
+
18
+
This favors extending the established per-kind timeline pattern and reusing the firewall source/status plumbing over introducing parallel structures, keeping steering integration consistent with how gateway and agent events are already handled.
19
+
20
+
## Alternatives Considered
21
+
22
+
### Alternative 1: Introduce a dedicated `TimelineSourceProxy` source and bespoke struct fields
23
+
Model the API proxy as its own timeline source with a new summary line and dedicated fields for steering subtype and message. Rejected because steering is conceptually a firewall/guard concern already grouped under the Firewall summary, and a new source would add a fourth summary block plus renderer branching for a single event kind, increasing surface area without a clear operator benefit.
24
+
25
+
### Alternative 2: Parse only the canonical event-name field and single directory layout
26
+
Read `event_name` from `sandbox/firewall/logs/api-proxy-logs/events.jsonl` only, treating the other field-name variants and the legacy layout as out of scope. Rejected because real proxy logs in the field use all four field-name spellings and both directory layouts; a strict reader would silently drop steering events from older runs and proxy versions, reintroducing the very gap this change closes.
27
+
28
+
## Consequences
29
+
30
+
### Positive
31
+
- Operators can now see when and why a run was steered directly in the unified timeline, closing the gap between `TotalSteeringEvents` metrics and the visible log.
32
+
- Defensive multi-variant field parsing and dual-layout collection make steering rendering robust across proxy versions and historical runs.
33
+
34
+
### Negative
35
+
- Reusing the `Status` field to carry the steering subtype overloads a field whose semantics now depend on `Kind`, so future readers must know that `Status` means something different for steering events than for other kinds.
36
+
- The collector adds another file scan (`events.jsonl`) to every `BuildUnifiedTimeline` call, with the spec-prefix validation and four-field probing duplicating event-name knowledge that must stay in sync with the AWF proxy spec.
37
+
38
+
### Neutral
39
+
- Steering events are grouped under the existing Firewall summary line rather than a new section; the `steering=N` suffix appears only when non-zero, leaving output unchanged for runs without steering.
40
+
- Steering entries with no parseable timestamp sort with a zero time, placing them at the start of the wall-clock ordering.
41
+
42
+
---
43
+
44
+
*This is a DRAFT ADR generated by the [Design Decision Gate](https://github.com/github/gh-aw/actions/runs/27252641413) workflow. The PR author must review, complete, and finalize this document before the PR can merge.*
0 commit comments