-
Notifications
You must be signed in to change notification settings - Fork 415
Add steering message rendering in unified log view #38277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
cd70f81
Start: add steering message rendering to unified log view
Copilot 16bb3ed
Add steering message rendering in unified log view
Copilot 480247b
Add draft ADR-38277 for steering message rendering
github-actions[bot] f13c3e3
Address review feedback: fix indentation, steeringCount scoping, dedu…
Copilot 83df84f
Merge remote-tracking branch 'origin/main' into copilot/add-rendering…
Copilot cec9e32
DRY: extract scanSteeringEntries to eliminate duplicated scan loop
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
44 changes: 44 additions & 0 deletions
44
docs/adr/38277-render-awf-steering-events-in-unified-timeline.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # ADR-38277: Render AWF Steering Events in the Unified Log Timeline | ||
|
|
||
| **Date**: 2026-06-10 | ||
| **Status**: Draft | ||
|
|
||
| ## Context | ||
|
|
||
| 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. | ||
|
|
||
| ## Decision | ||
|
|
||
| We will surface AWF steering events as first-class entries in the unified timeline by adding a new `TimelineKindSteering` event kind. Concretely: | ||
|
|
||
| 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. | ||
| 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. | ||
| 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. | ||
|
|
||
| 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. | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| ### Alternative 1: Introduce a dedicated `TimelineSourceProxy` source and bespoke struct fields | ||
| 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. | ||
|
|
||
| ### Alternative 2: Parse only the canonical event-name field and single directory layout | ||
| 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. | ||
|
|
||
| ## Consequences | ||
|
|
||
| ### Positive | ||
| - 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. | ||
| - Defensive multi-variant field parsing and dual-layout collection make steering rendering robust across proxy versions and historical runs. | ||
|
|
||
| ### Negative | ||
| - 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. | ||
| - 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. | ||
|
|
||
| ### Neutral | ||
| - 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. | ||
| - Steering entries with no parseable timestamp sort with a zero time, placing them at the start of the wall-clock ordering. | ||
|
|
||
| --- | ||
|
|
||
| *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.* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
steeringCountis source-independent but reported only insideif fwCount > 0: the counter is incremented in the flatswitch evt.Kindblock (no source guard), but emitted only whenfwCount > 0. Today this is harmless becausesteeringEntryToTimelineEventhardcodesSource: TimelineSourceFirewall. But if any steering event ever arrives from a different source,steeringCountwill be non-zero whilefwCountmay be zero, silently swallowing the steering tally from the summary.💡 Suggested fix
Count steering under the firewall source bucket explicitly so the coupling is visible and consistent:
Or, at minimum, add a standalone
if steeringCount > 0 && fwCount == 0branch in the summary formatter so the count is never silently dropped.